Skip to content

Commit

Permalink
Merge pull request #204 from browserstack/command-line-interface
Browse files Browse the repository at this point in the history
Added command line interface using yargs.
  • Loading branch information
mohitmun authored Aug 29, 2018
2 parents caea6e3 + 6c1b658 commit 2ff95f2
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 35 deletions.
42 changes: 33 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 -
Expand Down Expand Up @@ -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`

Expand Down Expand Up @@ -191,33 +208,37 @@ 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
}
]
}
```

#### `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
{
"browser": "ie",
"browser_version": "10.0",
"os": "Windows",
"os_version": "8"
"os_version": "8",
"cli_key": 1
}
```

Expand All @@ -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
}
]
```
Expand Down Expand Up @@ -266,7 +289,8 @@ Example:
"browser_version": "10.0",
"device": null,
"os": "Windows",
"os_version": "8"
"os_version": "8",
"cli_key": 1
}
]
}
Expand Down
5 changes: 3 additions & 2 deletions bin/init.js
Original file line number Diff line number Diff line change
@@ -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
};

Expand Down
77 changes: 63 additions & 14 deletions bin/runner.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 <key1> <key2> ...');
}
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) {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
24 changes: 16 additions & 8 deletions presets/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
40 changes: 39 additions & 1 deletion tests/behaviour/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
});
});
});

0 comments on commit 2ff95f2

Please sign in to comment.