| var fs = require('fs') |
| var path = require('path') |
| var which = require('which') |
| |
| function isJSFlags (flag) { |
| return flag.indexOf('--js-flags=') === 0 |
| } |
| |
| function sanitizeJSFlags (flag) { |
| var test = /--js-flags=(['"])/.exec(flag) |
| if (!test) { |
| return flag |
| } |
| var escapeChar = test[1] |
| var endExp = new RegExp(escapeChar + '$') |
| var startExp = new RegExp('--js-flags=' + escapeChar) |
| return flag.replace(startExp, '--js-flags=').replace(endExp, '') |
| } |
| |
| var ChromeBrowser = function (baseBrowserDecorator, args) { |
| baseBrowserDecorator(this) |
| |
| var flags = args.flags || [] |
| var userDataDir = args.chromeDataDir || this._tempDir |
| |
| this._getOptions = function (url) { |
| // Chrome CLI options |
| // http://peter.sh/experiments/chromium-command-line-switches/ |
| flags.forEach(function (flag, i) { |
| if (isJSFlags(flag)) { |
| flags[i] = sanitizeJSFlags(flag) |
| } |
| }) |
| |
| return [ |
| '--user-data-dir=' + userDataDir, |
| // https://github.com/GoogleChrome/chrome-launcher/blob/master/docs/chrome-flags-for-tools.md#--enable-automation |
| '--enable-automation', |
| '--no-default-browser-check', |
| '--no-first-run', |
| '--disable-default-apps', |
| '--disable-popup-blocking', |
| '--disable-translate', |
| '--disable-background-timer-throttling', |
| // on macOS, disable-background-timer-throttling is not enough |
| // and we need disable-renderer-backgrounding too |
| // see https://github.com/karma-runner/karma-chrome-launcher/issues/123 |
| '--disable-renderer-backgrounding', |
| '--disable-device-discovery-notifications' |
| ].concat(flags, [url]) |
| } |
| } |
| |
| // Return location of chrome.exe file for a given Chrome directory (available: "Chrome", "Chrome SxS"). |
| function getChromeExe (chromeDirName) { |
| // Only run these checks on win32 |
| if (process.platform !== 'win32') { |
| return null |
| } |
| var windowsChromeDirectory, i, prefix |
| var suffix = '\\Google\\' + chromeDirName + '\\Application\\chrome.exe' |
| var prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']] |
| |
| for (i = 0; i < prefixes.length; i++) { |
| prefix = prefixes[i] |
| try { |
| windowsChromeDirectory = path.join(prefix, suffix) |
| fs.accessSync(windowsChromeDirectory) |
| return windowsChromeDirectory |
| } catch (e) {} |
| } |
| |
| return windowsChromeDirectory |
| } |
| |
| var ChromiumBrowser = function (baseBrowserDecorator, args) { |
| baseBrowserDecorator(this) |
| |
| var flags = args.flags || [] |
| var userDataDir = args.chromeDataDir || this._tempDir |
| |
| this._getOptions = function (url) { |
| // Chromium CLI options |
| // http://peter.sh/experiments/chromium-command-line-switches/ |
| flags.forEach(function (flag, i) { |
| if (isJSFlags(flag)) { |
| flags[i] = sanitizeJSFlags(flag) |
| } |
| }) |
| |
| return [ |
| '--user-data-dir=' + userDataDir, |
| '--no-default-browser-check', |
| '--no-first-run', |
| '--disable-default-apps', |
| '--disable-popup-blocking', |
| '--disable-translate', |
| '--disable-background-timer-throttling' |
| ].concat(flags, [url]) |
| } |
| } |
| |
| // Return location of Chromium's chrome.exe file. |
| function getChromiumExe (chromeDirName) { |
| // Only run these checks on win32 |
| if (process.platform !== 'win32') { |
| return null |
| } |
| var windowsChromiumDirectory, i, prefix |
| var suffix = '\\Chromium\\Application\\chrome.exe' |
| var prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']] |
| |
| for (i = 0; i < prefixes.length; i++) { |
| prefix = prefixes[i] |
| try { |
| windowsChromiumDirectory = path.join(prefix, suffix) |
| fs.accessSync(windowsChromiumDirectory) |
| return windowsChromiumDirectory |
| } catch (e) {} |
| } |
| |
| return windowsChromiumDirectory |
| } |
| |
| function getBin (commands) { |
| // Don't run these checks on win32 |
| if (process.platform !== 'linux') { |
| return null |
| } |
| var bin, i |
| for (i = 0; i < commands.length; i++) { |
| try { |
| if (which.sync(commands[i])) { |
| bin = commands[i] |
| break |
| } |
| } catch (e) {} |
| } |
| return bin |
| } |
| |
| function getChromeDarwin (defaultPath) { |
| if (process.platform !== 'darwin') { |
| return null |
| } |
| |
| try { |
| var homePath = path.join(process.env.HOME, defaultPath) |
| fs.accessSync(homePath) |
| return homePath |
| } catch (e) { |
| return defaultPath |
| } |
| } |
| |
| ChromeBrowser.prototype = { |
| name: 'Chrome', |
| |
| DEFAULT_CMD: { |
| linux: getBin(['google-chrome', 'google-chrome-stable']), |
| darwin: getChromeDarwin('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'), |
| win32: getChromeExe('Chrome') |
| }, |
| ENV_CMD: 'CHROME_BIN' |
| } |
| |
| ChromeBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| function headlessGetOptions (url, args, parent) { |
| var mergedArgs = parent.call(this, url, args).concat([ |
| '--headless', |
| '--disable-gpu', |
| '--disable-dev-shm-usage' |
| ]) |
| |
| var isRemoteDebuggingFlag = function (flag) { |
| return flag.indexOf('--remote-debugging-port=') !== -1 |
| } |
| |
| return mergedArgs.some(isRemoteDebuggingFlag) |
| ? mergedArgs |
| : mergedArgs.concat(['--remote-debugging-port=9222']) |
| } |
| |
| var ChromeHeadlessBrowser = function (baseBrowserDecorator, args) { |
| ChromeBrowser.apply(this, arguments) |
| |
| var parentOptions = this._getOptions |
| this._getOptions = function (url) { |
| return headlessGetOptions.call(this, url, args, parentOptions) |
| } |
| } |
| |
| ChromeHeadlessBrowser.prototype = { |
| name: 'ChromeHeadless', |
| |
| DEFAULT_CMD: { |
| linux: getBin(['google-chrome', 'google-chrome-stable']), |
| darwin: getChromeDarwin('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'), |
| win32: getChromeExe('Chrome') |
| }, |
| ENV_CMD: 'CHROME_BIN' |
| } |
| |
| ChromeHeadlessBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| function canaryGetOptions (url, args, parent) { |
| // disable crankshaft optimizations, as it causes lot of memory leaks (as of Chrome 23.0) |
| var flags = args.flags || [] |
| var augmentedFlags |
| var customFlags = '--nocrankshaft --noopt' |
| |
| flags.forEach(function (flag) { |
| if (isJSFlags(flag)) { |
| augmentedFlags = sanitizeJSFlags(flag) + ' ' + customFlags |
| } |
| }) |
| |
| return parent.call(this, url).concat([augmentedFlags || '--js-flags=' + customFlags]) |
| } |
| |
| var ChromeCanaryBrowser = function (baseBrowserDecorator, args) { |
| ChromeBrowser.apply(this, arguments) |
| |
| var parentOptions = this._getOptions |
| this._getOptions = function (url) { |
| return canaryGetOptions.call(this, url, args, parentOptions) |
| } |
| } |
| |
| ChromeCanaryBrowser.prototype = { |
| name: 'ChromeCanary', |
| |
| DEFAULT_CMD: { |
| linux: getBin(['google-chrome-canary', 'google-chrome-unstable']), |
| darwin: getChromeDarwin('/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'), |
| win32: getChromeExe('Chrome SxS') |
| }, |
| ENV_CMD: 'CHROME_CANARY_BIN' |
| } |
| |
| ChromeCanaryBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| var ChromeCanaryHeadlessBrowser = function (baseBrowserDecorator, args) { |
| ChromeCanaryBrowser.apply(this, arguments) |
| |
| var parentOptions = this._getOptions |
| this._getOptions = function (url) { |
| return headlessGetOptions.call(this, url, args, parentOptions) |
| } |
| } |
| |
| ChromeCanaryHeadlessBrowser.prototype = { |
| name: 'ChromeCanaryHeadless', |
| |
| DEFAULT_CMD: { |
| linux: getBin(['google-chrome-canary', 'google-chrome-unstable']), |
| darwin: getChromeDarwin('/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'), |
| win32: getChromeExe('Chrome SxS') |
| }, |
| ENV_CMD: 'CHROME_CANARY_BIN' |
| } |
| |
| ChromeCanaryHeadlessBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| ChromiumBrowser.prototype = { |
| name: 'Chromium', |
| |
| DEFAULT_CMD: { |
| // Try chromium-browser before chromium to avoid conflict with the legacy |
| // chromium-bsu package previously known as 'chromium' in Debian and Ubuntu. |
| linux: getBin(['chromium-browser', 'chromium']), |
| darwin: '/Applications/Chromium.app/Contents/MacOS/Chromium', |
| win32: getChromiumExe() |
| }, |
| ENV_CMD: 'CHROMIUM_BIN' |
| } |
| |
| ChromiumBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| var ChromiumHeadlessBrowser = function (baseBrowserDecorator, args) { |
| ChromiumBrowser.apply(this, arguments) |
| |
| var parentOptions = this._getOptions |
| this._getOptions = function (url) { |
| return headlessGetOptions.call(this, url, args, parentOptions) |
| } |
| } |
| |
| ChromiumHeadlessBrowser.prototype = { |
| name: 'ChromiumHeadless', |
| |
| DEFAULT_CMD: { |
| // Try chromium-browser before chromium to avoid conflict with the legacy |
| // chromium-bsu package previously known as 'chromium' in Debian and Ubuntu. |
| linux: getBin(['chromium-browser', 'chromium']), |
| darwin: '/Applications/Chromium.app/Contents/MacOS/Chromium', |
| win32: getChromiumExe() |
| }, |
| ENV_CMD: 'CHROMIUM_BIN' |
| } |
| |
| var DartiumBrowser = function () { |
| ChromeBrowser.apply(this, arguments) |
| |
| var checkedFlag = '--checked' |
| var dartFlags = process.env.DART_FLAGS || '' |
| var flags = dartFlags.split(' ') |
| if (flags.indexOf(checkedFlag) === -1) { |
| flags.push(checkedFlag) |
| process.env.DART_FLAGS = flags.join(' ') |
| } |
| } |
| |
| DartiumBrowser.prototype = { |
| name: 'Dartium', |
| DEFAULT_CMD: {}, |
| ENV_CMD: 'DARTIUM_BIN' |
| } |
| |
| DartiumBrowser.$inject = ['baseBrowserDecorator', 'args'] |
| |
| // PUBLISH DI MODULE |
| module.exports = { |
| 'launcher:Chrome': ['type', ChromeBrowser], |
| 'launcher:ChromeHeadless': ['type', ChromeHeadlessBrowser], |
| 'launcher:ChromeCanary': ['type', ChromeCanaryBrowser], |
| 'launcher:ChromeCanaryHeadless': ['type', ChromeCanaryHeadlessBrowser], |
| 'launcher:Chromium': ['type', ChromiumBrowser], |
| 'launcher:ChromiumHeadless': ['type', ChromiumHeadlessBrowser], |
| 'launcher:Dartium': ['type', DartiumBrowser] |
| } |
| |
| module.exports.test = { |
| isJSFlags: isJSFlags, |
| sanitizeJSFlags: sanitizeJSFlags, |
| headlessGetOptions: headlessGetOptions, |
| canaryGetOptions: canaryGetOptions |
| } |