From 4a8c64a6db5dd73662ba986a396181818ca2b242 Mon Sep 17 00:00:00 2001 From: Pankaj Ahuja Date: Fri, 10 Aug 2018 19:20:46 +0530 Subject: [PATCH 1/4] Added command line interface using yargs. --- bin/init.js | 5 ++-- bin/runner.js | 71 +++++++++++++++++++++++++++++++++++--------- package.json | 3 +- presets/default.json | 24 ++++++++++----- 4 files changed, 78 insertions(+), 25 deletions(-) diff --git a/bin/init.js b/bin/init.js index 57640f4..2c0febb 100755 --- a/bin/init.js +++ b/bin/init.js @@ -1,13 +1,14 @@ #! /usr/bin/env node var fs = require('fs'); -var preset = process.argv[3] || 'default'; +var preset = require('./runner').preset; +var path = require('./runner').path; var browsers = require('../presets/' + preset + '.json'); var config = { username: 'BROWSERSTACK_USERNAME', key: 'BROWSERSTACK_KEY', - test_path: 'path/to/test/runner', + test_path: path || 'path/to/test/runner', browsers: browsers }; diff --git a/bin/runner.js b/bin/runner.js index d1abf0a..ba1c6f6 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -1,21 +1,53 @@ #! /usr/bin/env node -var todo = process.argv[2], - path = require('path'), - config; +var yargs = require('yargs') + .command('init [preset] [path]', 'initialise browserstack.json with preset and test runner path', function(yargs) { + return yargs.option('preset', { + type: 'string', + default: 'default', + description: 'name of preset json file(without extension)(present in node_modules/browserstack-runner/presets to be used while initiating' + }) + .option('path', { + type: 'string', + default: '/path/to/test/runner', + description: 'path to test runner to be inserted in browserstack.json' + }) + }) + .option('browsers', { + alias: 'b', + type: 'array', + description: 'list of space separatedbrowsers keys as described in json file' + }) + .option('path', { + type: 'string', + description: 'path to test file' + }) + .option('version', { + alias: 'V', + description: 'browserstack-runner version' + }) + .option('pid', { + type: 'string', + description: 'path to pid file' + }) + .option('verbose', { + alias: 'v', + description: 'verbose logging' + }).argv; -if (process.argv.indexOf('--verbose') !== -1) { +if (yargs['verbose']) { global.logLevel = process.env.LOG_LEVEL || 'debug'; } else { global.logLevel = 'info'; } +var path = require('path'), + config; -if (todo === 'init') { +if(yargs['_'].indexOf('init') !== -1) { + module.exports.preset = yargs['preset']; + module.exports.path = yargs['path']; require('./init.js'); return; -} else if (todo === '--version') { - require('./version.js'); - return; } var config_path = process.env.BROWSERSTACK_JSON || 'browserstack.json'; @@ -37,17 +69,28 @@ try { } // extract a path to file to store tunnel pid -var pid = process.argv.find(function (param) { return param.indexOf('--pid') !== -1; }); - -if (pid) { - var extracted_path = /--pid=([\w\/\.-]+)/g.exec(pid); - if (extracted_path) { - config.tunnel_pid_file = extracted_path[1]; +if(yargs['pid']) { + if(yargs['pid'].length > 0) { + config.tunnel_pid_file = yargs['pid']; } else { console.error('Error while parsing flag --pid. Usage: --pid=/path/to/file'); } } +// filter browsers according to from command line arguments +if(yargs['browsers']) { + if(yargs['browsers'].length > 0) { + config.browsers = config.browsers.filter( function(browser) { + return yargs['browsers'].indexOf(browser['cli_key']) !== -1; + }); + } else { + console.error('No browser keys specified. Usage --browsers ...'); + } +} + +// test file path from cli arguments +config.test_path = yargs['path'] || config.test_path; + var runner = require('./cli.js'); runner.run(config, function(err) { if(err) { diff --git a/package.json b/package.json index 94dfdcf..3c13a2b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "mime": "1.3.4", "resolve": "1.1.7", "send": "0.13.0", - "tunnel": "0.0.3" + "tunnel": "0.0.3", + "yargs": "^12.0.1" }, "devDependencies": { "jshint": "2.5.6", diff --git a/presets/default.json b/presets/default.json index 5498339..dcfcf53 100644 --- a/presets/default.json +++ b/presets/default.json @@ -3,48 +3,56 @@ "browser": "firefox", "browser_version": "latest", "os": "OS X", - "os_version": "Lion" + "os_version": "Lion", + "cli_key": 1 }, { "browser": "safari", "browser_version": "latest", "os": "OS X", - "os_version": "Mountain Lion" + "os_version": "Mountain Lion", + "cli_key": 2 }, { "browser": "chrome", "browser_version": "latest", "os": "OS X", - "os_version": "Mountain Lion" + "os_version": "Mountain Lion", + "cli_key": 3 }, { "browser": "firefox", "browser_version": "latest", "os": "Windows", - "os_version": "7" + "os_version": "7", + "cli_key": 4 }, { "browser": "chrome", "browser_version": "latest", "os": "Windows", - "os_version": "7" + "os_version": "7", + "cli_key": 5 }, { "browser": "ie", "browser_version": "9.0", "os": "Windows", - "os_version": "7" + "os_version": "7", + "cli_key": 6 }, { "browser": "ie", "browser_version": "10.0", "os": "Windows", - "os_version": "8" + "os_version": "8", + "cli_key": 7 }, { "browser": "ie", "browser_version": "11.0", "os": "Windows", - "os_version": "7" + "os_version": "7", + "cli_key": 8 } ] From e026e81bfbc070bed94686b18ba396cb86101798 Mon Sep 17 00:00:00 2001 From: Pankaj Ahuja Date: Mon, 13 Aug 2018 12:50:43 +0530 Subject: [PATCH 2/4] Fixed jshint error in runner.js --- bin/runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/runner.js b/bin/runner.js index ba1c6f6..55f95c8 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -11,7 +11,7 @@ var yargs = require('yargs') type: 'string', default: '/path/to/test/runner', description: 'path to test runner to be inserted in browserstack.json' - }) + }); }) .option('browsers', { alias: 'b', From 843c2cf6ec12d49b7e39a8488249c09a1686b972 Mon Sep 17 00:00:00 2001 From: Pankaj Ahuja Date: Wed, 22 Aug 2018 13:31:44 +0530 Subject: [PATCH 3/4] Updated Readme for CLI changes. --- README.md | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2a2f811..61dbc57 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,19 @@ If you're getting an error `EACCES open ... BrowserStackLocal`, configure npm to Where `[user]` is replaced with a local user with enough permissions. +CLI options: + +`--path`: Can be used if a different test runner is needed other than the one present in the `browserstack.json` file. + +`--pid`: Custom `pid` file that stores the pid's of the BrowserStackLocal instances created. + +`--verbose` or `-v`: For verbose logging. + +`--browsers` or `-b`: Space separated list of `cli_key` as defined in the `browserstack.json` file. This will run tests on the selected browsers only. If not present tests will run on all browsers present in the configuration file. + +Sample Usage: +`browserstack_runner --browsers 1 2 3 --path 'path/to/test/runner' --pid 'path/to/pid/file' -v` + ## Usage as a module `browserstack-runner` can also be used as a module. To run your tests, inside your project do - @@ -160,7 +173,11 @@ The structure of the `report` object is as follows - To run browser tests on BrowserStack infrastructure, you need to create a `browserstack.json` file in project's root directory (the directory from which tests are run), by running this command: - browserstack-runner init +`browserstack-runner init [preset] [path]` + +`preset`: Path of a custom preset file. Default: `presets/default.json` + +`path`: Path to test file. Default: `path/to/test/runner` ### Parameters for `browserstack.json` @@ -191,17 +208,20 @@ A sample configuration file: "browser_version": "10.0", "device": null, "os": "Windows", - "os_version": "8" + "os_version": "8", + "cli_key": 1 }, { "os": "android", "os_version": "4.0", - "device": "Samsung Galaxy Nexus" + "device": "Samsung Galaxy Nexus", + "cli_key": 2 }, { "os": "ios", "os_version": "7.0", - "device": "iPhone 5S" + "device": "iPhone 5S", + "cli_key": 3 } ] } @@ -209,7 +229,7 @@ A sample configuration file: #### `browsers` parameter -`browsers` parameter is a list of objects, where each object contains the details of the browsers on which you want to run your tests. This object differs for browsers on desktop platforms and browsers on mobile platforms. Browsers on desktop platform should contain `browser`, `browser_version`, `os `, `os_version` parameters set as required. +`browsers` parameter is a list of objects, where each object contains the details of the browsers on which you want to run your tests. This object differs for browsers on desktop platforms and browsers on mobile platforms. Browsers on desktop platform should contain `browser`, `browser_version`, `os`, `os_version` parameters set as required and the `cli_key` parameter is optional and can be used in the command line when tests need to be run on a set of browsers from the `browserstack.json` file. Example: ```json @@ -217,7 +237,8 @@ Example: "browser": "ie", "browser_version": "10.0", "os": "Windows", - "os_version": "8" + "os_version": "8", + "cli_key": 1 } ``` @@ -228,12 +249,14 @@ Example: [{ "os": "ios", "os_version": "8.3", - "device": "iPhone 6 Plus" + "device": "iPhone 6 Plus", + "cli_key": 1 }, { "os": "android", "os_version": "4.0", - "device": "Google Nexus" + "device": "Google Nexus", + "cli_key": 2 } ] ``` @@ -266,7 +289,8 @@ Example: "browser_version": "10.0", "device": null, "os": "Windows", - "os_version": "8" + "os_version": "8", + "cli_key": 1 } ] } From 6c1b658760de670f8de4521eff41d928f85d163d Mon Sep 17 00:00:00 2001 From: Pankaj Ahuja Date: Tue, 28 Aug 2018 16:04:25 +0530 Subject: [PATCH 4/4] Tests added for CLI --- bin/runner.js | 16 +++++++++++----- tests/behaviour/runner.js | 40 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/bin/runner.js b/bin/runner.js index 55f95c8..94fdec0 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -69,11 +69,11 @@ try { } // extract a path to file to store tunnel pid -if(yargs['pid']) { - if(yargs['pid'].length > 0) { - config.tunnel_pid_file = yargs['pid']; +if(yargs.hasOwnProperty('pid')) { + if(yargs['pid'].trim().length > 0) { + config.tunnel_pid_file = yargs['pid'].trim(); } else { - console.error('Error while parsing flag --pid. Usage: --pid=/path/to/file'); + throw new Error('Empty pid file path'); } } @@ -84,7 +84,13 @@ if(yargs['browsers']) { return yargs['browsers'].indexOf(browser['cli_key']) !== -1; }); } else { - console.error('No browser keys specified. Usage --browsers ...'); + throw new Error('No browser keys specified. Usage --browsers ...'); + } + if(config.browsers.length === 0) { + throw new Error('Invalid browser keys'); + } + if(config.browsers.length < yargs['browsers'].length) { + console.warn('Some browser keys not present in config file.'); } } diff --git a/tests/behaviour/runner.js b/tests/behaviour/runner.js index cebd9c2..9ae32b4 100644 --- a/tests/behaviour/runner.js +++ b/tests/behaviour/runner.js @@ -7,7 +7,9 @@ var assert = require('assert'), path = require('path'), http = require('http'), browserstackRunner = require('../../bin/cli.js'), - Tunnel = require('../../lib/local.js').Tunnel; + Tunnel = require('../../lib/local.js').Tunnel, + exec = require('child_process').exec, + execSync = require('child_process').execSync; var getBaseConfig = function() { return { @@ -219,3 +221,39 @@ describe('Pass/Fail reporting', function() { }); }); }); + +describe('Command Line Interface Tests', function() { + this.timeout(0); + it('Should run with valid CLI arguments', function(done) { + execSync('bin/runner.js init'); + exec('bin/runner.js --browsers 1 --path tests/behaviour/resources/qunit_sample.html', null, function(error, stdout, stderr) { + assert.equal(error, null); + done(); + }); + }); + it('Should raise errors if all invalid browser keys.', function(done) { + exec('bin/runner.js --browsers 10 --path tests/behaviour/resources/qunit_sample.html', null, function(error, stdout, stderr) { + assert.notEqual(error.message.match('Invalid'), null); + done(); + }); + }); + it('Should raise error if invalid test path', function(done) { + exec('bin/runner.js --browsers 1 --path invalid/path', function(error, stdout, stderr) { + assert.notEqual(error, null); + assert.notEqual(error.message.match('Invalid'), null); + done(); + }); + }); + it('Should run tests on browsers present if some keys not present', function(done) { + exec('bin/runner.js --browsers 1 10 --path tests/behaviour/resources/qunit_sample.html', null, function(error, stdout, stderr) { + assert.equal(error, null); + done(); + }); + }); + it('Should raise error if empty pid path with pid parameter', function(done) { + exec('bin/runner.js --browsers 1 --path tests/behaviour/resources/qunit_sample.html --pid', null, function(error, stdout, stderr) { + assert.notEqual(error, null); + done(); + }); + }); +});