orchestration | clean up old selenium sessions | Cell 9 | Search

This code automates screenshot capture from Selenium WebDriver sessions and uploads them to an AWS S3 bucket for storage.

Run example

npm run import -- "screenshot all sessions"

screenshot all sessions

var AWS = require('aws-sdk');
var fs = require('fs');
var path = require('path');
var importer = require('../Core');
var runSeleniumCell = importer.import("selenium cell");
var unidecode = require('unidecode');

// For dev purposes only
var PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
var SCREENSHOTS_DIR = path.join(PROFILE_PATH, 'Collections/screenshots');
AWS.config.update(JSON.parse(fs.readFileSync(path.join(PROFILE_PATH, '.credentials/aws-sdk.json')).toString()));

function uploadS3(file) {
    var base64data = fs.readFileSync(file);
    var s3 = new AWS.S3();
    return new Promise((resolve, reject) => s3.putObject({
        Bucket: 'selenium-bots',
        Key: path.basename(file),
        Body: base64data,
        ACL: 'public-read'
    },function (err, resp) {
        if(err) {
            return reject(err);
        }
        return resolve(resp);
    }));
}

function getScreenshots(client) {
    if(typeof client === 'undefined') {
        var client = runSeleniumCell(null, false);
    }
    var session, paths;
    return client
        .catch(e => {
            if((e + '').indexOf('Already') > -1) {
                // ignore because we don't need a valid session to start
                return;
            }
            throw e;
        })
        .then(() => {
            session = client.sessionId;
        })
        .then(() => importer.runAllPromises([client.getSessions(false), client.getSessions(true)]))
        .then(sess => [].concat(...sess))
        .then(r => {
            console.log(r);
            return importer.runAllPromises(r.map(s => resolve => {
                return client
                    .then(() => client.sessionId = s)
                    .then(() => client.getWindowHandles())
                    .then(h => importer.runAllPromises(h.map(hwnd => resolve => {
                         const time = new Date();
                        // TODO: include address in image?
                         let filepath = path.join(SCREENSHOTS_DIR, 'screenshot-'
                                                      + time.getFullYear() + '-'
                                                      + (time.getMonth() + 1) + '-'
                                                      + time.getDate() + '-'
                                                      + time.getHours() + '-'
                                                      + time.getMinutes() + '-'
                                                      + time.getSeconds());
                         return client
                            .switchToWindow(hwnd)
                            .then(() => client.getUrl())
                            .then(url => filepath += '-' + unidecode(url).replace(/[^a-z0-9_-]/igm, '_'))
                            .then(() => client.saveScreenshot(filepath + '.png'))
                            // TODO: create thumbnails
                            .then(() => uploadS3(filepath + '.png'))
                            .catch(e => console.log(e))
                            .then(() => resolve(filepath + '.png'))
                    })))
                    .catch(e => console.log(e))
                    .then(r => resolve(r))
            }));
        })
        .then(r => {
            client.sessionId = session;
            paths = r;
        })
        .catch(e => console.log(e))
        .then(() => paths)
}
module.exports = getScreenshots;

if(typeof $ !== 'undefined') {
    $.async();
    getScreenshots()
        .then(r => $.sendResult(r))
        .catch(e => $.sendError(e))
}

What the code could have been:

const AWS = require('aws-sdk');
const fs = require('fs');
const path = require('path');
const { runSeleniumCell, runAllPromises } = require('../Core');
const unidecode = require('unidecode');

// Constants
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
const SCREENSHOTS_DIR = path.join(PROFILE_PATH, 'Collections/screenshots');

// AWS Config
const awsConfig = JSON.parse(fs.readFileSync(path.join(PROFILE_PATH, '.credentials/aws-sdk.json')).toString());
AWS.config.update(awsConfig);
const s3 = new AWS.S3();

/**
 * Uploads a file to S3
 * @param {string} file - path to the file to upload
 * @returns {Promise} - resolved with the upload response
 */
function uploadS3(file) {
    const base64data = fs.readFileSync(file);
    return s3.putObject({
        Bucket:'selenium-bots',
        Key: path.basename(file),
        Body: base64data,
        ACL: 'public-read'
    }).promise();
}

/**
 * Gets screenshots of a selenium cell
 * @param {object} client - selenium client (optional, defaults to new instance)
 * @returns {Promise} - resolved with an array of screenshot paths
 */
function getScreenshots(client = runSeleniumCell()) {
    // Handle missing client
    if (!client) {
        client = runSeleniumCell();
    }

    // Get session ID and sessions
    let session, sessions;
    return client
       .catch(e => {
            if ((e + '').indexOf('Already') > -1) {
                // Ignore because we don't need a valid session to start
                return;
            }
            throw e;
        })
       .then(() => client.sessionId)
       .then(sessionId => {
            session = sessionId;
            return runAllPromises([client.getSessions(false), client.getSessions(true)]);
        })
       .then(sess => [].concat(...sess))
       .then(sessions => {
            // Map each session to its corresponding screenshot paths
            return runAllPromises(sessions.map(s => resolve => {
                const time = new Date();
                const filePath = path.join(SCREENSHOTS_DIR, `screenshot-${time.getFullYear()}-${time.getMonth() + 1}-${time.getDate()}-${time.getHours()}-${time.getMinutes()}-${time.getSeconds()}`);

                return client
                   .switchToWindow(s)
                   .then(() => client.getUrl())
                   .then(url => {
                        const fileName = `${filePath}-${unidecode(url).replace(/[^a-z0-9_-]/igm, '_')}.png`;
                        return client.saveScreenshot(fileName);
                    })
                   .then(() => uploadS3(fileName))
                   .then(() => resolve(fileName))
                   .catch(e => console.log(e))
                   .then(() => resolve(fileName));
            }));
        })
       .then(paths => {
            client.sessionId = session;
            return paths;
        })
       .catch(e => console.log(e));
}

module.exports = getScreenshots;

if (typeof $!== 'undefined') {
    $.async();
    getScreenshots()
       .then(r => $.sendResult(r))
       .catch(e => $.sendError(e));
}

This code snippet focuses on capturing and uploading screenshots from Selenium WebDriver sessions to an Amazon S3 bucket.

Here's a breakdown:

  1. Imports:

  2. Configuration:

  3. uploadS3 Function:

  4. getScreenshots Function:

  5. Execution:

In essence, this code automates the process of taking screenshots from Selenium WebDriver sessions and uploading them to an AWS S3 bucket for storage and sharing.