UNPKG

9.76 kBJavaScriptView Raw
1var fs = require('fs')
2var path = require('path')
3var which = require('which')
4
5function isJSFlags (flag) {
6 return flag.indexOf('--js-flags=') === 0
7}
8
9function sanitizeJSFlags (flag) {
10 var test = /--js-flags=(['"])/.exec(flag)
11 if (!test) {
12 return flag
13 }
14 var escapeChar = test[1]
15 var endExp = new RegExp(escapeChar + '$')
16 var startExp = new RegExp('--js-flags=' + escapeChar)
17 return flag.replace(startExp, '--js-flags=').replace(endExp, '')
18}
19
20var ChromeBrowser = function (baseBrowserDecorator, args) {
21 baseBrowserDecorator(this)
22
23 var flags = args.flags || []
24 var userDataDir = args.chromeDataDir || this._tempDir
25
26 this._getOptions = function (url) {
27 // Chrome CLI options
28 // http://peter.sh/experiments/chromium-command-line-switches/
29 flags.forEach(function (flag, i) {
30 if (isJSFlags(flag)) {
31 flags[i] = sanitizeJSFlags(flag)
32 }
33 })
34
35 return [
36 '--user-data-dir=' + userDataDir,
37 // https://github.com/GoogleChrome/chrome-launcher/blob/master/docs/chrome-flags-for-tools.md#--enable-automation
38 '--enable-automation',
39 '--no-default-browser-check',
40 '--no-first-run',
41 '--disable-default-apps',
42 '--disable-popup-blocking',
43 '--disable-translate',
44 '--disable-background-timer-throttling',
45 // on macOS, disable-background-timer-throttling is not enough
46 // and we need disable-renderer-backgrounding too
47 // see https://github.com/karma-runner/karma-chrome-launcher/issues/123
48 '--disable-renderer-backgrounding',
49 '--disable-device-discovery-notifications'
50 ].concat(flags, [url])
51 }
52}
53
54// Return location of chrome.exe file for a given Chrome directory (available: "Chrome", "Chrome SxS").
55function getChromeExe (chromeDirName) {
56 // Only run these checks on win32
57 if (process.platform !== 'win32') {
58 return null
59 }
60 var windowsChromeDirectory, i, prefix
61 var suffix = '\\Google\\' + chromeDirName + '\\Application\\chrome.exe'
62 var prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']]
63
64 for (i = 0; i < prefixes.length; i++) {
65 prefix = prefixes[i]
66 try {
67 windowsChromeDirectory = path.join(prefix, suffix)
68 fs.accessSync(windowsChromeDirectory)
69 return windowsChromeDirectory
70 } catch (e) {}
71 }
72
73 return windowsChromeDirectory
74}
75
76var ChromiumBrowser = function (baseBrowserDecorator, args) {
77 baseBrowserDecorator(this)
78
79 var flags = args.flags || []
80 var userDataDir = args.chromeDataDir || this._tempDir
81
82 this._getOptions = function (url) {
83 // Chromium CLI options
84 // http://peter.sh/experiments/chromium-command-line-switches/
85 flags.forEach(function (flag, i) {
86 if (isJSFlags(flag)) {
87 flags[i] = sanitizeJSFlags(flag)
88 }
89 })
90
91 return [
92 '--user-data-dir=' + userDataDir,
93 '--no-default-browser-check',
94 '--no-first-run',
95 '--disable-default-apps',
96 '--disable-popup-blocking',
97 '--disable-translate',
98 '--disable-background-timer-throttling'
99 ].concat(flags, [url])
100 }
101}
102
103// Return location of Chromium's chrome.exe file.
104function getChromiumExe (chromeDirName) {
105 // Only run these checks on win32
106 if (process.platform !== 'win32') {
107 return null
108 }
109 var windowsChromiumDirectory, i, prefix
110 var suffix = '\\Chromium\\Application\\chrome.exe'
111 var prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']]
112
113 for (i = 0; i < prefixes.length; i++) {
114 prefix = prefixes[i]
115 try {
116 windowsChromiumDirectory = path.join(prefix, suffix)
117 fs.accessSync(windowsChromiumDirectory)
118 return windowsChromiumDirectory
119 } catch (e) {}
120 }
121
122 return windowsChromiumDirectory
123}
124
125function getBin (commands) {
126 // Don't run these checks on win32
127 if (process.platform !== 'linux') {
128 return null
129 }
130 var bin, i
131 for (i = 0; i < commands.length; i++) {
132 try {
133 if (which.sync(commands[i])) {
134 bin = commands[i]
135 break
136 }
137 } catch (e) {}
138 }
139 return bin
140}
141
142function getChromeDarwin (defaultPath) {
143 if (process.platform !== 'darwin') {
144 return null
145 }
146
147 try {
148 var homePath = path.join(process.env.HOME, defaultPath)
149 fs.accessSync(homePath)
150 return homePath
151 } catch (e) {
152 return defaultPath
153 }
154}
155
156ChromeBrowser.prototype = {
157 name: 'Chrome',
158
159 DEFAULT_CMD: {
160 linux: getBin(['google-chrome', 'google-chrome-stable']),
161 darwin: getChromeDarwin('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'),
162 win32: getChromeExe('Chrome')
163 },
164 ENV_CMD: 'CHROME_BIN'
165}
166
167ChromeBrowser.$inject = ['baseBrowserDecorator', 'args']
168
169function headlessGetOptions (url, args, parent) {
170 var mergedArgs = parent.call(this, url, args).concat([
171 '--headless',
172 '--disable-gpu',
173 '--disable-dev-shm-usage'
174 ])
175
176 var isRemoteDebuggingFlag = function (flag) {
177 return flag.indexOf('--remote-debugging-port=') !== -1
178 }
179
180 return mergedArgs.some(isRemoteDebuggingFlag)
181 ? mergedArgs
182 : mergedArgs.concat(['--remote-debugging-port=9222'])
183}
184
185var ChromeHeadlessBrowser = function (baseBrowserDecorator, args) {
186 ChromeBrowser.apply(this, arguments)
187
188 var parentOptions = this._getOptions
189 this._getOptions = function (url) {
190 return headlessGetOptions.call(this, url, args, parentOptions)
191 }
192}
193
194ChromeHeadlessBrowser.prototype = {
195 name: 'ChromeHeadless',
196
197 DEFAULT_CMD: {
198 linux: getBin(['google-chrome', 'google-chrome-stable']),
199 darwin: getChromeDarwin('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'),
200 win32: getChromeExe('Chrome')
201 },
202 ENV_CMD: 'CHROME_BIN'
203}
204
205ChromeHeadlessBrowser.$inject = ['baseBrowserDecorator', 'args']
206
207function canaryGetOptions (url, args, parent) {
208 // disable crankshaft optimizations, as it causes lot of memory leaks (as of Chrome 23.0)
209 var flags = args.flags || []
210 var augmentedFlags
211 var customFlags = '--nocrankshaft --noopt'
212
213 flags.forEach(function (flag) {
214 if (isJSFlags(flag)) {
215 augmentedFlags = sanitizeJSFlags(flag) + ' ' + customFlags
216 }
217 })
218
219 return parent.call(this, url).concat([augmentedFlags || '--js-flags=' + customFlags])
220}
221
222var ChromeCanaryBrowser = function (baseBrowserDecorator, args) {
223 ChromeBrowser.apply(this, arguments)
224
225 var parentOptions = this._getOptions
226 this._getOptions = function (url) {
227 return canaryGetOptions.call(this, url, args, parentOptions)
228 }
229}
230
231ChromeCanaryBrowser.prototype = {
232 name: 'ChromeCanary',
233
234 DEFAULT_CMD: {
235 linux: getBin(['google-chrome-canary', 'google-chrome-unstable']),
236 darwin: getChromeDarwin('/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'),
237 win32: getChromeExe('Chrome SxS')
238 },
239 ENV_CMD: 'CHROME_CANARY_BIN'
240}
241
242ChromeCanaryBrowser.$inject = ['baseBrowserDecorator', 'args']
243
244var ChromeCanaryHeadlessBrowser = function (baseBrowserDecorator, args) {
245 ChromeCanaryBrowser.apply(this, arguments)
246
247 var parentOptions = this._getOptions
248 this._getOptions = function (url) {
249 return headlessGetOptions.call(this, url, args, parentOptions)
250 }
251}
252
253ChromeCanaryHeadlessBrowser.prototype = {
254 name: 'ChromeCanaryHeadless',
255
256 DEFAULT_CMD: {
257 linux: getBin(['google-chrome-canary', 'google-chrome-unstable']),
258 darwin: getChromeDarwin('/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'),
259 win32: getChromeExe('Chrome SxS')
260 },
261 ENV_CMD: 'CHROME_CANARY_BIN'
262}
263
264ChromeCanaryHeadlessBrowser.$inject = ['baseBrowserDecorator', 'args']
265
266ChromiumBrowser.prototype = {
267 name: 'Chromium',
268
269 DEFAULT_CMD: {
270 // Try chromium-browser before chromium to avoid conflict with the legacy
271 // chromium-bsu package previously known as 'chromium' in Debian and Ubuntu.
272 linux: getBin(['chromium-browser', 'chromium']),
273 darwin: '/Applications/Chromium.app/Contents/MacOS/Chromium',
274 win32: getChromiumExe()
275 },
276 ENV_CMD: 'CHROMIUM_BIN'
277}
278
279ChromiumBrowser.$inject = ['baseBrowserDecorator', 'args']
280
281var ChromiumHeadlessBrowser = function (baseBrowserDecorator, args) {
282 ChromiumBrowser.apply(this, arguments)
283
284 var parentOptions = this._getOptions
285 this._getOptions = function (url) {
286 return headlessGetOptions.call(this, url, args, parentOptions)
287 }
288}
289
290ChromiumHeadlessBrowser.prototype = {
291 name: 'ChromiumHeadless',
292
293 DEFAULT_CMD: {
294 // Try chromium-browser before chromium to avoid conflict with the legacy
295 // chromium-bsu package previously known as 'chromium' in Debian and Ubuntu.
296 linux: getBin(['chromium-browser', 'chromium']),
297 darwin: '/Applications/Chromium.app/Contents/MacOS/Chromium',
298 win32: getChromiumExe()
299 },
300 ENV_CMD: 'CHROMIUM_BIN'
301}
302
303var DartiumBrowser = function () {
304 ChromeBrowser.apply(this, arguments)
305
306 var checkedFlag = '--checked'
307 var dartFlags = process.env.DART_FLAGS || ''
308 var flags = dartFlags.split(' ')
309 if (flags.indexOf(checkedFlag) === -1) {
310 flags.push(checkedFlag)
311 process.env.DART_FLAGS = flags.join(' ')
312 }
313}
314
315DartiumBrowser.prototype = {
316 name: 'Dartium',
317 DEFAULT_CMD: {},
318 ENV_CMD: 'DARTIUM_BIN'
319}
320
321DartiumBrowser.$inject = ['baseBrowserDecorator', 'args']
322
323// PUBLISH DI MODULE
324module.exports = {
325 'launcher:Chrome': ['type', ChromeBrowser],
326 'launcher:ChromeHeadless': ['type', ChromeHeadlessBrowser],
327 'launcher:ChromeCanary': ['type', ChromeCanaryBrowser],
328 'launcher:ChromeCanaryHeadless': ['type', ChromeCanaryHeadlessBrowser],
329 'launcher:Chromium': ['type', ChromiumBrowser],
330 'launcher:ChromiumHeadless': ['type', ChromiumHeadlessBrowser],
331 'launcher:Dartium': ['type', DartiumBrowser]
332}
333
334module.exports.test = {
335 isJSFlags: isJSFlags,
336 sanitizeJSFlags: sanitizeJSFlags,
337 headlessGetOptions: headlessGetOptions,
338 canaryGetOptions: canaryGetOptions
339}