From ab8ef85ae4db60e8535a086c74e51f19658a5a07 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 16:06:09 +0100 Subject: [PATCH 01/20] Set up wanted structure --- lib/detect.js | 77 +++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 6fdf258..eeaf382 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -3,64 +3,45 @@ var spawn = require( 'child_process' ).spawn, darwin = require( './darwin' ), extend = require( 'lodash' ).extend, browsers = { - 'google-chrome': { - name: 'chrome', - re: /Google Chrome (\S+)/, - type: 'chrome', - profile: true - }, - 'google-chrome-canary': { - name: 'canary', - re: /Google Chrome (\S+)/, - type: 'chrome', - profile: true - }, - 'chromium': { - name: 'chromium', - re: /Chromium (\S+)/, - type: 'chrome', - profile: true + chrome: { + regex: /Google Chrome (\S+)/, + profile: true, + variants: { + 'chrome': [ 'google-chrome', 'google-chrome-stable' ], + 'chrome-beta': 'google-chrome-beta', + 'chrome-canary': 'google-chrome-canary' + } }, - 'chromium-browser': { - name: 'chromium', - re: /Chromium (\S+)/, - type: 'chrome', - profile: true + chromium: { + regex: /Chromium (\S+)/, + profile: true, + variants: { + 'chromium': [ 'chromium', 'chromium-browser' ] + } }, - 'firefox': { - name: 'firefox', - re: /Mozilla Firefox (\S+)/, - type: 'firefox', - profile: true + firefox: { + regex: /Mozilla Firefox (\S+)/, + profile: true, + variants: { + 'firefox': 'firefox', + 'firefox-developer': 'firefox-developer' + } }, - 'phantomjs': { - name: 'phantomjs', - re: /(\S+)/, - type: 'phantom', - headless: true, - profile: false + phantomjs: { + regex: /(\S+)/, + profile: false, + headless: true }, - 'safari': { - name: 'safari', - type: 'safari', + safari: { profile: false }, - 'ie': { - name: 'ie', - type: 'ie', + ie: { profile: false }, - 'opera': { - name: 'opera', - re: /Opera (\S+)/, - type: 'opera', - image: 'opera.exe', + opera: { + regex: /Opera (\S+)/, profile: true } - }, - winDetectMap = { - chrome: 'google-chrome', - chromium: 'chromium-browser' }; /** From bbea971dc5ba824f7695fadeab99ffed54af7474 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 17:00:13 +0100 Subject: [PATCH 02/20] Finish refactor, update breaking changes --- CHANGELOG.md | 3 +- index.js | 6 +- lib/detect.js | 167 +++++++++++++++++++++++++++----------------------- 3 files changed, 96 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f0b73..16b5753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## Upcoming Release #### Breaking changes -- None yet +- Type `phantom` is now `phantomjs`, which is a little more consistent +- The property "name" is more descriptive for variant channels, e.g. "chrome-canary" #### User features - None yet diff --git a/index.js b/index.js index f81d529..44c2916 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ var path = require( 'path' ), - _ = require( 'lodash' ), + pick = require( 'lodash/pick' ), configModule = require( './lib/config' ), detect = require( './lib/detect' ), run = require( './lib/run' ), @@ -75,14 +75,14 @@ function getLauncher( configFile, callback ) { getLauncher.detect = function( callback ) { detect( function( browsers ) { callback( browsers.map( function( browser ) { - return _.pick( browser, [ 'name', 'version', 'type', 'command' ] ); + return pick( browser, [ 'name', 'version', 'type', 'command' ] ); } ) ); } ); }; /** * Update the browsers cache and create new profiles if necessary - * @param {String} configDir Path to the configuration file + * @param {String} configFile Path to the configuration file * @param {Function} callback Callback function */ getLauncher.update = function( configFile, callback ) { diff --git a/lib/detect.js b/lib/detect.js index eeaf382..40a0f54 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -1,30 +1,31 @@ var spawn = require( 'child_process' ).spawn, winDetect = require( 'win-detect-browsers' ), darwin = require( './darwin' ), - extend = require( 'lodash' ).extend, + assign = require('lodash/assign'), + omit = require('lodash/omit'), browsers = { chrome: { regex: /Google Chrome (\S+)/, profile: true, variants: { - 'chrome': [ 'google-chrome', 'google-chrome-stable' ], - 'chrome-beta': 'google-chrome-beta', - 'chrome-canary': 'google-chrome-canary' + 'chrome': ['google-chrome', 'google-chrome-stable'], + 'chrome-beta': ['google-chrome-beta'], + 'chrome-canary': ['google-chrome-canary'] } }, chromium: { regex: /Chromium (\S+)/, profile: true, variants: { - 'chromium': [ 'chromium', 'chromium-browser' ] + 'chromium': ['chromium', 'chromium-browser'] } }, firefox: { regex: /Mozilla Firefox (\S+)/, profile: true, variants: { - 'firefox': 'firefox', - 'firefox-developer': 'firefox-developer' + 'firefox': ['firefox'], + 'firefox-developer': ['firefox-developer'] } }, phantomjs: { @@ -72,32 +73,28 @@ function detectWindows( callback ) { * @param {Function} callback Callback function */ function checkDarwin( name, callback ) { - if ( darwin[ name ] ) { - if ( darwin[ name ].all ) { - darwin[ name ].all( function( err, available ) { - if ( err ) { - callback( 'failed to get version for ' + name ); - } else { - callback( err, available ); - } - } ); - } else { - darwin[ name ].version( function( err, version ) { - if ( version ) { - darwin[ name ].path( function( err, p ) { - if ( err ) { - return callback( 'failed to get path for ' + name ); - } - - callback( null, version, p ); - } ); - } else { - callback( 'failed to get version for ' + name ); - } - } ); - } + if ( darwin[ name ].all ) { + darwin[ name ].all( function( err, available ) { + if ( err ) { + callback( 'failed to get version for ' + name ); + } else { + callback( err, available ); + } + } ); } else { - checkOthers( name, callback ); + darwin[ name ].version( function( err, version ) { + if ( version ) { + darwin[ name ].path( function( err, p ) { + if ( err ) { + return callback( 'failed to get path for ' + name ); + } + + callback( null, version, p ); + } ); + } else { + callback( 'failed to get version for ' + name ); + } + } ); } } @@ -105,11 +102,11 @@ function checkDarwin( name, callback ) { * Check if the given browser is available (on Unix systems). * Pass its version to the callback function if found. * @param {String} name Name of a browser + * @param {RegExp} regex Extracts version from command output * @param {Function} callback Callback function */ -function checkOthers( name, callback ) { +function checkOthers( name, regex, callback ) { var process = spawn( name, [ '--version' ] ), - re = browsers[ name ].re, data = ''; process.stdout.on( 'data', function( buf ) { @@ -130,65 +127,83 @@ function checkOthers( name, callback ) { return callback( 'not installed' ); } - var m = re.exec( data ); + var match = regex.exec( data ); - if ( m ) { - callback( null, m[ 1 ] ); + if ( match ) { + callback( null, match[ 1 ] ); } else { callback( null, data.trim() ); } } ); } +function flattenBrowsers(shouldUseDarwinDetector) { + var flatBrowsers = []; + + Object.keys(browsers).forEach(function(type) { + var variants = browsers[type].variants; + var config = omit(browsers[type], 'variants'); + + if (!variants) { + return flatBrowsers.push(assign({type: type, name: type, command: type}, config)); + } + + Object.keys(variants).map(function(name) { + if (shouldUseDarwinDetector(name)) { + return flatBrowsers.push(assign({type, name}, config)); // `command` not needed, will use darwin detector + } + + return variants[name].map(function(command) { + flatBrowsers.push(assign({type, name, command}, config)); + }); + }); + }); + + return flatBrowsers; +} + /** * Detect all available web browsers. * Pass an array of available browsers to the callback function when done. * @param {Function} callback Callback function */ -module.exports = function detect( callback ) { - var available = [], - names, - check; - - if ( process.platform === 'win32' ) { - return detectWindows( callback ); - } else if ( process.platform === 'darwin' ) { - check = checkDarwin; - } else { - check = checkOthers; +module.exports = function detect(callback) { + if (process.platform === 'win32') { + return detectWindows(callback); } - names = Object.keys( browsers ); - - function next() { - var name = names.shift(); - - if ( !name ) { - return callback( available ); - } + function shouldUseDarwinDetector(browserName) { + return process.platform === 'darwin' && darwin[browserName]; + } - var br = browsers[ name ]; - - check( name, function( err, v, p ) { - if ( err === null ) { - if ( Array.isArray( v ) ) { - v.forEach( function( item ) { - available.push( extend( {}, br, { - command: item.path, - version: item.version - } ) ); - } ); + var available = [], + detectAttempts = 0, + flattened = flattenBrowsers(shouldUseDarwinDetector); + flattened.forEach(function(flatBrowser) { + function cb(err, version, path) { + detectAttempts++; + if (!err) { + if (Array.isArray(version)) { + version.forEach(function(item) { + flatBrowser.command = item.path || flatBrowser.command; + flatBrowser.version = item.version; + available.push(flatBrowser); + }); } else { - available.push( extend( {}, br, { - command: p || name, - version: v - } ) ); + flatBrowser.command = path || flatBrowser.command; + flatBrowser.version = version; + available.push(flatBrowser); } } - next(); - } ); - } + if (detectAttempts === flattened.length) { + callback(available); + } + } - next(); -}; + if (shouldUseDarwinDetector(flatBrowser.name)) { + return checkDarwin(flatBrowser.name, cb); + } + checkOthers(flatBrowser.command, flatBrowser.regex, cb); + }); +}; \ No newline at end of file From 98bd1f2abe36834c13f4923aaa2b5d9781cda810 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 17:02:47 +0100 Subject: [PATCH 03/20] Fix refactor on windows --- lib/detect.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 40a0f54..6a8012c 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -50,20 +50,20 @@ var spawn = require( 'child_process' ).spawn, * Pass an array of detected browsers to the callback function when done. * @param {Function} callback Callback function */ -function detectWindows( callback ) { - winDetect( function( found ) { - var available = found.map( function( browser ) { - var br = browsers[ winDetectMap[ browser.name ] || browser.name ]; +function detectWindows(callback) { + winDetect(function (found) { + var available = found.map(function (browser) { + var br = omit(browsers[browser.name], 'variants'); - return extend( {}, { + return extend({ name: browser.name, command: browser.path, version: browser.version - }, br || {} ); - } ); + }, br); + }); - callback( available ); - } ); + callback(available); + }); } /** From 3174ee990401d81925c848e3e4e91f2655e1545a Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 17:03:12 +0100 Subject: [PATCH 04/20] Extend is now assign in Lodash --- lib/detect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/detect.js b/lib/detect.js index 6a8012c..a720cc7 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -55,7 +55,7 @@ function detectWindows(callback) { var available = found.map(function (browser) { var br = omit(browsers[browser.name], 'variants'); - return extend({ + return assign({ name: browser.name, command: browser.path, version: browser.version From 90a4b2a8a90759306c54757d075dc535bb1ff63e Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 17:03:58 +0100 Subject: [PATCH 05/20] Missing type on Windows --- lib/detect.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/detect.js b/lib/detect.js index a720cc7..0a88ec2 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -56,6 +56,7 @@ function detectWindows(callback) { var br = omit(browsers[browser.name], 'variants'); return assign({ + type: browser.name, name: browser.name, command: browser.path, version: browser.version From 20bcacd682ea4be88e26380a375ec09629d6ca25 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 21:20:12 +0100 Subject: [PATCH 06/20] Properly support older JS version Code reduction --- lib/detect.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 0a88ec2..57c1605 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -151,11 +151,11 @@ function flattenBrowsers(shouldUseDarwinDetector) { Object.keys(variants).map(function(name) { if (shouldUseDarwinDetector(name)) { - return flatBrowsers.push(assign({type, name}, config)); // `command` not needed, will use darwin detector + return flatBrowsers.push(assign({type: type, name: name}, config)); // `command` not needed, will use darwin detector } return variants[name].map(function(command) { - flatBrowsers.push(assign({type, name, command}, config)); + flatBrowsers.push(assign({type: type, name: name, command: command}, config)); }); }); }); @@ -184,17 +184,15 @@ module.exports = function detect(callback) { function cb(err, version, path) { detectAttempts++; if (!err) { - if (Array.isArray(version)) { - version.forEach(function(item) { - flatBrowser.command = item.path || flatBrowser.command; - flatBrowser.version = item.version; - available.push(flatBrowser); - }); - } else { - flatBrowser.command = path || flatBrowser.command; - flatBrowser.version = version; - available.push(flatBrowser); + if (!Array.isArray(version)) { + version = [{path: path, version: version}]; } + + version.forEach(function(item) { + flatBrowser.command = item.path || flatBrowser.command; + flatBrowser.version = item.version; + available.push(flatBrowser); + }); } if (detectAttempts === flattened.length) { @@ -207,4 +205,4 @@ module.exports = function detect(callback) { } checkOthers(flatBrowser.command, flatBrowser.regex, cb); }); -}; \ No newline at end of file +}; From 53c3b7754baf675fdaee83f0ea92ae69f1dc7ec1 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 21:25:00 +0100 Subject: [PATCH 07/20] Update darwin detectors --- lib/darwin/{canary.js => chrome-canary.js} | 0 lib/darwin/index.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/darwin/{canary.js => chrome-canary.js} (100%) diff --git a/lib/darwin/canary.js b/lib/darwin/chrome-canary.js similarity index 100% rename from lib/darwin/canary.js rename to lib/darwin/chrome-canary.js diff --git a/lib/darwin/index.js b/lib/darwin/index.js index c92c4ca..d83a3b7 100644 --- a/lib/darwin/index.js +++ b/lib/darwin/index.js @@ -1,7 +1,7 @@ exports.safari = require( './safari' ); exports.firefox = require( './firefox' ); -exports.chrome = exports[ 'google-chrome' ] = require( './chrome' ); +exports.chrome = require( './chrome' ); exports.chromium = require( './chromium' ); -exports.canary = exports[ 'chrome-canary' ] = exports[ 'google-chrome-canary' ] = require( './canary' ); +exports[ 'chrome-canary' ] = require( './chrome-canary' ); exports.opera = require( './opera' ); exports.phantomjs = require( './phantomjs' ); From 69849d63bb23252037a1ebfe74872302e7a9d994 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 21:27:44 +0100 Subject: [PATCH 08/20] All flatBrowsers should have name, type, command (+ config) --- lib/detect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/detect.js b/lib/detect.js index 57c1605..b32994e 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -151,7 +151,7 @@ function flattenBrowsers(shouldUseDarwinDetector) { Object.keys(variants).map(function(name) { if (shouldUseDarwinDetector(name)) { - return flatBrowsers.push(assign({type: type, name: name}, config)); // `command` not needed, will use darwin detector + return flatBrowsers.push(assign({type: type, name: name, command: command}, config)); } return variants[name].map(function(command) { From 7fd09e5e83fe6e0d34b94eec67429ae752fc3de7 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 21:37:50 +0100 Subject: [PATCH 09/20] Flatten checkDarwin --- lib/detect.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index b32994e..33ee32c 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -73,30 +73,30 @@ function detectWindows(callback) { * @param {String} name Name of a browser * @param {Function} callback Callback function */ -function checkDarwin( name, callback ) { - if ( darwin[ name ].all ) { - darwin[ name ].all( function( err, available ) { - if ( err ) { - callback( 'failed to get version for ' + name ); - } else { - callback( err, available ); +function checkDarwin(name, callback) { + if (darwin[name].all) { + darwin[name].all(function (err, available) { + if (err) { + return callback('failed to get version for ' + name); } - } ); - } else { - darwin[ name ].version( function( err, version ) { - if ( version ) { - darwin[ name ].path( function( err, p ) { - if ( err ) { - return callback( 'failed to get path for ' + name ); - } - - callback( null, version, p ); - } ); - } else { - callback( 'failed to get version for ' + name ); - } - } ); + callback(undefined, available); + }); + return; } + + darwin[name].version(function (err, version) { + if (err) { + return callback('failed to get version for ' + name); + } + + darwin[name].path(function (err, path) { + if (err) { + return callback('failed to get path for ' + name); + } + + callback(undefined, version, path); + }); + }); } /** From cc897e27cc7e47b9de812c12564ee69ac00aee88 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 21:52:34 +0100 Subject: [PATCH 10/20] Embrace immutability in setting version and path --- lib/detect.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 33ee32c..6ef7f02 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -79,7 +79,7 @@ function checkDarwin(name, callback) { if (err) { return callback('failed to get version for ' + name); } - callback(undefined, available); + callback(null, available); }); return; } @@ -94,7 +94,7 @@ function checkDarwin(name, callback) { return callback('failed to get path for ' + name); } - callback(undefined, version, path); + callback(null, version, path); }); }); } @@ -129,12 +129,8 @@ function checkOthers( name, regex, callback ) { } var match = regex.exec( data ); - - if ( match ) { - callback( null, match[ 1 ] ); - } else { - callback( null, data.trim() ); - } + var version = match ? match[1] : data.trim(); + callback(null, version); } ); } @@ -189,9 +185,10 @@ module.exports = function detect(callback) { } version.forEach(function(item) { - flatBrowser.command = item.path || flatBrowser.command; - flatBrowser.version = item.version; - available.push(flatBrowser); + available.push(assign({ + command: item.path || flatBrowser.command, + version: item.version + }, flatBrowser)); }); } From 5413e5c574f6f7368cbcf6467fe6cabac1e05ee3 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Sun, 28 Feb 2016 22:07:48 +0100 Subject: [PATCH 11/20] Fix usage of assign --- lib/detect.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 6ef7f02..e32a67d 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -185,10 +185,10 @@ module.exports = function detect(callback) { } version.forEach(function(item) { - available.push(assign({ + available.push(assign({}, flatBrowser, { command: item.path || flatBrowser.command, version: item.version - }, flatBrowser)); + })); }); } From 2831a4a89731ca756ab12d4d48fd2b34f6aa6237 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 29 Feb 2016 14:19:50 +0100 Subject: [PATCH 12/20] Import 'omit' properly Set up type and name on 'available' browser object --- lib/browsers.js | 85 +++++++++++++++++++++++++++ lib/detect.js | 150 ++++++++++++++++++------------------------------ 2 files changed, 141 insertions(+), 94 deletions(-) create mode 100644 lib/browsers.js diff --git a/lib/browsers.js b/lib/browsers.js new file mode 100644 index 0000000..c072601 --- /dev/null +++ b/lib/browsers.js @@ -0,0 +1,85 @@ +/** + * Created by mitch on 2/29/16. + */ +var omit = require('lodash/omit'); + +var browsers = { + chrome: { + regex: /Google Chrome (\S+)/, + profile: true, + variants: { + 'chrome': ['google-chrome', 'google-chrome-stable'], + 'chrome-beta': ['google-chrome-beta'], + 'chrome-canary': ['google-chrome-canary'] + } + }, + chromium: { + regex: /Chromium (\S+)/, + profile: true, + variants: { + 'chromium': ['chromium', 'chromium-browser'] + } + }, + firefox: { + regex: /Mozilla Firefox (\S+)/, + profile: true, + variants: { + 'firefox': ['firefox'], + 'firefox-developer': ['firefox-developer'] + } + }, + phantomjs: { + regex: /(\S+)/, + profile: false, + headless: true + }, + safari: { + profile: false + }, + ie: { + profile: false + }, + opera: { + regex: /Opera (\S+)/, + profile: true + } +}; + +/** + * Compiles each browser into the relevant data for Linux or Darwin. The structure of each object returned is: + * type: type of browser, e.g.: "chrome", "chromium", "ie" + * darwin: name of browser, used to look up "darwin detector" (see "./darwin" folder) + * linux: array of commands that the browser might run as on a 'nix environment + * regex: extracts version code when browser is run as a command + * @returns {Array} + */ +function browserPlatforms() { + var _browsers = []; + + Object.keys(browsers).forEach(function(type) { + var regex = browsers[type].regex; + var variants = browsers[type].variants; + + if (!variants) { + return _browsers.push({type: type, darwin: type, linux: [type], regex: regex}); + } + + Object.keys(variants).map(function(name) { + return _browsers.push({type: type, darwin: name, linux: variants[name], regex: regex}); + }); + }); + + return _browsers; +} + +/** + * Returns the configuration for the browser type specified + * @param type type of browser + * @returns {Object} config for the specified browser type + */ +function typeConfig(type) { + return omit(browsers[type], 'variants'); +} + +module.exports.browserPlatforms = browserPlatforms; +module.exports.typeConfig = typeConfig; \ No newline at end of file diff --git a/lib/detect.js b/lib/detect.js index e32a67d..5e87fdf 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -1,49 +1,9 @@ var spawn = require( 'child_process' ).spawn, winDetect = require( 'win-detect-browsers' ), darwin = require( './darwin' ), + browsers = require('./browsers'), assign = require('lodash/assign'), - omit = require('lodash/omit'), - browsers = { - chrome: { - regex: /Google Chrome (\S+)/, - profile: true, - variants: { - 'chrome': ['google-chrome', 'google-chrome-stable'], - 'chrome-beta': ['google-chrome-beta'], - 'chrome-canary': ['google-chrome-canary'] - } - }, - chromium: { - regex: /Chromium (\S+)/, - profile: true, - variants: { - 'chromium': ['chromium', 'chromium-browser'] - } - }, - firefox: { - regex: /Mozilla Firefox (\S+)/, - profile: true, - variants: { - 'firefox': ['firefox'], - 'firefox-developer': ['firefox-developer'] - } - }, - phantomjs: { - regex: /(\S+)/, - profile: false, - headless: true - }, - safari: { - profile: false - }, - ie: { - profile: false - }, - opera: { - regex: /Opera (\S+)/, - profile: true - } - }; + omit = require('lodash/omit'); /** * Detect all available browsers on Windows systems. @@ -53,14 +13,14 @@ var spawn = require( 'child_process' ).spawn, function detectWindows(callback) { winDetect(function (found) { var available = found.map(function (browser) { - var br = omit(browsers[browser.name], 'variants'); + var config = browsers.typeConfig(browser.name); return assign({ type: browser.name, name: browser.name, command: browser.path, version: browser.version - }, br); + }, config); }); callback(available); @@ -72,8 +32,13 @@ function detectWindows(callback) { * Pass its version and path to the callback function if found. * @param {String} name Name of a browser * @param {Function} callback Callback function + * @return {Boolean} true if there exists a "darwin detector" for the provided browser name */ function checkDarwin(name, callback) { + if (!(process.platform === 'darwin' && darwin[name])) { + return false; + } + if (darwin[name].all) { darwin[name].all(function (err, available) { if (err) { @@ -81,22 +46,22 @@ function checkDarwin(name, callback) { } callback(null, available); }); - return; - } - - darwin[name].version(function (err, version) { - if (err) { - return callback('failed to get version for ' + name); - } - - darwin[name].path(function (err, path) { + } else { + darwin[name].version(function (err, version) { if (err) { - return callback('failed to get path for ' + name); + return callback('failed to get version for ' + name); } - callback(null, version, path); + darwin[name].path(function (err, path) { + if (err) { + return callback('failed to get path for ' + name); + } + + callback(null, version, path); + }); }); - }); + } + return true; } /** @@ -134,31 +99,6 @@ function checkOthers( name, regex, callback ) { } ); } -function flattenBrowsers(shouldUseDarwinDetector) { - var flatBrowsers = []; - - Object.keys(browsers).forEach(function(type) { - var variants = browsers[type].variants; - var config = omit(browsers[type], 'variants'); - - if (!variants) { - return flatBrowsers.push(assign({type: type, name: type, command: type}, config)); - } - - Object.keys(variants).map(function(name) { - if (shouldUseDarwinDetector(name)) { - return flatBrowsers.push(assign({type: type, name: name, command: command}, config)); - } - - return variants[name].map(function(command) { - flatBrowsers.push(assign({type: type, name: name, command: command}, config)); - }); - }); - }); - - return flatBrowsers; -} - /** * Detect all available web browsers. * Pass an array of available browsers to the callback function when done. @@ -169,15 +109,15 @@ module.exports = function detect(callback) { return detectWindows(callback); } - function shouldUseDarwinDetector(browserName) { - return process.platform === 'darwin' && darwin[browserName]; - } - var available = [], detectAttempts = 0, - flattened = flattenBrowsers(shouldUseDarwinDetector); - flattened.forEach(function(flatBrowser) { - function cb(err, version, path) { + browserPlatforms = browsers.browserPlatforms(); + + browserPlatforms.forEach(function(browserPlatform) { + var linuxChecks = 0; + var linuxVersion; + + function browserDone(err, version, path) { detectAttempts++; if (!err) { if (!Array.isArray(version)) { @@ -185,21 +125,43 @@ module.exports = function detect(callback) { } version.forEach(function(item) { - available.push(assign({}, flatBrowser, { - command: item.path || flatBrowser.command, + var config = browsers.typeConfig(browserPlatform.type); + available.push(assign({}, config, { + type: browserPlatform.type, + name: browserPlatform.darwin, + command: item.path, version: item.version })); }); } - if (detectAttempts === flattened.length) { + if (detectAttempts === browserPlatforms.length) { callback(available); } } - if (shouldUseDarwinDetector(flatBrowser.name)) { - return checkDarwin(flatBrowser.name, cb); + if (!checkDarwin(browserPlatform.darwin, browserDone)) { + browserPlatform.linux.forEach(function(command) { + + /* + There could be multiple commands run per browser on Linux, and we can't call `browserDone`, because then it + will be called more than `browserPlatforms.length` times. + + This callback function debounces it, and also takes care of the case when the same browser matches + multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and + passed onto `browserDone` + */ + checkOthers(command, browserPlatform.regex, function linuxDone(err, version) { + linuxChecks++; + if (!err) { + linuxVersion = version; + } + + if (linuxChecks == browserPlatform.linux.length) { + browserDone(!linuxVersion ? 'Browser not found' : null, linuxVersion, command); + } + }); + }); } - checkOthers(flatBrowser.command, flatBrowser.regex, cb); }); }; From 23434752b925cf0b6251460b7e46ac9cce7304dd Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 29 Feb 2016 14:24:22 +0100 Subject: [PATCH 13/20] Add optional `browserList` param to `browserPlatforms` --- lib/browsers.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/browsers.js b/lib/browsers.js index c072601..9708764 100644 --- a/lib/browsers.js +++ b/lib/browsers.js @@ -51,14 +51,18 @@ var browsers = { * darwin: name of browser, used to look up "darwin detector" (see "./darwin" folder) * linux: array of commands that the browser might run as on a 'nix environment * regex: extracts version code when browser is run as a command + * + * @param {Array} [browserList] list of browsers to extract platform details from. Default is internal list, this + * param should be used for testing * @returns {Array} */ -function browserPlatforms() { +function browserPlatforms(browserList) { var _browsers = []; + browserList = browserList || browsers; - Object.keys(browsers).forEach(function(type) { - var regex = browsers[type].regex; - var variants = browsers[type].variants; + Object.keys(browserList).forEach(function(type) { + var regex = browserList[type].regex; + var variants = browserList[type].variants; if (!variants) { return _browsers.push({type: type, darwin: type, linux: [type], regex: regex}); From ab4b8d3f883b7525edb4ebdebef9c18ef80050a9 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 29 Feb 2016 14:28:30 +0100 Subject: [PATCH 14/20] Remove unused import Add ava --- lib/detect.js | 3 +- package.json | 108 +++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index 5e87fdf..e212e8b 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -2,8 +2,7 @@ var spawn = require( 'child_process' ).spawn, winDetect = require( 'win-detect-browsers' ), darwin = require( './darwin' ), browsers = require('./browsers'), - assign = require('lodash/assign'), - omit = require('lodash/omit'); + assign = require('lodash/assign'); /** * Detect all available browsers on Windows systems. diff --git a/package.json b/package.json index f6bf945..f538c46 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,57 @@ { - "name": "james-browser-launcher", - "version": "1.1.0", - "description": "Detect, launch and stop browser versions", - "main": "index.js", - "scripts": { - "lint": "jscs . && jshint index.js lib/ example/" - }, - "directories": { - "example": "example", - "res": "res" - }, - "dependencies": { - "headless": "^1.0.0", - "lodash": "^4.5.1", - "mkdirp": "^0.5.0", - "osenv": "^0.1.0", - "plist": "^1.0.1", - "win-detect-browsers": "^2.1.0", - "uid": "0.0.2", - "rimraf": "~2.5.2" - }, - "repository": { - "type": "git", - "url": "git://github.com/james-proxy/james-browser-launcher.git" - }, - "homepage": "https://github.com/james-proxy/james-browser-launcher", - "keywords": [ - "browser", - "headless", - "phantom", - "chrome", - "firefox", - "chromium", - "safari", - "ie", - "opera", - "osx", - "windows" - ], - "author": "James Halliday (http://substack.net)", - "contributors": [ - "CKSource (http://cksource.com/)", - "benderjs", - "mitchhentges" - ], - "license": "MIT", - "engine": { - "node": ">=0.8" - }, - "devDependencies": { - "jscs": "^2.10.1", - "jshint": "^2.5.2" - } + "name": "james-browser-launcher", + "version": "1.1.0", + "description": "Detect, launch and stop browser versions", + "main": "index.js", + "scripts": { + "lint": "jscs . && jshint index.js lib/ example/", + "test": "ava" + }, + "directories": { + "example": "example", + "res": "res" + }, + "dependencies": { + "headless": "^1.0.0", + "lodash": "^4.5.1", + "mkdirp": "^0.5.0", + "osenv": "^0.1.0", + "plist": "^1.0.1", + "win-detect-browsers": "^2.1.0", + "uid": "0.0.2", + "rimraf": "~2.5.2" + }, + "repository": { + "type": "git", + "url": "git://github.com/james-proxy/james-browser-launcher.git" + }, + "homepage": "https://github.com/james-proxy/james-browser-launcher", + "keywords": [ + "browser", + "headless", + "phantom", + "chrome", + "firefox", + "chromium", + "safari", + "ie", + "opera", + "osx", + "windows" + ], + "author": "James Halliday (http://substack.net)", + "contributors": [ + "CKSource (http://cksource.com/)", + "benderjs", + "mitchhentges" + ], + "license": "MIT", + "engine": { + "node": ">=0.8" + }, + "devDependencies": { + "ava": "^0.12.0", + "jscs": "^2.10.1", + "jshint": "^2.5.2" + } } From 478b09b7627498bec67a75267def32322e101640 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 29 Feb 2016 15:26:40 +0100 Subject: [PATCH 15/20] Add tests! --- lib/browsers.js | 32 ++++++++------ lib/detect.js | 5 ++- package.json | 6 +++ test/browsers.js | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 test/browsers.js diff --git a/lib/browsers.js b/lib/browsers.js index 9708764..c75d108 100644 --- a/lib/browsers.js +++ b/lib/browsers.js @@ -45,6 +45,15 @@ var browsers = { } }; +/** + * Used to get browser information and configuration. By default, uses internal browser list + * @param [browserList] list of browsers, configuration and variants + * @constructor + */ +function Browsers(browserList) { + this.browserList = browserList || browsers; +} + /** * Compiles each browser into the relevant data for Linux or Darwin. The structure of each object returned is: * type: type of browser, e.g.: "chrome", "chromium", "ie" @@ -52,17 +61,15 @@ var browsers = { * linux: array of commands that the browser might run as on a 'nix environment * regex: extracts version code when browser is run as a command * - * @param {Array} [browserList] list of browsers to extract platform details from. Default is internal list, this - * param should be used for testing * @returns {Array} */ -function browserPlatforms(browserList) { +Browsers.prototype.browserPlatforms = function browserPlatforms() { var _browsers = []; - browserList = browserList || browsers; + var browsers = this.browserList; - Object.keys(browserList).forEach(function(type) { - var regex = browserList[type].regex; - var variants = browserList[type].variants; + Object.keys(browsers).forEach(function(type) { + var regex = browsers[type].regex; + var variants = browsers[type].variants; if (!variants) { return _browsers.push({type: type, darwin: type, linux: [type], regex: regex}); @@ -74,16 +81,15 @@ function browserPlatforms(browserList) { }); return _browsers; -} +}; /** * Returns the configuration for the browser type specified * @param type type of browser * @returns {Object} config for the specified browser type */ -function typeConfig(type) { - return omit(browsers[type], 'variants'); -} +Browsers.prototype.typeConfig = function typeConfig(type) { + return omit(this.browserList[type], 'variants'); +}; -module.exports.browserPlatforms = browserPlatforms; -module.exports.typeConfig = typeConfig; \ No newline at end of file +module.exports = Browsers; \ No newline at end of file diff --git a/lib/detect.js b/lib/detect.js index e212e8b..ef814f0 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -1,8 +1,9 @@ var spawn = require( 'child_process' ).spawn, winDetect = require( 'win-detect-browsers' ), darwin = require( './darwin' ), - browsers = require('./browsers'), - assign = require('lodash/assign'); + assign = require('lodash/assign'), + Browsers = require('./browsers'), + browsers = new Browsers(); /** * Detect all available browsers on Windows systems. diff --git a/package.json b/package.json index f538c46..3bf5a33 100644 --- a/package.json +++ b/package.json @@ -53,5 +53,11 @@ "ava": "^0.12.0", "jscs": "^2.10.1", "jshint": "^2.5.2" + }, + "ava": { + "failFast": true, + "files": [ + "test/**/*.js" + ] } } diff --git a/test/browsers.js b/test/browsers.js new file mode 100644 index 0000000..1b80ff8 --- /dev/null +++ b/test/browsers.js @@ -0,0 +1,106 @@ +/** + * Created by mitch on 2/29/16. + */ +import test from 'ava'; +import Browsers from '../lib/browsers'; + +test('browser platforms without any variants', t => { + var browsers = new Browsers({ + firefox: {} + }); + + t.same(browsers.browserPlatforms(), [{ + type: 'firefox', + darwin: 'firefox', + linux: ['firefox'], + regex: undefined + }]); +}); + +test('browser platforms with multiple variants', t => { + var browsers = new Browsers({ + firefox: { + variants: { + 'firefox': ['firefox'], + 'firefox-developer': ['firefox-developer'] + } + } + }); + + t.same(browsers.browserPlatforms(), [{ + type: 'firefox', + darwin: 'firefox', + linux: ['firefox'], + regex: undefined + },{ + type: 'firefox', + darwin: 'firefox-developer', + linux: ['firefox-developer'], + regex: undefined + }]); +}); + +test('browser platforms when command is different from variant name', t => { + var browsers = new Browsers({ + chrome: { + variants: { + 'chrome': ['google-chrome'] + } + } + }); + + t.same(browsers.browserPlatforms(), [{ + type: 'chrome', + darwin: 'chrome', + linux: ['google-chrome'], + regex: undefined + }]); +}); + +test('browser platforms when multiple commands are possible for a variant', t => { + var browsers = new Browsers({ + chrome: { + variants: { + 'chrome': ['google-chrome', 'google-chrome-stable'] + } + } + }); + + t.same(browsers.browserPlatforms(), [{ + type: 'chrome', + darwin: 'chrome', + linux: ['google-chrome', 'google-chrome-stable'], + regex: undefined + }]); +}); + +test('browser config by type', t => { + var browsers = new Browsers({ + chrome: { + profile: true + }, + firefox: { + profile: false + } + }); + + t.same(browsers.typeConfig('firefox'), { + profile: false + }); +}); + +test('browser config supports all options', t => { + var browsers = new Browsers({ + chrome: { + startupTime: 1000, + nsaUplink: true, + 'john-cena': 'champ' + } + }); + + t.same(browsers.typeConfig('chrome'), { + startupTime: 1000, + nsaUplink: true, + 'john-cena': 'champ' + }); +}); \ No newline at end of file From 640a300b01ed7358e52fa5de7704c27259226a67 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 29 Feb 2016 15:31:22 +0100 Subject: [PATCH 16/20] Add travis.yml --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..25c3683 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - '4.1' +script: + - npm test \ No newline at end of file From 65eef71c983818c968d6a8047267a665f835f664 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Tue, 1 Mar 2016 12:39:57 +0100 Subject: [PATCH 17/20] Break up ! check on using darwin detector --- lib/detect.js | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index ef814f0..f150fb2 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -140,28 +140,31 @@ module.exports = function detect(callback) { } } - if (!checkDarwin(browserPlatform.darwin, browserDone)) { - browserPlatform.linux.forEach(function(command) { - - /* - There could be multiple commands run per browser on Linux, and we can't call `browserDone`, because then it - will be called more than `browserPlatforms.length` times. - - This callback function debounces it, and also takes care of the case when the same browser matches - multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and - passed onto `browserDone` - */ - checkOthers(command, browserPlatform.regex, function linuxDone(err, version) { - linuxChecks++; - if (!err) { - linuxVersion = version; - } - - if (linuxChecks == browserPlatform.linux.length) { - browserDone(!linuxVersion ? 'Browser not found' : null, linuxVersion, command); - } - }); - }); + var usingDarwinDetector = checkDarwin(browserPlatform.darwin, browserDone); + if (usingDarwinDetector) { + return; } + + browserPlatform.linux.forEach(function(command) { + + /* + There could be multiple commands run per browser on Linux, and we can't call `browserDone`, because then it + will be called more than `browserPlatforms.length` times. + + This callback function debounces it, and also takes care of the case when the same browser matches + multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and + passed onto `browserDone` + */ + checkOthers(command, browserPlatform.regex, function linuxDone(err, version) { + linuxChecks++; + if (!err) { + linuxVersion = version; + } + + if (linuxChecks == browserPlatform.linux.length) { + browserDone(!linuxVersion ? 'Browser not found' : null, linuxVersion, command); + } + }); + }); }); }; From a29dcb1d538955c205d65e5c119d157be1daa030 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Wed, 2 Mar 2016 00:40:55 +0100 Subject: [PATCH 18/20] Move unix-specific code from detect() method --- lib/detect.js | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index f150fb2..bf44420 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -32,13 +32,8 @@ function detectWindows(callback) { * Pass its version and path to the callback function if found. * @param {String} name Name of a browser * @param {Function} callback Callback function - * @return {Boolean} true if there exists a "darwin detector" for the provided browser name */ function checkDarwin(name, callback) { - if (!(process.platform === 'darwin' && darwin[name])) { - return false; - } - if (darwin[name].all) { darwin[name].all(function (err, available) { if (err) { @@ -61,17 +56,16 @@ function checkDarwin(name, callback) { }); }); } - return true; } /** - * Check if the given browser is available (on Unix systems). + * Attempt to run browser (on Unix systems). * Pass its version to the callback function if found. * @param {String} name Name of a browser * @param {RegExp} regex Extracts version from command output * @param {Function} callback Callback function */ -function checkOthers( name, regex, callback ) { +function runBrowserCommand( name, regex, callback ) { var process = spawn( name, [ '--version' ] ), data = ''; @@ -99,6 +93,33 @@ function checkOthers( name, regex, callback ) { } ); } +function checkUnix(commands, regex, cb) { + var checkCount = 0; + var detectedVersion; + + commands.forEach(function(command) { + + /* + There could be multiple commands run per browser on Linux, and we can't call the callback on _every_ + successful command invokation, because then it will be called more than `browserPlatforms.length` times. + + This callback function performs debouncing, and also takes care of the case when the same browser matches + multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and + passed on + */ + runBrowserCommand(command, regex, function linuxDone(err, version) { + checkCount++; + if (!err) { + detectedVersion = version; + } + + if (checkCount == commands.length) { + cb(!detectedVersion ? 'Browser not found' : null, detectedVersion, command); + } + }); + }); +} + /** * Detect all available web browsers. * Pass an array of available browsers to the callback function when done. @@ -114,9 +135,6 @@ module.exports = function detect(callback) { browserPlatforms = browsers.browserPlatforms(); browserPlatforms.forEach(function(browserPlatform) { - var linuxChecks = 0; - var linuxVersion; - function browserDone(err, version, path) { detectAttempts++; if (!err) { @@ -140,31 +158,11 @@ module.exports = function detect(callback) { } } - var usingDarwinDetector = checkDarwin(browserPlatform.darwin, browserDone); - if (usingDarwinDetector) { + if (process.platform === 'darwin' && darwin[name]) { + checkDarwin(browserPlatform.darwin, browserDone); return; } - browserPlatform.linux.forEach(function(command) { - - /* - There could be multiple commands run per browser on Linux, and we can't call `browserDone`, because then it - will be called more than `browserPlatforms.length` times. - - This callback function debounces it, and also takes care of the case when the same browser matches - multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and - passed onto `browserDone` - */ - checkOthers(command, browserPlatform.regex, function linuxDone(err, version) { - linuxChecks++; - if (!err) { - linuxVersion = version; - } - - if (linuxChecks == browserPlatform.linux.length) { - browserDone(!linuxVersion ? 'Browser not found' : null, linuxVersion, command); - } - }); - }); + checkUnix(browserPlatform.linux, browserPlatform.regex, browserDone) }); }; From dcd1b06754b2c6d63ad510b6ca56af62985f71cc Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Wed, 2 Mar 2016 00:42:17 +0100 Subject: [PATCH 19/20] missing semicolon --- lib/detect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/detect.js b/lib/detect.js index bf44420..bed3948 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -163,6 +163,6 @@ module.exports = function detect(callback) { return; } - checkUnix(browserPlatform.linux, browserPlatform.regex, browserDone) + checkUnix(browserPlatform.linux, browserPlatform.regex, browserDone); }); }; From fdb8c27046f8491013841bbaa9f6e1aad269f1a6 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Wed, 2 Mar 2016 00:49:57 +0100 Subject: [PATCH 20/20] JSDoc, better function naming --- lib/detect.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/detect.js b/lib/detect.js index bed3948..d7ef568 100644 --- a/lib/detect.js +++ b/lib/detect.js @@ -65,7 +65,7 @@ function checkDarwin(name, callback) { * @param {RegExp} regex Extracts version from command output * @param {Function} callback Callback function */ -function runBrowserCommand( name, regex, callback ) { +function getCommandVersion( name, regex, callback ) { var process = spawn( name, [ '--version' ] ), data = ''; @@ -93,6 +93,13 @@ function runBrowserCommand( name, regex, callback ) { } ); } +/** + * Check if the given browser is available (on Unix systems). + * Pass its version and command to the callback function if found. + * @param {Array} commands List of potential commands used to start browser + * @param {RegExp} regex extracts version from browser's command-line output + * @param {Function} callback Callback function + */ function checkUnix(commands, regex, cb) { var checkCount = 0; var detectedVersion; @@ -101,13 +108,13 @@ function checkUnix(commands, regex, cb) { /* There could be multiple commands run per browser on Linux, and we can't call the callback on _every_ - successful command invokation, because then it will be called more than `browserPlatforms.length` times. + successful command invocation, because then it will be called more than `browserPlatforms.length` times. This callback function performs debouncing, and also takes care of the case when the same browser matches multiple commands (due to symlinking or whatnot). Only the last _successful_ "check" will be saved and passed on */ - runBrowserCommand(command, regex, function linuxDone(err, version) { + getCommandVersion(command, regex, function linuxDone(err, version) { checkCount++; if (!err) { detectedVersion = version;