Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser map refactor 3 #17

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 3 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -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' ),
Expand Down Expand Up @@ -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 ) {
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions lib/darwin/index.js
Original file line number Diff line number Diff line change
@@ -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' );
256 changes: 124 additions & 132 deletions lib/detect.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,70 @@
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 = {
'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'
};

/**
* Detect all available browsers on Windows systems.
* 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 assign({
type: browser.name,
name: browser.name,
command: browser.path,
version: browser.version
}, br || {} );
} );
}, br);
});

callback( available );
} );
callback(available);
});
}

/**
Expand All @@ -90,45 +73,41 @@ function detectWindows( callback ) {
* @param {String} name Name of a browser
* @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 );
}
} );
}
} else {
checkOthers( name, callback );
function checkDarwin(name, callback) {
if (darwin[name].all) {
darwin[name].all(function (err, available) {
if (err) {
return callback('failed to get version for ' + name);
}
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) {
if (err) {
return callback('failed to get path for ' + name);
}

callback(null, version, path);
});
});
}

/**
* 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 ) {
Expand All @@ -149,65 +128,78 @@ function checkOthers( name, callback ) {
return callback( 'not installed' );
}

var m = re.exec( data );
var match = regex.exec( data );
var version = match ? match[1] : data.trim();
callback(null, version);
} );
}

function flattenBrowsers(shouldUseDarwinDetector) {
var flatBrowsers = [];

if ( m ) {
callback( null, m[ 1 ] );
} else {
callback( null, data.trim() );
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.
* @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
} ) );
} );
} else {
available.push( extend( {}, br, {
command: p || name,
version: v
} ) );
var available = [],
detectAttempts = 0,
flattened = flattenBrowsers(shouldUseDarwinDetector);
flattened.forEach(function(flatBrowser) {
function cb(err, version, path) {
detectAttempts++;
if (!err) {
if (!Array.isArray(version)) {
version = [{path: path, version: version}];
}

version.forEach(function(item) {
available.push(assign({}, flatBrowser, {
command: item.path || flatBrowser.command,
version: item.version
}));
});
}

next();
} );
}
if (detectAttempts === flattened.length) {
callback(available);
}
}

next();
if (shouldUseDarwinDetector(flatBrowser.name)) {
return checkDarwin(flatBrowser.name, cb);
}
checkOthers(flatBrowser.command, flatBrowser.regex, cb);
});
};