chore: align more server-side options with rpc protocol (#3506)
This touches: - noDefaultViewport; - ignoreAllDefaultArgs; - env; - validateXYZ logic that was copying objects - we do not need that anymore; - shuffles some converters closer to their usage.
This commit is contained in:
parent
7a77faf194
commit
9790ea5b5d
|
|
@ -40,12 +40,10 @@ export type BrowserOptions = {
|
|||
proxy?: ProxySettings,
|
||||
};
|
||||
|
||||
export type BrowserContextOptions = types.BrowserContextOptions;
|
||||
|
||||
export interface Browser extends EventEmitter {
|
||||
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
||||
newContext(options?: types.BrowserContextOptions): Promise<BrowserContext>;
|
||||
contexts(): BrowserContext[];
|
||||
newPage(options?: BrowserContextOptions): Promise<Page>;
|
||||
newPage(options?: types.BrowserContextOptions): Promise<Page>;
|
||||
isConnected(): boolean;
|
||||
close(): Promise<void>;
|
||||
version(): string;
|
||||
|
|
@ -62,12 +60,12 @@ export abstract class BrowserBase extends EventEmitter implements Browser {
|
|||
this._options = options;
|
||||
}
|
||||
|
||||
abstract newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
||||
abstract newContext(options?: types.BrowserContextOptions): Promise<BrowserContext>;
|
||||
abstract contexts(): BrowserContext[];
|
||||
abstract isConnected(): boolean;
|
||||
abstract version(): string;
|
||||
|
||||
async newPage(options?: BrowserContextOptions): Promise<Page> {
|
||||
async newPage(options?: types.BrowserContextOptions): Promise<Page> {
|
||||
const context = await this.newContext(options);
|
||||
const page = await context.newPage();
|
||||
page._ownedContext = context;
|
||||
|
|
|
|||
|
|
@ -228,47 +228,23 @@ export function assertBrowserContextIsNotOwned(context: BrowserContextBase) {
|
|||
}
|
||||
}
|
||||
|
||||
export function validateBrowserContextOptions(options: types.BrowserContextOptions): types.BrowserContextOptions {
|
||||
// Copy all fields manually to strip any extra junk.
|
||||
// Especially useful when we share context and launch options for launchPersistent.
|
||||
const result: types.BrowserContextOptions = {
|
||||
ignoreHTTPSErrors: options.ignoreHTTPSErrors,
|
||||
bypassCSP: options.bypassCSP,
|
||||
locale: options.locale,
|
||||
timezoneId: options.timezoneId,
|
||||
offline: options.offline,
|
||||
colorScheme: options.colorScheme,
|
||||
acceptDownloads: options.acceptDownloads,
|
||||
viewport: options.viewport,
|
||||
javaScriptEnabled: options.javaScriptEnabled,
|
||||
userAgent: options.userAgent,
|
||||
geolocation: options.geolocation,
|
||||
permissions: options.permissions,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders,
|
||||
httpCredentials: options.httpCredentials,
|
||||
deviceScaleFactor: options.deviceScaleFactor,
|
||||
isMobile: options.isMobile,
|
||||
hasTouch: options.hasTouch,
|
||||
};
|
||||
if (result.viewport === null && result.deviceScaleFactor !== undefined)
|
||||
export function validateBrowserContextOptions(options: types.BrowserContextOptions) {
|
||||
if (options.noDefaultViewport && options.deviceScaleFactor !== undefined)
|
||||
throw new Error(`"deviceScaleFactor" option is not supported with null "viewport"`);
|
||||
if (result.viewport === null && result.isMobile !== undefined)
|
||||
if (options.noDefaultViewport && options.isMobile !== undefined)
|
||||
throw new Error(`"isMobile" option is not supported with null "viewport"`);
|
||||
if (!result.viewport && result.viewport !== null)
|
||||
result.viewport = { width: 1280, height: 720 };
|
||||
if (result.viewport)
|
||||
result.viewport = { ...result.viewport };
|
||||
if (result.geolocation)
|
||||
result.geolocation = verifyGeolocation(result.geolocation);
|
||||
if (result.extraHTTPHeaders)
|
||||
result.extraHTTPHeaders = network.verifyHeaders(result.extraHTTPHeaders);
|
||||
return result;
|
||||
if (!options.viewport && !options.noDefaultViewport)
|
||||
options.viewport = { width: 1280, height: 720 };
|
||||
verifyGeolocation(options.geolocation);
|
||||
if (options.extraHTTPHeaders)
|
||||
options.extraHTTPHeaders = network.verifyHeaders(options.extraHTTPHeaders);
|
||||
}
|
||||
|
||||
export function verifyGeolocation(geolocation: types.Geolocation): types.Geolocation {
|
||||
const result = { ...geolocation };
|
||||
result.accuracy = result.accuracy || 0;
|
||||
const { longitude, latitude, accuracy } = result;
|
||||
export function verifyGeolocation(geolocation?: types.Geolocation) {
|
||||
if (!geolocation)
|
||||
return;
|
||||
geolocation.accuracy = geolocation.accuracy || 0;
|
||||
const { longitude, latitude, accuracy } = geolocation;
|
||||
if (!helper.isNumber(longitude))
|
||||
throw new Error(`geolocation.longitude: expected number, got ${typeof longitude}`);
|
||||
if (longitude < -180 || longitude > 180)
|
||||
|
|
@ -281,7 +257,6 @@ export function verifyGeolocation(geolocation: types.Geolocation): types.Geoloca
|
|||
throw new Error(`geolocation.accuracy: expected number, got ${typeof accuracy}`);
|
||||
if (accuracy < 0)
|
||||
throw new Error(`geolocation.accuracy: precondition 0 <= ACCURACY failed.`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function verifyProxySettings(proxy: types.ProxySettings): types.ProxySettings {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BrowserBase, BrowserOptions, BrowserContextOptions } from '../browser';
|
||||
import { BrowserBase, BrowserOptions } from '../browser';
|
||||
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
|
||||
import { Events as CommonEvents } from '../events';
|
||||
import { assert } from '../helper';
|
||||
|
|
@ -99,8 +99,8 @@ export class CRBrowser extends BrowserBase {
|
|||
this._session.on('Target.detachedFromTarget', this._onDetachedFromTarget.bind(this));
|
||||
}
|
||||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
options = validateBrowserContextOptions(options);
|
||||
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
validateBrowserContextOptions(options);
|
||||
const { browserContextId } = await this._session.send('Target.createBrowserContext', { disposeOnDetach: true });
|
||||
const context = new CRBrowserContext(this, browserContextId, options);
|
||||
await context._initialize();
|
||||
|
|
@ -381,8 +381,7 @@ export class CRBrowserContext extends BrowserContextBase {
|
|||
}
|
||||
|
||||
async setGeolocation(geolocation?: types.Geolocation): Promise<void> {
|
||||
if (geolocation)
|
||||
geolocation = verifyGeolocation(geolocation);
|
||||
verifyGeolocation(geolocation);
|
||||
this._options.geolocation = geolocation;
|
||||
for (const page of this.pages())
|
||||
await (page._delegate as CRPage).updateGeolocation();
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export class CRPage implements PageDelegate {
|
|||
this._mainFrameSession = new FrameSession(this, client, targetId, null);
|
||||
this._sessions.set(targetId, this._mainFrameSession);
|
||||
client.once(CRSessionEvents.Disconnected, () => this._page._didDisconnect());
|
||||
if (opener && browserContext._options.viewport !== null) {
|
||||
if (opener && !browserContext._options.noDefaultViewport) {
|
||||
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
|
||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
|
||||
if (viewportSize)
|
||||
|
|
@ -371,7 +371,7 @@ class FrameSession {
|
|||
}
|
||||
|
||||
async _initialize(hasUIWindow: boolean) {
|
||||
if (hasUIWindow && this._crPage._browserContext._options.viewport !== null) {
|
||||
if (hasUIWindow && !this._crPage._browserContext._options.noDefaultViewport) {
|
||||
const { windowId } = await this._client.send('Browser.getWindowForTarget');
|
||||
this._windowId = windowId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,19 +105,3 @@ export function headersArrayToObject(headers: types.HeadersArray): types.Headers
|
|||
result[name] = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function envObjectToArray(env: types.Env): types.EnvArray {
|
||||
const result: types.EnvArray = [];
|
||||
for (const name in env) {
|
||||
if (!Object.is(env[name], undefined))
|
||||
result.push({ name, value: String(env[name]) });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function envArrayToObject(env: types.EnvArray): types.Env {
|
||||
const result: types.Env = {};
|
||||
for (const { name, value } of env)
|
||||
result[name] = value;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BrowserBase, BrowserOptions, BrowserContextOptions } from '../browser';
|
||||
import { BrowserBase, BrowserOptions } from '../browser';
|
||||
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
|
||||
import { Events } from '../events';
|
||||
import { assert, helper, RegisteredListener } from '../helper';
|
||||
|
|
@ -91,8 +91,8 @@ export class FFBrowser extends BrowserBase {
|
|||
return !this._connection._closed;
|
||||
}
|
||||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
options = validateBrowserContextOptions(options);
|
||||
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
validateBrowserContextOptions(options);
|
||||
if (options.isMobile)
|
||||
throw new Error('options.isMobile is not supported in Firefox');
|
||||
const { browserContextId } = await this._connection.send('Browser.createBrowserContext', { removeOnDetach: true });
|
||||
|
|
@ -289,8 +289,7 @@ export class FFBrowserContext extends BrowserContextBase {
|
|||
}
|
||||
|
||||
async setGeolocation(geolocation?: types.Geolocation): Promise<void> {
|
||||
if (geolocation)
|
||||
geolocation = verifyGeolocation(geolocation);
|
||||
verifyGeolocation(geolocation);
|
||||
this._options.geolocation = geolocation;
|
||||
await this._browser._connection.send('Browser.setGeolocationOverride', { browserContextId: this._browserContextId || undefined, geolocation: geolocation || null });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ export class Page extends EventEmitter {
|
|||
this._crashedPromise = new Promise(f => this._crashedCallback = f);
|
||||
this._browserContext = browserContext;
|
||||
this._state = {
|
||||
viewportSize: browserContext._options.viewport ? { ...browserContext._options.viewport } : null,
|
||||
viewportSize: browserContext._options.viewport || null,
|
||||
mediaType: null,
|
||||
colorScheme: null,
|
||||
extraHTTPHeaders: null,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { BrowserDispatcher } from './server/browserDispatcher';
|
|||
import { BrowserContextDispatcher } from './server/browserContextDispatcher';
|
||||
import { BrowserNewContextParams, BrowserContextChannel } from './channels';
|
||||
import { BrowserServerLauncher, BrowserServer } from './client/browserType';
|
||||
import { envObjectToArray } from './client/clientHelper';
|
||||
|
||||
export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
||||
private _browserType: BrowserTypeBase;
|
||||
|
|
@ -36,7 +37,12 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
|||
}
|
||||
|
||||
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServerImpl> {
|
||||
const browser = await this._browserType.launch(options);
|
||||
const browser = await this._browserType.launch({
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
});
|
||||
return new BrowserServerImpl(this._browserType, browser as BrowserBase, options.port);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { BrowserTypeChannel, BrowserTypeInitializer, BrowserTypeLaunchParams, Br
|
|||
import { Browser } from './browser';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { headersObjectToArray, envObjectToArray } from '../../converters';
|
||||
import { headersObjectToArray } from '../../converters';
|
||||
import { assert, helper } from '../../helper';
|
||||
import { LaunchOptions, LaunchServerOptions, ConnectOptions, LaunchPersistentContextOptions } from './types';
|
||||
import * as WebSocket from 'ws';
|
||||
|
|
@ -27,6 +27,7 @@ import { serializeError } from '../serializers';
|
|||
import { Events } from './events';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { envObjectToArray } from './clientHelper';
|
||||
|
||||
export interface BrowserServerLauncher {
|
||||
launchServer(options?: LaunchServerOptions): Promise<BrowserServer>;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
import { isUnderTest as commonIsUnderTest } from '../../helper';
|
||||
import * as types from './types';
|
||||
|
||||
const deprecatedHits = new Set();
|
||||
export function deprecate(methodName: string, message: string) {
|
||||
|
|
@ -28,3 +29,12 @@ export function deprecate(methodName: string, message: string) {
|
|||
export function isUnderTest() {
|
||||
return commonIsUnderTest();
|
||||
}
|
||||
|
||||
export function envObjectToArray(env: types.Env): { name: string, value: string }[] {
|
||||
const result: { name: string, value: string }[] = [];
|
||||
for (const name in env) {
|
||||
if (!Object.is(env[name], undefined))
|
||||
result.push({ name, value: String(env[name]) });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from '.
|
|||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import { Events } from './events';
|
||||
import { envObjectToArray } from '../../converters';
|
||||
import { WaitForEventOptions, Env, LoggerSink } from './types';
|
||||
import { envObjectToArray } from './clientHelper';
|
||||
|
||||
type ElectronOptions = Omit<ElectronLaunchOptions, 'env'> & {
|
||||
env?: Env,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> i
|
|||
async newContext(params: BrowserNewContextParams): Promise<{ context: BrowserContextChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
viewport: params.viewport || (params.noDefaultViewport ? null : undefined),
|
||||
extraHTTPHeaders: params.extraHTTPHeaders ? headersArrayToObject(params.extraHTTPHeaders) : undefined,
|
||||
};
|
||||
return { context: new BrowserContextDispatcher(this._scope, await this._object.newContext(options) as BrowserContextBase) };
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeI
|
|||
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||
import { BrowserContextBase } from '../../browserContext';
|
||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||
import { headersArrayToObject, envArrayToObject } from '../../converters';
|
||||
import { headersArrayToObject } from '../../converters';
|
||||
|
||||
export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeInitializer> implements BrowserTypeChannel {
|
||||
constructor(scope: DispatcherScope, browserType: BrowserTypeBase) {
|
||||
|
|
@ -32,21 +32,13 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
|||
}
|
||||
|
||||
async launch(params: BrowserTypeLaunchParams): Promise<{ browser: BrowserChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
|
||||
env: params.env ? envArrayToObject(params.env) : undefined,
|
||||
};
|
||||
const browser = await this._object.launch(options);
|
||||
const browser = await this._object.launch(params);
|
||||
return { browser: new BrowserDispatcher(this._scope, browser as BrowserBase) };
|
||||
}
|
||||
|
||||
async launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams): Promise<{ context: BrowserContextChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
viewport: params.viewport || (params.noDefaultViewport ? null : undefined),
|
||||
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
|
||||
env: params.env ? envArrayToObject(params.env) : undefined,
|
||||
extraHTTPHeaders: params.extraHTTPHeaders ? headersArrayToObject(params.extraHTTPHeaders) : undefined,
|
||||
};
|
||||
const browserContext = await this._object.launchPersistentContext(params.userDataDir, options);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import { BrowserContextBase } from '../../browserContext';
|
|||
import { PageDispatcher } from './pageDispatcher';
|
||||
import { parseArgument, serializeResult } from './jsHandleDispatcher';
|
||||
import { createHandle } from './elementHandlerDispatcher';
|
||||
import { envArrayToObject } from '../../converters';
|
||||
|
||||
export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer> implements ElectronChannel {
|
||||
constructor(scope: DispatcherScope, electron: Electron) {
|
||||
|
|
@ -30,11 +29,7 @@ export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer
|
|||
}
|
||||
|
||||
async launch(params: ElectronLaunchParams): Promise<{ electronApplication: ElectronApplicationChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
env: params.env ? envArrayToObject(params.env) : undefined,
|
||||
};
|
||||
const electronApplication = await this._object.launch(params.executablePath, options);
|
||||
const electronApplication = await this._object.launch(params.executablePath, params);
|
||||
return { electronApplication: new ElectronApplicationDispatcher(this._scope, electronApplication) };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,24 +23,18 @@ import * as browserPaths from '../install/browserPaths';
|
|||
import { ConnectionTransport, WebSocketTransport } from '../transport';
|
||||
import { BrowserBase, BrowserOptions, Browser, BrowserProcess } from '../browser';
|
||||
import { assert, helper } from '../helper';
|
||||
import { launchProcess, Env, waitForLine } from './processLauncher';
|
||||
import { launchProcess, Env, waitForLine, envArrayToObject } from './processLauncher';
|
||||
import { PipeTransport } from './pipeTransport';
|
||||
import { Progress, runAbortableTask } from '../progress';
|
||||
import * as types from '../types';
|
||||
import { TimeoutSettings } from '../timeoutSettings';
|
||||
import { validateHostRequirements } from './validateDependencies';
|
||||
|
||||
type FirefoxPrefsOptions = { firefoxUserPrefs?: { [key: string]: string | number | boolean } };
|
||||
|
||||
export type LaunchNonPersistentOptions = types.LaunchOptions & FirefoxPrefsOptions;
|
||||
type LaunchPersistentOptions = types.LaunchOptions & types.BrowserContextOptions;
|
||||
type LaunchServerOptions = types.LaunchServerOptions & FirefoxPrefsOptions;
|
||||
|
||||
export interface BrowserType {
|
||||
executablePath(): string;
|
||||
name(): string;
|
||||
launch(options?: LaunchNonPersistentOptions): Promise<Browser>;
|
||||
launchPersistentContext(userDataDir: string, options?: LaunchPersistentOptions): Promise<BrowserContext>;
|
||||
launch(options?: types.LaunchOptions): Promise<Browser>;
|
||||
launchPersistentContext(userDataDir: string, options?: types.LaunchPersistentOptions): Promise<BrowserContext>;
|
||||
}
|
||||
|
||||
const mkdirAsync = util.promisify(fs.mkdir);
|
||||
|
|
@ -76,7 +70,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
|||
return this._name;
|
||||
}
|
||||
|
||||
async launch(options: LaunchNonPersistentOptions = {}): Promise<Browser> {
|
||||
async launch(options: types.LaunchOptions = {}): Promise<Browser> {
|
||||
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = validateLaunchOptions(options);
|
||||
|
|
@ -84,10 +78,11 @@ export abstract class BrowserTypeBase implements BrowserType {
|
|||
return browser;
|
||||
}
|
||||
|
||||
async launchPersistentContext(userDataDir: string, options: LaunchPersistentOptions = {}): Promise<BrowserContext> {
|
||||
async launchPersistentContext(userDataDir: string, options: types.LaunchPersistentOptions = {}): Promise<BrowserContext> {
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = validateLaunchOptions(options);
|
||||
const persistent = validateBrowserContextOptions(options);
|
||||
const persistent: types.BrowserContextOptions = options;
|
||||
validateBrowserContextOptions(persistent);
|
||||
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, persistent, userDataDir), TimeoutSettings.timeout(options), 'browser').catch(e => { throw this._rewriteStartupError(e); });
|
||||
return browser._defaultContext!;
|
||||
}
|
||||
|
|
@ -109,23 +104,24 @@ export abstract class BrowserTypeBase implements BrowserType {
|
|||
copyTestHooks(options, browserOptions);
|
||||
const browser = await this._connectToTransport(transport, browserOptions);
|
||||
// We assume no control when using custom arguments, and do not prepare the default context in that case.
|
||||
const hasCustomArguments = !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs);
|
||||
if (persistent && !hasCustomArguments)
|
||||
if (persistent && !options.ignoreAllDefaultArgs)
|
||||
await browser._defaultContext!._loadDefaultContext(progress);
|
||||
return browser;
|
||||
}
|
||||
|
||||
private async _launchProcess(progress: Progress, options: LaunchServerOptions, isPersistent: boolean, userDataDir?: string): Promise<{ browserProcess: BrowserProcess, downloadsPath: string, transport: ConnectionTransport }> {
|
||||
private async _launchProcess(progress: Progress, options: types.LaunchOptions, isPersistent: boolean, userDataDir?: string): Promise<{ browserProcess: BrowserProcess, downloadsPath: string, transport: ConnectionTransport }> {
|
||||
const {
|
||||
ignoreDefaultArgs = false,
|
||||
ignoreDefaultArgs,
|
||||
ignoreAllDefaultArgs,
|
||||
args = [],
|
||||
executablePath = null,
|
||||
env = process.env,
|
||||
handleSIGINT = true,
|
||||
handleSIGTERM = true,
|
||||
handleSIGHUP = true,
|
||||
} = options;
|
||||
|
||||
const env = options.env ? envArrayToObject(options.env) : process.env;
|
||||
|
||||
const tempDirectories = [];
|
||||
let downloadsPath: string;
|
||||
if (options.downloadsPath) {
|
||||
|
|
@ -142,12 +138,12 @@ export abstract class BrowserTypeBase implements BrowserType {
|
|||
}
|
||||
|
||||
const browserArguments = [];
|
||||
if (!ignoreDefaultArgs)
|
||||
browserArguments.push(...this._defaultArgs(options, isPersistent, userDataDir));
|
||||
else if (Array.isArray(ignoreDefaultArgs))
|
||||
if (ignoreAllDefaultArgs)
|
||||
browserArguments.push(...args);
|
||||
else if (ignoreDefaultArgs)
|
||||
browserArguments.push(...this._defaultArgs(options, isPersistent, userDataDir).filter(arg => ignoreDefaultArgs.indexOf(arg) === -1));
|
||||
else
|
||||
browserArguments.push(...args);
|
||||
browserArguments.push(...this._defaultArgs(options, isPersistent, userDataDir));
|
||||
|
||||
const executable = executablePath || this.executablePath();
|
||||
if (!executable)
|
||||
|
|
@ -211,7 +207,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
|||
return { browserProcess, downloadsPath, transport };
|
||||
}
|
||||
|
||||
abstract _defaultArgs(options: types.LaunchOptionsBase, isPersistent: boolean, userDataDir: string): string[];
|
||||
abstract _defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[];
|
||||
abstract _connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<BrowserBase>;
|
||||
abstract _amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
|
||||
abstract _amendArguments(browserArguments: string[]): string[];
|
||||
|
|
@ -226,7 +222,7 @@ function copyTestHooks(from: object, to: object) {
|
|||
}
|
||||
}
|
||||
|
||||
function validateLaunchOptions<Options extends types.LaunchOptionsBase>(options: Options): Options {
|
||||
function validateLaunchOptions<Options extends types.LaunchOptions>(options: Options): Options {
|
||||
const { devtools = false, headless = !helper.isDebugMode() && !devtools } = options;
|
||||
return { ...options, devtools, headless };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { ConnectionTransport, ProtocolRequest } from '../transport';
|
|||
import { BrowserDescriptor } from '../install/browserPaths';
|
||||
import { CRDevTools } from '../chromium/crDevTools';
|
||||
import { BrowserOptions } from '../browser';
|
||||
import { LaunchOptionsBase } from '../types';
|
||||
import * as types from '../types';
|
||||
|
||||
export class Chromium extends BrowserTypeBase {
|
||||
private _devtools: CRDevTools | undefined;
|
||||
|
|
@ -101,7 +101,7 @@ export class Chromium extends BrowserTypeBase {
|
|||
transport.send(message);
|
||||
}
|
||||
|
||||
_defaultArgs(options: LaunchOptionsBase, isPersistent: boolean, userDataDir: string): string[] {
|
||||
_defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[] {
|
||||
const { args = [], proxy } = options;
|
||||
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir'));
|
||||
if (userDataDirArg)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { Page } from '../page';
|
|||
import { TimeoutSettings } from '../timeoutSettings';
|
||||
import { WebSocketTransport } from '../transport';
|
||||
import * as types from '../types';
|
||||
import { launchProcess, waitForLine } from './processLauncher';
|
||||
import { launchProcess, waitForLine, envArrayToObject } from './processLauncher';
|
||||
import { BrowserContext } from '../browserContext';
|
||||
import type {BrowserWindow} from 'electron';
|
||||
import { runAbortableTask, ProgressController } from '../progress';
|
||||
|
|
@ -35,7 +35,7 @@ import { BrowserProcess } from '../browser';
|
|||
export type ElectronLaunchOptionsBase = {
|
||||
args?: string[],
|
||||
cwd?: string,
|
||||
env?: types.Env,
|
||||
env?: types.EnvArray,
|
||||
handleSIGINT?: boolean,
|
||||
handleSIGTERM?: boolean,
|
||||
handleSIGHUP?: boolean,
|
||||
|
|
@ -145,7 +145,6 @@ export class Electron {
|
|||
async launch(executablePath: string, options: ElectronLaunchOptionsBase = {}): Promise<ElectronApplication> {
|
||||
const {
|
||||
args = [],
|
||||
env = process.env,
|
||||
handleSIGINT = true,
|
||||
handleSIGTERM = true,
|
||||
handleSIGHUP = true,
|
||||
|
|
@ -156,7 +155,7 @@ export class Electron {
|
|||
const { launchedProcess, gracefullyClose, kill } = await launchProcess({
|
||||
executablePath,
|
||||
args: electronArguments,
|
||||
env,
|
||||
env: options.env ? envArrayToObject(options.env) : process.env,
|
||||
handleSIGINT,
|
||||
handleSIGTERM,
|
||||
handleSIGHUP,
|
||||
|
|
@ -180,7 +179,7 @@ export class Electron {
|
|||
close: gracefullyClose,
|
||||
kill
|
||||
};
|
||||
const browser = await CRBrowser.connect(chromeTransport, { name: 'electron', headful: true, persistent: { viewport: null }, browserProcess });
|
||||
const browser = await CRBrowser.connect(chromeTransport, { name: 'electron', headful: true, persistent: { noDefaultViewport: true }, browserProcess });
|
||||
app = new ElectronApplication(browser, nodeConnection);
|
||||
await app._init();
|
||||
return app;
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@ import * as fs from 'fs';
|
|||
import * as path from 'path';
|
||||
import { FFBrowser } from '../firefox/ffBrowser';
|
||||
import { kBrowserCloseMessageId } from '../firefox/ffConnection';
|
||||
import { BrowserTypeBase, LaunchNonPersistentOptions } from './browserType';
|
||||
import { BrowserTypeBase } from './browserType';
|
||||
import { Env } from './processLauncher';
|
||||
import { ConnectionTransport } from '../transport';
|
||||
import { BrowserOptions } from '../browser';
|
||||
import { BrowserDescriptor } from '../install/browserPaths';
|
||||
import * as types from '../types';
|
||||
|
||||
export class Firefox extends BrowserTypeBase {
|
||||
constructor(packagePath: string, browser: BrowserDescriptor) {
|
||||
|
|
@ -57,7 +58,7 @@ export class Firefox extends BrowserTypeBase {
|
|||
transport.send(message);
|
||||
}
|
||||
|
||||
_defaultArgs(options: LaunchNonPersistentOptions, isPersistent: boolean, userDataDir: string): string[] {
|
||||
_defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[] {
|
||||
const { args = [], devtools, headless } = options;
|
||||
if (devtools)
|
||||
console.warn('devtools parameter is not supported as a launch argument in Firefox. You can launch the devtools window manually.');
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import * as removeFolder from 'rimraf';
|
|||
import * as stream from 'stream';
|
||||
import { helper, isUnderTest } from '../helper';
|
||||
import { Progress } from '../progress';
|
||||
import * as types from '../types';
|
||||
|
||||
export type Env = {[key: string]: string | number | boolean | undefined};
|
||||
|
||||
|
|
@ -204,3 +205,10 @@ export function waitForLine(progress: Progress, process: childProcess.ChildProce
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function envArrayToObject(env: types.EnvArray): Env {
|
||||
const result: Env = {};
|
||||
for (const { name, value } of env)
|
||||
result[name] = value;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { BrowserTypeBase } from './browserType';
|
|||
import { ConnectionTransport } from '../transport';
|
||||
import { BrowserOptions } from '../browser';
|
||||
import { BrowserDescriptor } from '../install/browserPaths';
|
||||
import { LaunchOptionsBase } from '../types';
|
||||
import * as types from '../types';
|
||||
|
||||
export class WebKit extends BrowserTypeBase {
|
||||
constructor(packagePath: string, browser: BrowserDescriptor) {
|
||||
|
|
@ -50,7 +50,7 @@ export class WebKit extends BrowserTypeBase {
|
|||
transport.send({method: 'Playwright.close', params: {}, id: kBrowserCloseMessageId});
|
||||
}
|
||||
|
||||
_defaultArgs(options: LaunchOptionsBase, isPersistent: boolean, userDataDir: string): string[] {
|
||||
_defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[] {
|
||||
const { args = [], proxy, devtools, headless } = options;
|
||||
if (devtools)
|
||||
console.warn('devtools parameter as a launch argument in WebKit is not supported. Also starting Web Inspector manually will terminate the execution in WebKit.');
|
||||
|
|
|
|||
19
src/types.ts
19
src/types.ts
|
|
@ -265,7 +265,8 @@ export type SetNetworkCookieParam = {
|
|||
};
|
||||
|
||||
export type BrowserContextOptions = {
|
||||
viewport?: Size | null,
|
||||
viewport?: Size,
|
||||
noDefaultViewport?: boolean,
|
||||
ignoreHTTPSErrors?: boolean,
|
||||
javaScriptEnabled?: boolean,
|
||||
bypassCSP?: boolean,
|
||||
|
|
@ -284,27 +285,29 @@ export type BrowserContextOptions = {
|
|||
acceptDownloads?: boolean,
|
||||
};
|
||||
|
||||
export type Env = {[key: string]: string | number | boolean | undefined};
|
||||
export type EnvArray = { name: string, value: string }[];
|
||||
|
||||
export type LaunchOptionsBase = {
|
||||
type LaunchOptionsBase = {
|
||||
executablePath?: string,
|
||||
args?: string[],
|
||||
ignoreDefaultArgs?: boolean | string[],
|
||||
ignoreDefaultArgs?: string[],
|
||||
ignoreAllDefaultArgs?: boolean,
|
||||
handleSIGINT?: boolean,
|
||||
handleSIGTERM?: boolean,
|
||||
handleSIGHUP?: boolean,
|
||||
timeout?: number,
|
||||
env?: Env,
|
||||
env?: EnvArray,
|
||||
headless?: boolean,
|
||||
devtools?: boolean,
|
||||
proxy?: ProxySettings,
|
||||
downloadsPath?: string,
|
||||
chromiumSandbox?: boolean,
|
||||
slowMo?: number,
|
||||
};
|
||||
|
||||
export type LaunchOptions = LaunchOptionsBase & { slowMo?: number };
|
||||
export type LaunchServerOptions = LaunchOptionsBase & { port?: number };
|
||||
export type LaunchOptions = LaunchOptionsBase & {
|
||||
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
||||
};
|
||||
export type LaunchPersistentOptions = LaunchOptionsBase & BrowserContextOptions;
|
||||
|
||||
export type SerializedAXNode = {
|
||||
role: string,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BrowserBase, BrowserOptions, BrowserContextOptions } from '../browser';
|
||||
import { BrowserBase, BrowserOptions } from '../browser';
|
||||
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
|
||||
import { Events } from '../events';
|
||||
import { helper, RegisteredListener, assert } from '../helper';
|
||||
|
|
@ -72,8 +72,8 @@ export class WKBrowser extends BrowserBase {
|
|||
this._didClose();
|
||||
}
|
||||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
options = validateBrowserContextOptions(options);
|
||||
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
validateBrowserContextOptions(options);
|
||||
const { browserContextId } = await this._browserSession.send('Playwright.createContext');
|
||||
options.userAgent = options.userAgent || DEFAULT_USER_AGENT;
|
||||
const context = new WKBrowserContext(this, browserContextId, options);
|
||||
|
|
@ -287,8 +287,7 @@ export class WKBrowserContext extends BrowserContextBase {
|
|||
}
|
||||
|
||||
async setGeolocation(geolocation?: types.Geolocation): Promise<void> {
|
||||
if (geolocation)
|
||||
geolocation = verifyGeolocation(geolocation);
|
||||
verifyGeolocation(geolocation);
|
||||
this._options.geolocation = geolocation;
|
||||
const payload: any = geolocation ? { ...geolocation, timestamp: Date.now() } : undefined;
|
||||
await this._browser._browserSession.send('Playwright.setGeolocationOverride', { browserContextId: this._browserContextId, geolocation: payload });
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export class WKPage implements PageDelegate {
|
|||
this._firstNonInitialNavigationCommittedFulfill = f;
|
||||
this._firstNonInitialNavigationCommittedReject = r;
|
||||
});
|
||||
if (opener && browserContext._options.viewport !== null && opener._nextWindowOpenPopupFeatures) {
|
||||
if (opener && !browserContext._options.noDefaultViewport && opener._nextWindowOpenPopupFeatures) {
|
||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
|
||||
opener._nextWindowOpenPopupFeatures = undefined;
|
||||
if (viewportSize)
|
||||
|
|
|
|||
Loading…
Reference in a new issue