You made it. After weeks writing a dozen Selenium tests with Nightwatch.js, you are done. Your elements have been found, your buttons have been clicked, and your page objects have been modeled. The only thing left is to run your suite of tests across all the browsers you care about. That’s where parallel testing comes in handy. Twelve tests across five platforms mean 60 test cases, but you have a 25-parallel Automation plan, so this shouldn’t take long.
$ nightwatch --env ie,edge,chrome,ff,safari
You press enter and…
Started child process for: ie environment Started child process for: edge environment Started child process for: chrome environment Started child process for: ff environment Started child process for: safari environment
Huh, that’s funny. It looks like it’s only running five tests at a time, not 20.
Yup, CBT shows that there are only five tests running. What gives?
It turns out that if you use the --env
flag to specify the browsers to run on, then Nightwatch will run each environment in parallel, but each test case will execute sequentially.
That’s not what we want! What’s the point of having a big beefy Automation plan if you can’t use it?
So the question becomes, how do we run with MAXIMUM CONCURRENCY?
Well, I couldn’t figure out how to do it in Nightwatch, but I hacked together a workaround!
The following Node.js code will take the --env
(or -e
) flag and launch an instance of Nightwatch for each specified environment. If no environment is specified, then it will use all environments specified in your Nightwatch configuration file.
parallel-nw.js:
const cbt = require('cbt_tunnels'); const nwConfig = require('./nightwatch') const spawn = require('child_process').spawn; const tunnelOptions = { 'username': nwConfig.test_settings.default.username, 'authkey': nwConfig.test_settings.default.access_key } async function startTunnel(tunnelOptions){ return new Promise( (resolve, reject) => { cbt.start(tunnelOptions, function(err, data) { if (err) { reject(err) } else { resolve(data) } }); }) } function envNames(config){ if(config && config.test_settings){ return Object.keys(config.test_settings); } else { return []; } } async function spawnNW(envName){ return new Promise( (resolve, reject) => { let err; let proc = spawn('nightwatch', ['-e', envName], {shell:true}); proc.stdout.on('data', data => { if (data.toString('utf8').replace(/\s/g, '') !== ""){ console.log(`${envName}:\n ${data.toString('utf8')}`) } }) proc.stderr.on('data', data => { if (data.toString('utf8').replace(/\s/g, '') !== ""){ console.error(data.toString('utf8')) } }) proc.on('close', (code) => { if(code === 0){ console.log(`${envName}: Finished!`) resolve(code) } else { reject(new Error(`${envName}: failed ` + err)); } }) }) } ( async () => { // make sure tunnel is started before starting selenium tests await startTunnel(tunnelOptions); // look for environment names in command line args... let names; for (let i=0; i < process.argv.length; i++){ if (process.argv[i] === '--env' || process.argv[i] === '-e'){ names = process.argv[i+1].split(','); } } // or pull from the config file if (names === undefined){ names = envNames(nwConfig); } // spawn nightwatch for each environment let procs = names.map(spawnNW) console.log(`Starting to run Nightwatch on ${names.join(', ')}`) // wait for all nightwatch processes to return Promise.all(procs) .then( () => { console.log('Nightwatch finished!') // stop tunnel when all tests are done cbt.stop() }) .catch( (err) => {console.log(err)}) })()
Once that file is in place, we can use it to run our tests!
node parallel-nw.js --env ie,edge,chrome,ff,safari
Much better!
Nightwatch.js is an End-to-End testing platform for writing and running Selenium tests with Node.js.