2

I'm sharding (running in parallel) my Protractor tests and am storing each test's result in a database. I need a way to tie all the tests from a single test run together. The plan was to set an id in the config and include it in DB. Problem is, the config gets re-run for each sharded test (ie. multiple times)... so I end up with multiple IDs. No bueno.

So, anyone have an idea on how I might set a single, unique id, once at the beginning of a sharded test run?

Update: To clarify, I was hoping there might be a simple solution within Protractor itself. Otherwise I'll just create an id (eg. via grunt/gulp/npm) and pass it via the cli via --params.specRunId=xxxxx.

Brine
  • 3,733
  • 1
  • 21
  • 38

3 Answers3

1

I guess this would work you. Protractor configuration file has an option - beforeLaunch

As per the belo extract from official documentation, it gets invoked before the complete test run and its a good place to generate a unique ID for the complete test run.

All parallel tests with share this uniqueID

A callback function called once configs are read but before any environment setup. This will only run once, and before onPrepare.

I have a basic example setup

    var test_run_id;
    beforeLaunch:function(){
       test_run_id = Math.random(); // Have a better ID generation logic here
    },

In on-prepare() And set the value onto a global variable browser.specRunId for subsequent use

onPrepare: function() {
 browser.specRunId= test_run_id
 },

UPDATE: structure of protractor config file now

var test_run_id;
exports.config = {
    specs: ['demo.js'],
    framework: 'jasmine2',
    baseUrl: 'http://www.protractortest.org/',
    multiCapabilities: [{
        'browserName': 'chrome',
        name: 'browser1'
    }],
    beforeLaunch: function() {
        test_run_id = Math.random();
    },
    onPrepare: function() {
        browser.runid = test_run_id
    },
};
AdityaReddy
  • 3,625
  • 12
  • 25
  • Now I need to figure out how to access a var created in `beforeLaunch`... since it's called _after_ the config is read, but _before_ browser is available. Ain't nothing easy. – Brine Oct 02 '16 at 12:16
  • you can do it..the variable declaration can be outside and its read along with config and then value is assigned in `beforeLaunch()` and value is ported to browser object in `onprepare()`. I have updated the answer with how conf.js will look like :) – AdityaReddy Oct 02 '16 at 14:57
  • Yeah, tried that. Sadly, neither var (`browser` or config var) is available to `afterLaunch`, which is ultimately where I have to culminate the tests and send off for reporting. Any other hook that has `browser` available, is loaded for each shard, so that's out too. I am stuck. – Brine Oct 02 '16 at 15:44
  • noproblem .. did you try `onComplete` - This is invoked once tests are finished and browser object is available here - https://github.com/angular/protractor/blob/master/lib/config.ts#L401 – AdityaReddy Oct 02 '16 at 16:29
  • Yeah, `onComplete` has `browser` but also gets reloaded each shard. I _think_ I have it working by stashing an id in `proces.env.specRunId`, which I set in `beforeLaunch`. Not sure what happens when I have multiple runs on the server though :) – Brine Oct 03 '16 at 22:22
  • This isn't working for me :( It looks like sharding will run several separate processes, so the beforeLaunch code (and anything else in the e2e.conf.js file) gets executed several times separately, and there's no cross-process persistence that I can see. I did find [this feature request](https://github.com/angular/protractor/issues/2392), but it doesn't seem to have been implemented yet – Constantinos Jun 30 '17 at 10:29
1

Instead of generating a random number, you could tie it to the browser session id.

In your config, instead of assigning a random id, use browser.driver.getSession(). This should return a WebDriver promise of Promise<Session>. You can resolve the promise and get the session id.

Maybe something like:

beforeLaunch: {

  // may need to call browser.get('some URL') for the driver
  // to get a session id

  return new Promise((resolve, reject) => {
    browser.getSession().then((session) => {
      browser.session_id = session.getId();
    });
  });
}
cnishina
  • 5,016
  • 1
  • 23
  • 40
  • A good suggestion, and I did try it, but the session id is tied to browser, and runs one per shard, and thus, changes each time. – Brine Oct 04 '16 at 02:49
  • That was not clarified in the question. I was under the assumption that you wanted a unique id. – cnishina Oct 04 '16 at 07:24
0

The best way is to create a unique id every test you run, so your code should create a unique id and run the sharded test with it and then generate a new one for the next test. You can generate a unique id like that:

function generateUIDNotMoreThan1million() {
return ("0000" + (Math.random()*Math.pow(36,4) << 0).toString(36)).slice(-4)

}

The code is taken from: how to generate short uid like "aX4j9Z" (in JS)`

Community
  • 1
  • 1
Adi
  • 2,074
  • 22
  • 26
  • 1
    Thanks, but I'm looking for _where_ I can set an id, not how. Eg. setting it in the config doesn't work because the config is run every shard. – Brine Oct 01 '16 at 17:31
  • You need to generate a new one every test not set a fixed on. – Adi Oct 01 '16 at 17:38
  • No, just one for the entire test run. I updated my question to help clarify. – Brine Oct 01 '16 at 17:41