feat(launcher): allow options to be passed into puppeteer.defaultArgs (#2950)

This commit is contained in:
Joel Einbinder
2018-08-07 13:22:04 -07:00
committed by Andrey Lushnikov
parent 2e0007669d
commit 6825088644
5 changed files with 85 additions and 70 deletions

View File

@@ -48,9 +48,6 @@ const DEFAULT_ARGS = [
'--metrics-recording-only',
'--no-first-run',
'--safebrowsing-disable-auto-update',
];
const AUTOMATION_ARGS = [
'--enable-automation',
'--password-store=basic',
'--use-mock-keychain',
@@ -58,52 +55,43 @@ const AUTOMATION_ARGS = [
class Launcher {
/**
* @param {!(LaunchOptions & BrowserOptions)=} options
* @param {!(LaunchOptions & ChromeArgOptions & BrowserOptions)=} options
* @return {!Promise<!Browser>}
*/
static async launch(options) {
options = Object.assign({}, options || {});
static async launch(options = {}) {
const {
ignoreDefaultArgs = false,
args = [],
dumpio = false,
executablePath = null,
pipe = false,
env = process.env,
handleSIGINT = true,
handleSIGTERM = true,
handleSIGHUP = true,
ignoreHTTPSErrors = false,
defaultViewport = {width: 800, height: 600},
slowMo = 0,
timeout = 30000
} = options;
const chromeArguments = !ignoreDefaultArgs ? this.defaultArgs(options) : args;
let temporaryUserDataDir = null;
const chromeArguments = [];
if (!options.ignoreDefaultArgs)
chromeArguments.push(...DEFAULT_ARGS);
if (!options.ignoreDefaultArgs)
chromeArguments.push(...AUTOMATION_ARGS);
if (!options.ignoreDefaultArgs || !chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))
chromeArguments.push(options.pipe ? '--remote-debugging-pipe' : '--remote-debugging-port=0');
if (!options.args || !options.args.some(arg => arg.startsWith('--user-data-dir'))) {
if (!options.userDataDir)
temporaryUserDataDir = await mkdtempAsync(CHROME_PROFILE_PATH);
chromeArguments.push(`--user-data-dir=${options.userDataDir || temporaryUserDataDir}`);
if (!chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))
chromeArguments.push(pipe ? '--remote-debugging-pipe' : '--remote-debugging-port=0');
if (!chromeArguments.some(arg => arg.startsWith('--user-data-dir'))) {
temporaryUserDataDir = await mkdtempAsync(CHROME_PROFILE_PATH);
chromeArguments.push(`--user-data-dir=${temporaryUserDataDir}`);
}
if (options.devtools === true) {
chromeArguments.push('--auto-open-devtools-for-tabs');
options.headless = false;
}
if (typeof options.headless !== 'boolean' || options.headless) {
chromeArguments.push(
'--headless',
'--hide-scrollbars',
'--mute-audio'
);
if (os.platform() === 'win32')
chromeArguments.push('--disable-gpu');
}
if (Array.isArray(options.args) && options.args.every(arg => arg.startsWith('-')))
chromeArguments.push('about:blank');
let chromeExecutable = options.executablePath;
if (typeof chromeExecutable !== 'string') {
let chromeExecutable = executablePath;
if (!executablePath) {
const browserFetcher = new BrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
assert(revisionInfo.local, `Chromium revision is not downloaded. Run "npm install" or "yarn install"`);
chromeExecutable = revisionInfo.executablePath;
}
if (Array.isArray(options.args))
chromeArguments.push(...options.args);
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
const stdio = usePipe ? ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'] : ['pipe', 'pipe', 'pipe'];
@@ -115,12 +103,12 @@ class Launcher {
// process group, making it possible to kill child process tree with `.kill(-pid)` command.
// @see https://nodejs.org/api/child_process.html#child_process_options_detached
detached: process.platform !== 'win32',
env: options.env || process.env,
env,
stdio
}
);
if (options.dumpio) {
if (dumpio) {
chromeProcess.stderr.pipe(process.stderr);
chromeProcess.stdout.pipe(process.stdout);
}
@@ -141,22 +129,16 @@ class Launcher {
});
const listeners = [ helper.addEventListener(process, 'exit', killChrome) ];
if (options.handleSIGINT !== false)
if (handleSIGINT)
listeners.push(helper.addEventListener(process, 'SIGINT', () => { killChrome(); process.exit(130); }));
if (options.handleSIGTERM !== false)
if (handleSIGTERM)
listeners.push(helper.addEventListener(process, 'SIGTERM', gracefullyCloseChrome));
if (options.handleSIGHUP !== false)
if (handleSIGHUP)
listeners.push(helper.addEventListener(process, 'SIGHUP', gracefullyCloseChrome));
/** @type {?Connection} */
let connection = null;
try {
const {
ignoreHTTPSErrors = false,
defaultViewport = {width: 800, height: 600},
slowMo = 0
} = options;
if (!usePipe) {
const timeout = helper.isNumber(options.timeout) ? options.timeout : 30000;
const browserWSEndpoint = await waitForWSEndpoint(chromeProcess, timeout);
connection = await Connection.createForWebSocket(browserWSEndpoint, slowMo);
} else {
@@ -228,10 +210,34 @@ class Launcher {
}
/**
* @param {!ChromeArgOptions=} options
* @return {!Array<string>}
*/
static defaultArgs() {
return DEFAULT_ARGS.concat(AUTOMATION_ARGS);
static defaultArgs(options = {}) {
const {
devtools = false,
headless = !devtools,
args = [],
userDataDir = null
} = options;
const chromeArguments = [...DEFAULT_ARGS];
if (userDataDir)
chromeArguments.push(`--user-data-dir=${userDataDir}`);
if (devtools)
chromeArguments.push('--auto-open-devtools-for-tabs');
if (headless) {
chromeArguments.push(
'--headless',
'--hide-scrollbars',
'--mute-audio'
);
if (os.platform() === 'win32')
chromeArguments.push('--disable-gpu');
}
if (args.every(arg => arg.startsWith('-')))
chromeArguments.push('about:blank');
chromeArguments.push(...args);
return chromeArguments;
}
/**
@@ -317,19 +323,23 @@ function waitForWSEndpoint(chromeProcess, timeout) {
}
/**
* @typedef {Object} LaunchOptions
* @typedef {Object} ChromeArgOptions
* @property {boolean=} headless
* @property {Array<string>=} args
* @property {string=} userDataDir
* @property {boolean=} devtools
*/
/**
* @typedef {Object} LaunchOptions
* @property {string=} executablePath
* @property {!Array<string>=} args
* @property {boolean=} ignoreDefaultArgs
* @property {boolean=} handleSIGINT
* @property {boolean=} handleSIGTERM
* @property {boolean=} handleSIGHUP
* @property {number=} timeout
* @property {boolean=} dumpio
* @property {string=} userDataDir
* @property {!Object<string, string | undefined>=} env
* @property {boolean=} devtools
* @property {boolean=} pipe
*/