selenium server | | Cell 1 | Search

This code sets up a REST API using Express.js to enable a web application to control a Selenium WebDriver instance running on a separate server, automating browser interactions. It uses Socket.IO for communication and a custom importer module to execute a Jupyter notebook containing Selenium server logic.

Run example

npm run import -- "Start a selenium http express server"

Start a selenium http express server

var importer = require('../Core')
var bodyParser = require('body-parser');
var express = require('express');
var io = require('socket.io-client');
var client = io('https://localhost:8000', {
    secure: true,
    rejectUnauthorized: false
});
var currentCallback = null;
client.on('result', function (name, ...args) {
    // TODO: not just verify the service,
    //   also verify the tab id matches
    if (name === 'BrowserService.prototype.chrome') {
        if(currentCallback) {
            currentCallback.apply(this, args);
        }
    }
})

function promisifyChrome(...args) {
    return new Promise((resolve, reject) => {
        console.log('call ' + JSON.stringify(args).substr(0, 200));
        if(typeof currentCallback === 'function') {
            throw new Error('Callback already defined.');
        }
        var cmdTimeout = setTimeout(() => {
            currentCallback = null;
            reject(new Error('command took too long to respond', 3000));
        }, 9000)
        currentCallback = (err, data) => {
            currentCallback = null;
            clearTimeout(cmdTimeout);
            if (err !== null) {
                return reject(err);
            }
            return resolve.apply(this, JSON.parse(data));
        };
        client.emit.apply(client, [
            'call',
            'BrowserService.prototype.chrome',
            ...args
        ]);
    });
};
function response(res, promise) {
    return promise.then(r => {
        res.setHeader('Content-Type', 'application/json');
        res.send(JSON.stringify(r));
    })
}

var tabId;
function seleniumServer() {
    const selenium = express();
    const server = require('http').createServer(selenium);
    selenium.use(bodyParser.json());    // to support JSON-encoded bodies
    selenium.use(bodyParser.urlencoded({// to support URL-encoded bodies
        extended: true
    }));
    // TODO: import the rest of the modules in this script
    return importer.getCells(__dirname + '/../Selenium/selenium server.ipynb')
        .then(cells => {
            for (const c of cells.slice(1)) /* exclude this cell */ {
                const mod = importer.runInNewContext(c.source.join(''), {
                    __filename: __dirname + '/../Selenium/selenium server.ipynb',
                    promisifyChrome,
                    getTab: () => tabId,
                    setTab: (id) => (tabId = id),
                    response
                }, {}, false);
                if (typeof mod !== 'undefined' && typeof mod.router !== 'undefined') {
                    selenium.use('/wd/hub', mod.router);
                }
            }
            return server.listen(4444);
        });
};
module.exports = seleniumServer;

What the code could have been:

const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const io = require('socket.io-client');
const importer = require('../Core');

const app = express();
const server = http.createServer(app);
const ioClient = io('https://localhost:8000', {
  secure: true,
  rejectUnauthorized: false,
});

// Handle results from the server
ioClient.on('result', (name,...args) => {
  if (name === 'BrowserService.prototype.chrome') {
    if (currentCallback) {
      currentCallback.apply(this, args);
    }
  }
});

// Create a promise for Chrome calls
function promisifyChrome(...args) {
  return new Promise((resolve, reject) => {
    console.log('call'+ JSON.stringify(args).substr(0, 200));
    if (currentCallback) {
      throw new Error('Callback already defined.');
    }

    const cmdTimeout = setTimeout(() => {
      currentCallback = null;
      reject(new Error('Command took too long to respond.', 3000));
    }, 9000);

    currentCallback = (err, data) => {
      currentCallback = null;
      clearTimeout(cmdTimeout);
      if (err!== null) {
        return reject(err);
      }
      return resolve(JSON.parse(data));
    };

    ioClient.emit.apply(ioClient, [
      'call',
      'BrowserService.prototype.chrome',
     ...args,
    ]);
  });
}

// Handle responses
function response(res, promise) {
  return promise.then((r) => {
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify(r));
  });
}

let tabId = '';

// Create a selenium server
async function seleniumServer() {
  try {
    // Import the selenium server cells
    const cells = await importer.getCells(__dirname + '/../Selenium/selenium server.ipynb');
    const router = cells.slice(1).reduce((acc, cell) => {
      const mod = importer.runInNewContext(cell.source.join(''), {
        __filename: __dirname + '/../Selenium/selenium server.ipynb',
        promisifyChrome,
        getTab: () => tabId,
        setTab: (id) => (tabId = id),
        response,
      }, {}, false);

      if (typeof mod!== 'undefined' && typeof mod.router!== 'undefined') {
        acc.use('/wd/hub', mod.router);
      }

      return acc;
    }, app);

    // Start the server
    server.listen(4444);

    return router;
  } catch (error) {
    console.error(error);
  }
}

module.exports = seleniumServer;

This code sets up a basic REST API server using Express.js to interact with a Selenium WebDriver instance running on a separate server.

Here's a breakdown:

  1. Dependencies:

  2. Socket.IO Connection:

  3. promisifyChrome Function:

  4. response Function:

  5. seleniumServer Function:

Purpose:

This code likely forms part of a larger system where a web application interacts with a Selenium server to automate browser interactions. The API server acts as a bridge between the web application and the Selenium server, allowing the application to send commands to the server and receive results.