Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can I write an AWS Lambda Script that Runs a Protractor / Selenium Browser Automation Script?

I am very much enjoying AWS Lambda functions, and I'm wondering if what I want to do here is possible. On my local machine, I have a Protractor config file :

// conf.js
exports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://127.0.0.1:4444/wd/hub',
  specs: ['automation-script.js'],
  capabilities: {
    browserName: 'chrome'
  }
}

and a script that loads up a browser window with a certain url:

describe('Protractor Demo App', function() {
  it('should have a title', function() {
    browser.driver.get('https://github.com/');

   // Click around and do things here.

  });
});

The purpose my scripts right now are not to black-box test an application that I'm developing, but instead to automate common browser tasks that I don't feel like doing.

Currently, I'm running the protractor script through my local command shell like this:

protractor protractor.conf.js 

I'm wondering if it is possibly to run protractor from within another node.js script. My thinking is that I could have the Lambda function kick off a protractor job, possibly by using the browsers available from Browserstack or Sauce Labs, but I can't figure out how to run protractor from a Node.js script.

like image 411
Jim Avatar asked Nov 13 '16 15:11

Jim


People also ask

Can you run Selenium in AWS Lambda?

IMPORTANT UPDATE. This post is outdated now that AWS Lambda allows users to create and distribute layers with all sorts of plugins and packages, including Selenium and chromedriver. This simplifies a lot of the process.

Can we integrate protractor with Selenium?

Protractor make use of Selenium Grid to initialize, control and run browser instance. Can easily integrate with jasmine, mocha and cucumber framework to write your test.

How do you automate Lambda testing?

Navigate to the Lambda console and choose the function. From the Test dropdown, choose Configure Test Event. Choose Create a new Test Event and select the template for the service you want to act as the trigger for your Lambda function. In this example, you choose Amazon DynamoDB Update.


1 Answers

This is a really interesting question. Our organization has been probing how much of our CI/CD pipeline can be done in a serverless fashion. This is right up that alley.

Unfortunately, I don't think there is an elegant way to run protractor from another Node script. That is, protractor doesn't seem to expose an API that makes it easy to consume in such a manner.

It's been asked for, but (as a relative newcomer to protractor) the comment right before the issue was closed doesn't contain enough detail for me to know how to take that approach. So, the not-so-elegant approach:

Child Process

Prior comments notwithstanding, you can indeed run protractor from within another Node script, including a Node script executing in AWS' Lambda environment. There may be prettier/better ways to do this, but I took this answer and based the following Lambda function on it:

'use strict';

module.exports.runtest = (event, context, callback) => {

  var npm = require('npm');
  var path = require('path');
  var childProcess = require('child_process');
  var args = ['conf.js'];

  npm.load({}, function() {
    var child = childProcess
    .fork(path.join(npm.root, 'protractor/bin/protractor'), args)
    .on('close', function(errorCode) {
      const response = {
        statusCode: 200,
        body: JSON.stringify({
          message: `Selenium Test executed on BrowserStack!  Child process Error Code: ${errorCode}`,
        }),
      };
      callback(null, response);
    });
    process.on('SIGINT', child.kill);
  });
};

var args = ['conf.js']; points to the protractor config file, which in turn points to the test (index.js in this case):

exports.config = {
    'specs': ['./index.js'],
    'seleniumAddress': 'http://hub-cloud.browserstack.com/wd/hub',
    'capabilities': {
      'browserstack.user': '<BROWSERSTACK_USER>',
      'browserstack.key': '<BROWSERSTACK_KEY>',
      'browserName': 'chrome'
    }
  };

Repository here.

Notes

  • npm is a runtime dependency using this approach, meaning it has to be packaged into your deployable. This makes for a relatively large lambda function. At ~20mb, it's big enough that you don't get to edit code inline in the AWS console anymore. An approach that didn't package npm as a runtime dependency would be much nicer.
  • Don't forget Lambda has a hard 5 minute time limit. Your tests will need to complete in less time than that.
  • Watch the clock. In many instances, my toy example only uses a browser for a couple of seconds, but the overhead (of connecting to BrowserStack, mostly, I presume) makes the Lambda take 12-30 seconds altogether. Paying for 30 seconds of compute to use a browser for 2.5 seconds doesn't sound like a win. Larger batches of tests might be less wasteful.
  • You do get CloudWatch logging of the child process without doing any extra plumbing yourself, which is nice.
  • Disclaimer: My example has only been happy-path tested, and I'm no expert on child processes in Node.
like image 108
Mike Patrick Avatar answered Sep 24 '22 02:09

Mike Patrick