diff --git a/README.md b/README.md index be18496..0f81e86 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 } ] } 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..94fdec0 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,34 @@ try { } // extract a path to file to store tunnel pid -var pid = process.argv.find(function (param) { return param.indexOf('--pid') !== -1; }); +if(yargs.hasOwnProperty('pid')) { + if(yargs['pid'].trim().length > 0) { + config.tunnel_pid_file = yargs['pid'].trim(); + } else { + throw new Error('Empty pid file path'); + } +} -if (pid) { - var extracted_path = /--pid=([\w\/\.-]+)/g.exec(pid); - if (extracted_path) { - config.tunnel_pid_file = extracted_path[1]; +// 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('Error while parsing flag --pid. Usage: --pid=/path/to/file'); + 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.'); } } +// 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 0faa8af..91deb24 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 } ] diff --git a/tests/behaviour/runner.js b/tests/behaviour/runner.js index 03316bf..7c898b1 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 { @@ -226,3 +228,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(); + }); + }); +});