13

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.

Jim
  • 2,968
  • 1
  • 22
  • 50
  • 1
    I'm not sure, but generally lambdas are for changing/checking files going in and out of S3 storage, responding to certain http calls etc? This seems like something that would be better suited to run on an EC2 instance in Node etc. – adeneo Nov 13 '16 at 15:59
  • 2
    I would think anything that can be done with Ec2 could also be done as a serverless architecture with Lambda. – Jim Nov 13 '16 at 16:34

1 Answers1

8

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.
Mike Patrick
  • 9,144
  • 1
  • 23
  • 46
  • have you experimented with passing the "index.js" file into the lambda function? That way you can execute the lambda function "x" times for each script you have? I'm thinking of writing something using what you've built and passing the test script in and executing it on lambda in this fashion. That way I can just run this lambda 100 times async and run all of the protractor tests at once. – Exziled Jul 12 '18 at 15:55