feat(firefox): allow passing user prefs at launch time (#2417)

This commit is contained in:
Pavel Feldman 2020-05-31 09:28:57 -07:00 committed by GitHub
parent 3cad857644
commit c001facffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 5 deletions

View File

@ -3997,6 +3997,7 @@ This methods attaches Playwright to an existing browser instance.
- `executablePath` <[string]> Path to a browser executable to run instead of the bundled one. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). Note that Playwright only works with the bundled Chromium, Firefox or WebKit, use at your own risk.
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
- `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, Playwright does not pass its own configurations args and only uses the ones from `args`. If an array is given, then filters out the given default arguments. Dangerous option; use with care. Defaults to `false`.
- `firefoxUserPrefs` <[Object]> Firefox user preferences. Learn more about the Firefox user preferences at [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
@ -4072,6 +4073,7 @@ Launches browser that uses persistent storage located at `userDataDir` and retur
- `executablePath` <[string]> Path to a browser executable to run instead of the bundled one. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Playwright is only guaranteed to work with the bundled Chromium, Firefox or WebKit, use at your own risk.
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
- `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, then do not use any of the default arguments. If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
- `firefoxUserPrefs` <[Object]> Firefox user preferences. Learn more about the Firefox user preferences at [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.

View File

@ -36,6 +36,10 @@ export type BrowserArgOptions = {
devtools?: boolean,
};
export type FirefoxUserPrefsOptions = {
firefoxUserPrefs?: { [key: string]: string | number | boolean },
};
type LaunchOptionsBase = BrowserArgOptions & {
executablePath?: string,
ignoreDefaultArgs?: boolean | string[],
@ -64,8 +68,8 @@ type LaunchServerOptions = LaunchOptionsBase & { port?: number };
export interface BrowserType {
executablePath(): string;
name(): string;
launch(options?: LaunchOptions): Promise<Browser>;
launchServer(options?: LaunchServerOptions): Promise<BrowserServer>;
launch(options?: LaunchOptions & FirefoxUserPrefsOptions): Promise<Browser>;
launchServer(options?: LaunchServerOptions & FirefoxUserPrefsOptions): Promise<BrowserServer>;
launchPersistentContext(userDataDir: string, options?: LaunchOptions & PersistentContextOptions): Promise<BrowserContext>;
connect(options: ConnectOptions): Promise<Browser>;
}

View File

@ -16,13 +16,14 @@
*/
import * as os from 'os';
import * as fs from 'fs';
import * as path from 'path';
import * as ws from 'ws';
import { FFBrowser } from '../firefox/ffBrowser';
import { kBrowserCloseMessageId } from '../firefox/ffConnection';
import { helper } from '../helper';
import { WebSocketWrapper } from './browserServer';
import { BrowserArgOptions, BrowserTypeBase, processBrowserArgOptions } from './browserType';
import { BrowserArgOptions, BrowserTypeBase, processBrowserArgOptions, FirefoxUserPrefsOptions } from './browserType';
import { Env } from './processLauncher';
import { ConnectionTransport, SequenceNumberMixer } from '../transport';
import { InnerLogger, logError } from '../logger';
@ -56,7 +57,7 @@ export class Firefox extends BrowserTypeBase {
return wrapTransportWithWebSocket(transport, logger, port);
}
_defaultArgs(options: BrowserArgOptions, isPersistent: boolean, userDataDir: string): string[] {
_defaultArgs(options: BrowserArgOptions & FirefoxUserPrefsOptions, isPersistent: boolean, userDataDir: string): string[] {
const { devtools, headless } = processBrowserArgOptions(options);
const { args = [] } = options;
if (devtools)
@ -66,7 +67,12 @@ export class Firefox extends BrowserTypeBase {
throw new Error('Pass userDataDir parameter instead of specifying -profile argument');
if (args.find(arg => arg.startsWith('-juggler')))
throw new Error('Use the port parameter instead of -juggler argument');
if (options.firefoxUserPrefs) {
const lines: string[] = [];
for (const [name, value] of Object.entries(options.firefoxUserPrefs))
lines.push(`user_pref(${JSON.stringify(name)}, ${JSON.stringify(value)});`);
fs.writeFileSync(path.join(userDataDir, 'user.js'), lines.join('\n'));
}
const firefoxArguments = ['-no-remote'];
if (headless) {
firefoxArguments.push('-headless');

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const path = require('path');
const utils = require('../utils');
const {makeUserDataDir, removeUserDataDir} = utils;
const {FFOX, CHROMIUM, WEBKIT, WIN} = utils.testOptions(browserType);
describe('launcher', function() {
it('should pass firefox user preferences', async({browserType, defaultBrowserOptions}) => {
const browser = await browserType.launch({
...defaultBrowserOptions,
firefoxUserPrefs: {
'network.proxy.type': 1,
'network.proxy.http': '127.0.0.1',
'network.proxy.http_port': 3333,
}
});
const page = await browser.newPage();
const error = await page.goto('http://example.com').catch(e => e);
expect(error.message).toContain('NS_ERROR_PROXY_CONNECTION_REFUSED');
await browser.close();
});
});

View File

@ -243,6 +243,15 @@ module.exports = {
environments: [customEnvironment],
},
{
files: [
'./firefox/launcher.spec.js',
],
browsers: ['firefox'],
title: '[Firefox]',
environments: [customEnvironment],
},
{
files: [
'./electron/electron.spec.js',