# Puppeteer

# Quick Starting

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false
    });

    const page = await browser.newPage();
    page.setViewport({width: 1400, height: 700, isLandscape: true});

    await page.goto('https://sotaychemgio.com', {waitUntil: 'networkidle2'});
    await browser.close();
})();

# Execute in the page context

var result = await page.evaluate( function() {
    $('#my-button').click();
    return $('#result').html();
});

# Inject Script

async function injectScriptTask(page, scriptUrl){
    await page.addScriptTag({ url: scriptUrl });
}

// usage
await injectScriptTask('https://code.jquery.com/jquery-3.2.1.min.js');

# Workflow Pattern

# Workflow

const {Logger, UI_Utils, _} = runtime;

function Workflow(config){
    let instance = {};
    let { name, url } = config;

    let page = null; //runtime.getPage();
    let tasks = [];
    
    instance.addTask = (taskItem) => { tasks.push(taskItem) };

    instance.setPage = (_page) => { 
        page = _page;
    }

    instance.getPage = () => page;

    
    instance.accessPage = async () => {
        await UI_Utils.accessPage(page, url, name, 1000);
        Logger.info('Done loading page');
    }


    /*  Hook for run function */
    instance.afterRun = async function(data) { }
    instance.beforeRun = async function(data) { }


   
    instance.runTasks = async function(data) {
        if(!_.isArray(tasks)){
            return;
        }

        for(let task of tasks) {
            await task.run(page, { config, data, app: instance}); // 
        }
    }

    instance.run = async function(){
        var data = {};
        await instance.beforeRun(data);

        await instance.accessPage();
        await instance.runTasks(data);

        await instance.afterRun(data);
    }

    return instance;
}

module.exports = Workflow;

# Workflow Task

const _ = require("underscore");

var WorkflowTask = function(_subTasks){
    var subTasks = _.isArray(_subTasks) ? _subTasks : []; 
    var instance = {};

    /// NEED TO OVERRIDE BY SUBCLASS
    // will be called by `instance.run`
    instance.execute = async function(page, option){
        console.log('Please implement <3');
    }

    /// DONT EXPECT TO OVERRIDE
    instance.addTask = (task) => {subTasks.push(task) } ;

  
   
    /*
    * This function will call recursive 
    *     if sub task has sub sub tasks 
    */
    /// DONT EXPECT TO OVERRIDE
    instance.run = async function(page, option) {
        await instance.execute(page, option);
        await instance.runTasks(page, option);
    }


    /// DONT EXPECT TO OVERRIDE
    instance.runTasks =  async function(page, option){
        if(!_.isArray(subTasks)){
            return;
        }

        for(let subTask of subTasks) {
            await subTask.run(page, option); // 
        }
    }

    return instance;
};

module.exports = Task;

# Usage

Workflow level Focus on config & tasks

let grabImageTask = require('./grabImageTask');
let downloadImageTask = require('./downloadImageTask');

const config = {
    name: 'Images', 
}

let wf = Workflow(config);

wf.addTask(grabImageTask);
wf.addTask(downloadImageTask);

module.exports = wf;

Task Level

downloadImageTask.js

const download = require('image-downloader')

const instance = WorkflowTask();

instance.execute = async function (page, option) {
    console.log('run task download', option.data.imageLinks)

    for(let i =0, len = option.data.imageLinks.length; i < len; ++i) {
        const url = option.data.imageLinks[i];

        console.log('Downloading image: ', url);
        const options = {
            url: url,
            dest: appRoot + 'downloads/',   
        }
        await download.image(options) 
    }
}

module.exports = instance;