chore: add Playwright to attribution (#23447)
This makes it easier to plumb all kinds of options around.
This commit is contained in:
parent
2719f408b2
commit
14a1eaa474
|
|
@ -24,7 +24,7 @@ import { PlaywrightServer } from './remote/playwrightServer';
|
||||||
|
|
||||||
export class AndroidServerLauncherImpl {
|
export class AndroidServerLauncherImpl {
|
||||||
async launchServer(options: LaunchAndroidServerOptions = {}): Promise<BrowserServer> {
|
async launchServer(options: LaunchAndroidServerOptions = {}): Promise<BrowserServer> {
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright({ sdkLanguage: 'javascript', isServer: true });
|
||||||
// 1. Pre-connect to the device
|
// 1. Pre-connect to the device
|
||||||
let devices = await playwright.android.devices({
|
let devices = await playwright.android.devices({
|
||||||
host: options.adbHost,
|
host: options.adbHost,
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
|
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright({ sdkLanguage: 'javascript', isServer: true });
|
||||||
// TODO: enable socks proxy once ipv6 is supported.
|
// TODO: enable socks proxy once ipv6 is supported.
|
||||||
const socksProxy = false ? new SocksProxy() : undefined;
|
const socksProxy = false ? new SocksProxy() : undefined;
|
||||||
playwright.options.socksProxyPort = await socksProxy?.listen(0);
|
playwright.options.socksProxyPort = await socksProxy?.listen(0);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export function printApiJson() {
|
||||||
export function runDriver() {
|
export function runDriver() {
|
||||||
const dispatcherConnection = new DispatcherConnection();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
new RootDispatcher(dispatcherConnection, async (rootScope, { sdkLanguage }) => {
|
new RootDispatcher(dispatcherConnection, async (rootScope, { sdkLanguage }) => {
|
||||||
const playwright = createPlaywright(sdkLanguage);
|
const playwright = createPlaywright({ sdkLanguage });
|
||||||
return new PlaywrightDispatcher(rootScope, playwright);
|
return new PlaywrightDispatcher(rootScope, playwright);
|
||||||
});
|
});
|
||||||
const transport = new PipeTransport(process.stdout, process.stdin);
|
const transport = new PipeTransport(process.stdout, process.stdin);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { AndroidServerLauncherImpl } from './androidServerImpl';
|
||||||
import type { Language } from './utils/isomorphic/locatorGenerators';
|
import type { Language } from './utils/isomorphic/locatorGenerators';
|
||||||
|
|
||||||
export function createInProcessPlaywright(): PlaywrightAPI {
|
export function createInProcessPlaywright(): PlaywrightAPI {
|
||||||
const playwright = createPlaywright((process.env.PW_LANG_NAME as Language | undefined) || 'javascript');
|
const playwright = createPlaywright({ sdkLanguage: (process.env.PW_LANG_NAME as Language | undefined) || 'javascript' });
|
||||||
|
|
||||||
const clientConnection = new Connection();
|
const clientConnection = new Connection();
|
||||||
const dispatcherConnection = new DispatcherConnection(true /* local */);
|
const dispatcherConnection = new DispatcherConnection(true /* local */);
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ export class PlaywrightConnection {
|
||||||
|
|
||||||
private async _initLaunchBrowserMode(scope: RootDispatcher) {
|
private async _initLaunchBrowserMode(scope: RootDispatcher) {
|
||||||
debugLogger.log('server', `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
|
debugLogger.log('server', `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright({ sdkLanguage: 'javascript', isServer: true });
|
||||||
|
|
||||||
const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
|
const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
|
||||||
const browser = await playwright[this._options.browserName as 'chromium'].launch(serverSideCallMetadata(), this._options.launchOptions);
|
const browser = await playwright[this._options.browserName as 'chromium'].launch(serverSideCallMetadata(), this._options.launchOptions);
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ export class PlaywrightServer {
|
||||||
constructor(options: ServerOptions) {
|
constructor(options: ServerOptions) {
|
||||||
this._options = options;
|
this._options = options;
|
||||||
if (options.preLaunchedBrowser)
|
if (options.preLaunchedBrowser)
|
||||||
this._preLaunchedPlaywright = options.preLaunchedBrowser.options.rootSdkObject as Playwright;
|
this._preLaunchedPlaywright = options.preLaunchedBrowser.attribution.playwright;
|
||||||
if (options.preLaunchedAndroidDevice)
|
if (options.preLaunchedAndroidDevice)
|
||||||
this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android._playwrightOptions.rootSdkObject as Playwright;
|
this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android.attribution.playwright;
|
||||||
}
|
}
|
||||||
|
|
||||||
async listen(port: number = 0): Promise<string> {
|
async listen(port: number = 0): Promise<string> {
|
||||||
|
|
@ -114,7 +114,7 @@ export class PlaywrightServer {
|
||||||
const isExtension = this._options.mode === 'extension';
|
const isExtension = this._options.mode === 'extension';
|
||||||
if (isExtension) {
|
if (isExtension) {
|
||||||
if (!this._preLaunchedPlaywright)
|
if (!this._preLaunchedPlaywright)
|
||||||
this._preLaunchedPlaywright = createPlaywright('javascript');
|
this._preLaunchedPlaywright = createPlaywright({ sdkLanguage: 'javascript', isServer: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
let clientType: ClientType = 'launch-browser';
|
let clientType: ClientType = 'launch-browser';
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import type * as stream from 'stream';
|
||||||
import { wsReceiver, wsSender } from '../../utilsBundle';
|
import { wsReceiver, wsSender } from '../../utilsBundle';
|
||||||
import { createGuid, makeWaitForNextTask, isUnderTest } from '../../utils';
|
import { createGuid, makeWaitForNextTask, isUnderTest } from '../../utils';
|
||||||
import { removeFolders } from '../../utils/fileUtils';
|
import { removeFolders } from '../../utils/fileUtils';
|
||||||
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
|
import type { BrowserOptions, BrowserProcess } from '../browser';
|
||||||
import type { BrowserContext } from '../browserContext';
|
import type { BrowserContext } from '../browserContext';
|
||||||
import { validateBrowserContextOptions } from '../browserContext';
|
import { validateBrowserContextOptions } from '../browserContext';
|
||||||
import { ProgressController } from '../progress';
|
import { ProgressController } from '../progress';
|
||||||
|
|
@ -63,12 +63,10 @@ export class Android extends SdkObject {
|
||||||
private _backend: Backend;
|
private _backend: Backend;
|
||||||
private _devices = new Map<string, AndroidDevice>();
|
private _devices = new Map<string, AndroidDevice>();
|
||||||
readonly _timeoutSettings: TimeoutSettings;
|
readonly _timeoutSettings: TimeoutSettings;
|
||||||
readonly _playwrightOptions: PlaywrightOptions;
|
|
||||||
|
|
||||||
constructor(backend: Backend, playwrightOptions: PlaywrightOptions) {
|
constructor(parent: SdkObject, backend: Backend) {
|
||||||
super(playwrightOptions.rootSdkObject, 'android');
|
super(parent, 'android');
|
||||||
this._backend = backend;
|
this._backend = backend;
|
||||||
this._playwrightOptions = playwrightOptions;
|
|
||||||
this._timeoutSettings = new TimeoutSettings();
|
this._timeoutSettings = new TimeoutSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,7 +324,6 @@ export class AndroidDevice extends SdkObject {
|
||||||
cleanupArtifactsDir().catch(e => debug('pw:android')(`could not cleanup artifacts dir: ${e}`));
|
cleanupArtifactsDir().catch(e => debug('pw:android')(`could not cleanup artifacts dir: ${e}`));
|
||||||
});
|
});
|
||||||
const browserOptions: BrowserOptions = {
|
const browserOptions: BrowserOptions = {
|
||||||
...this._android._playwrightOptions,
|
|
||||||
name: 'clank',
|
name: 'clank',
|
||||||
isChromium: true,
|
isChromium: true,
|
||||||
slowMo: 0,
|
slowMo: 0,
|
||||||
|
|
@ -342,7 +339,7 @@ export class AndroidDevice extends SdkObject {
|
||||||
};
|
};
|
||||||
validateBrowserContextOptions(options, browserOptions);
|
validateBrowserContextOptions(options, browserOptions);
|
||||||
|
|
||||||
const browser = await CRBrowser.connect(androidBrowser, browserOptions);
|
const browser = await CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions);
|
||||||
const controller = new ProgressController(serverSideCallMetadata(), this);
|
const controller = new ProgressController(serverSideCallMetadata(), this);
|
||||||
const defaultContext = browser._defaultContext!;
|
const defaultContext = browser._defaultContext!;
|
||||||
await controller.run(async progress => {
|
await controller.run(async progress => {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@ import type { RecentLogsCollector } from '../common/debugLogger';
|
||||||
import type { CallMetadata } from './instrumentation';
|
import type { CallMetadata } from './instrumentation';
|
||||||
import { SdkObject } from './instrumentation';
|
import { SdkObject } from './instrumentation';
|
||||||
import { Artifact } from './artifact';
|
import { Artifact } from './artifact';
|
||||||
import type { Selectors } from './selectors';
|
|
||||||
import type { Language } from '../utils/isomorphic/locatorGenerators';
|
|
||||||
|
|
||||||
export interface BrowserProcess {
|
export interface BrowserProcess {
|
||||||
onclose?: ((exitCode: number | null, signal: string | null) => void);
|
onclose?: ((exitCode: number | null, signal: string | null) => void);
|
||||||
|
|
@ -35,14 +33,7 @@ export interface BrowserProcess {
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PlaywrightOptions = {
|
export type BrowserOptions = {
|
||||||
rootSdkObject: SdkObject;
|
|
||||||
selectors: Selectors;
|
|
||||||
socksProxyPort?: number;
|
|
||||||
sdkLanguage: Language,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BrowserOptions = PlaywrightOptions & {
|
|
||||||
name: string,
|
name: string,
|
||||||
isChromium: boolean,
|
isChromium: boolean,
|
||||||
channel?: string,
|
channel?: string,
|
||||||
|
|
@ -74,8 +65,8 @@ export abstract class Browser extends SdkObject {
|
||||||
readonly _idToVideo = new Map<string, { context: BrowserContext, artifact: Artifact }>();
|
readonly _idToVideo = new Map<string, { context: BrowserContext, artifact: Artifact }>();
|
||||||
private _contextForReuse: { context: BrowserContext, hash: string } | undefined;
|
private _contextForReuse: { context: BrowserContext, hash: string } | undefined;
|
||||||
|
|
||||||
constructor(options: BrowserOptions) {
|
constructor(parent: SdkObject, options: BrowserOptions) {
|
||||||
super(options.rootSdkObject, 'browser');
|
super(parent, 'browser');
|
||||||
this.attribution.browser = this;
|
this.attribution.browser = this;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.instrumentation.onBrowserOpen(this);
|
this.instrumentation.onBrowserOpen(this);
|
||||||
|
|
|
||||||
|
|
@ -107,11 +107,11 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
selectors(): Selectors {
|
selectors(): Selectors {
|
||||||
return this._selectors || this._browser.options.selectors;
|
return this._selectors || this.attribution.playwright.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _initialize() {
|
async _initialize() {
|
||||||
if (this.attribution.isInternalPlaywright)
|
if (this.attribution.playwright.options.isInternalPlaywright)
|
||||||
return;
|
return;
|
||||||
// Debugger will pause execution upon page.pause in headed mode.
|
// Debugger will pause execution upon page.pause in headed mode.
|
||||||
this._debugger = new Debugger(this);
|
this._debugger = new Debugger(this);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import type { BrowserName } from './registry';
|
||||||
import { registry } from './registry';
|
import { registry } from './registry';
|
||||||
import type { ConnectionTransport } from './transport';
|
import type { ConnectionTransport } from './transport';
|
||||||
import { WebSocketTransport } from './transport';
|
import { WebSocketTransport } from './transport';
|
||||||
import type { BrowserOptions, Browser, BrowserProcess, PlaywrightOptions } from './browser';
|
import type { BrowserOptions, Browser, BrowserProcess } from './browser';
|
||||||
import type { Env } from '../utils/processLauncher';
|
import type { Env } from '../utils/processLauncher';
|
||||||
import { launchProcess, envArrayToObject } from '../utils/processLauncher';
|
import { launchProcess, envArrayToObject } from '../utils/processLauncher';
|
||||||
import { PipeTransport } from './pipeTransport';
|
import { PipeTransport } from './pipeTransport';
|
||||||
|
|
@ -45,17 +45,15 @@ export const kNoXServerRunningError = 'Looks like you launched a headed browser
|
||||||
|
|
||||||
export abstract class BrowserType extends SdkObject {
|
export abstract class BrowserType extends SdkObject {
|
||||||
private _name: BrowserName;
|
private _name: BrowserName;
|
||||||
readonly _playwrightOptions: PlaywrightOptions;
|
|
||||||
|
|
||||||
constructor(browserName: BrowserName, playwrightOptions: PlaywrightOptions) {
|
constructor(parent: SdkObject, browserName: BrowserName) {
|
||||||
super(playwrightOptions.rootSdkObject, 'browser-type');
|
super(parent, 'browser-type');
|
||||||
this.attribution.browserType = this;
|
this.attribution.browserType = this;
|
||||||
this._playwrightOptions = playwrightOptions;
|
|
||||||
this._name = browserName;
|
this._name = browserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
executablePath(): string {
|
executablePath(): string {
|
||||||
return registry.findExecutable(this._name).executablePath(this._playwrightOptions.sdkLanguage) || '';
|
return registry.findExecutable(this._name).executablePath(this.attribution.playwright.options.sdkLanguage) || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
name(): string {
|
name(): string {
|
||||||
|
|
@ -107,7 +105,6 @@ export abstract class BrowserType extends SdkObject {
|
||||||
if ((options as any).__testHookBeforeCreateBrowser)
|
if ((options as any).__testHookBeforeCreateBrowser)
|
||||||
await (options as any).__testHookBeforeCreateBrowser();
|
await (options as any).__testHookBeforeCreateBrowser();
|
||||||
const browserOptions: BrowserOptions = {
|
const browserOptions: BrowserOptions = {
|
||||||
...this._playwrightOptions,
|
|
||||||
name: this._name,
|
name: this._name,
|
||||||
isChromium: this._name === 'chromium',
|
isChromium: this._name === 'chromium',
|
||||||
channel: options.channel,
|
channel: options.channel,
|
||||||
|
|
@ -184,8 +181,8 @@ export abstract class BrowserType extends SdkObject {
|
||||||
const registryExecutable = registry.findExecutable(options.channel || this._name);
|
const registryExecutable = registry.findExecutable(options.channel || this._name);
|
||||||
if (!registryExecutable || registryExecutable.browserName !== this._name)
|
if (!registryExecutable || registryExecutable.browserName !== this._name)
|
||||||
throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
||||||
executable = registryExecutable.executablePathOrDie(this._playwrightOptions.sdkLanguage);
|
executable = registryExecutable.executablePathOrDie(this.attribution.playwright.options.sdkLanguage);
|
||||||
await registryExecutable.validateHostRequirements(this._playwrightOptions.sdkLanguage);
|
await registryExecutable.validateHostRequirements(this.attribution.playwright.options.sdkLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitForWSEndpoint = (options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'))) ? new ManualPromise<string>() : undefined;
|
const waitForWSEndpoint = (options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'))) ? new ManualPromise<string>() : undefined;
|
||||||
|
|
@ -275,8 +272,8 @@ export abstract class BrowserType extends SdkObject {
|
||||||
headless = false;
|
headless = false;
|
||||||
if (downloadsPath && !path.isAbsolute(downloadsPath))
|
if (downloadsPath && !path.isAbsolute(downloadsPath))
|
||||||
downloadsPath = path.join(process.cwd(), downloadsPath);
|
downloadsPath = path.join(process.cwd(), downloadsPath);
|
||||||
if (this._playwrightOptions.socksProxyPort)
|
if (this.attribution.playwright.options.socksProxyPort)
|
||||||
proxy = { server: `socks5://127.0.0.1:${this._playwrightOptions.socksProxyPort}` };
|
proxy = { server: `socks5://127.0.0.1:${this.attribution.playwright.options.socksProxyPort}` };
|
||||||
return { ...options, devtools, headless, downloadsPath, proxy };
|
return { ...options, devtools, headless, downloadsPath, proxy };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import { BrowserType, kNoXServerRunningError } from '../browserType';
|
||||||
import type { ConnectionTransport, ProtocolRequest } from '../transport';
|
import type { ConnectionTransport, ProtocolRequest } from '../transport';
|
||||||
import { WebSocketTransport } from '../transport';
|
import { WebSocketTransport } from '../transport';
|
||||||
import { CRDevTools } from './crDevTools';
|
import { CRDevTools } from './crDevTools';
|
||||||
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
|
import type { BrowserOptions, BrowserProcess } from '../browser';
|
||||||
import { Browser } from '../browser';
|
import { Browser } from '../browser';
|
||||||
import type * as types from '../types';
|
import type * as types from '../types';
|
||||||
import type * as channels from '@protocol/channels';
|
import type * as channels from '@protocol/channels';
|
||||||
|
|
@ -43,7 +43,7 @@ import type { Progress } from '../progress';
|
||||||
import { ProgressController } from '../progress';
|
import { ProgressController } from '../progress';
|
||||||
import { TimeoutSettings } from '../../common/timeoutSettings';
|
import { TimeoutSettings } from '../../common/timeoutSettings';
|
||||||
import { helper } from '../helper';
|
import { helper } from '../helper';
|
||||||
import type { CallMetadata } from '../instrumentation';
|
import type { CallMetadata, SdkObject } from '../instrumentation';
|
||||||
import type http from 'http';
|
import type http from 'http';
|
||||||
import { registry } from '../registry';
|
import { registry } from '../registry';
|
||||||
import { ManualPromise } from '../../utils/manualPromise';
|
import { ManualPromise } from '../../utils/manualPromise';
|
||||||
|
|
@ -55,8 +55,8 @@ const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
|
||||||
export class Chromium extends BrowserType {
|
export class Chromium extends BrowserType {
|
||||||
private _devtools: CRDevTools | undefined;
|
private _devtools: CRDevTools | undefined;
|
||||||
|
|
||||||
constructor(playwrightOptions: PlaywrightOptions) {
|
constructor(parent: SdkObject) {
|
||||||
super('chromium', playwrightOptions);
|
super(parent, 'chromium');
|
||||||
|
|
||||||
if (debugMode())
|
if (debugMode())
|
||||||
this._devtools = this._createDevTools();
|
this._devtools = this._createDevTools();
|
||||||
|
|
@ -99,7 +99,6 @@ export class Chromium extends BrowserType {
|
||||||
const browserProcess: BrowserProcess = { close: doClose, kill: doClose };
|
const browserProcess: BrowserProcess = { close: doClose, kill: doClose };
|
||||||
const persistent: channels.BrowserNewContextParams = { noDefaultViewport: true };
|
const persistent: channels.BrowserNewContextParams = { noDefaultViewport: true };
|
||||||
const browserOptions: BrowserOptions = {
|
const browserOptions: BrowserOptions = {
|
||||||
...this._playwrightOptions,
|
|
||||||
slowMo: options.slowMo,
|
slowMo: options.slowMo,
|
||||||
name: 'chromium',
|
name: 'chromium',
|
||||||
isChromium: true,
|
isChromium: true,
|
||||||
|
|
@ -120,7 +119,7 @@ export class Chromium extends BrowserType {
|
||||||
};
|
};
|
||||||
validateBrowserContextOptions(persistent, browserOptions);
|
validateBrowserContextOptions(persistent, browserOptions);
|
||||||
progress.throwIfAborted();
|
progress.throwIfAborted();
|
||||||
const browser = await CRBrowser.connect(chromeTransport, browserOptions);
|
const browser = await CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions);
|
||||||
browser.on(Browser.Events.Disconnected, doCleanup);
|
browser.on(Browser.Events.Disconnected, doCleanup);
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +136,7 @@ export class Chromium extends BrowserType {
|
||||||
devtools = this._createDevTools();
|
devtools = this._createDevTools();
|
||||||
await (options as any).__testHookForDevTools(devtools);
|
await (options as any).__testHookForDevTools(devtools);
|
||||||
}
|
}
|
||||||
return CRBrowser.connect(transport, options, devtools);
|
return CRBrowser.connect(this.attribution.playwright, transport, options, devtools);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewriteStartupError(error: Error): Error {
|
_rewriteStartupError(error: Error): Error {
|
||||||
|
|
@ -309,14 +308,14 @@ export class Chromium extends BrowserType {
|
||||||
const proxyURL = new URL(proxy.server);
|
const proxyURL = new URL(proxy.server);
|
||||||
const isSocks = proxyURL.protocol === 'socks5:';
|
const isSocks = proxyURL.protocol === 'socks5:';
|
||||||
// https://www.chromium.org/developers/design-documents/network-settings
|
// https://www.chromium.org/developers/design-documents/network-settings
|
||||||
if (isSocks && !this._playwrightOptions.socksProxyPort) {
|
if (isSocks && !this.attribution.playwright.options.socksProxyPort) {
|
||||||
// https://www.chromium.org/developers/design-documents/network-stack/socks-proxy
|
// https://www.chromium.org/developers/design-documents/network-stack/socks-proxy
|
||||||
chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
|
chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
|
||||||
}
|
}
|
||||||
chromeArguments.push(`--proxy-server=${proxy.server}`);
|
chromeArguments.push(`--proxy-server=${proxy.server}`);
|
||||||
const proxyBypassRules = [];
|
const proxyBypassRules = [];
|
||||||
// https://source.chromium.org/chromium/chromium/src/+/master:net/docs/proxy.md;l=548;drc=71698e610121078e0d1a811054dcf9fd89b49578
|
// https://source.chromium.org/chromium/chromium/src/+/master:net/docs/proxy.md;l=548;drc=71698e610121078e0d1a811054dcf9fd89b49578
|
||||||
if (this._playwrightOptions.socksProxyPort)
|
if (this.attribution.playwright.options.socksProxyPort)
|
||||||
proxyBypassRules.push('<-loopback>');
|
proxyBypassRules.push('<-loopback>');
|
||||||
if (proxy.bypass)
|
if (proxy.bypass)
|
||||||
proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));
|
proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import { readProtocolStream } from './crProtocolHelper';
|
||||||
import type { Protocol } from './protocol';
|
import type { Protocol } from './protocol';
|
||||||
import type { CRDevTools } from './crDevTools';
|
import type { CRDevTools } from './crDevTools';
|
||||||
import { CRServiceWorker } from './crServiceWorker';
|
import { CRServiceWorker } from './crServiceWorker';
|
||||||
|
import type { SdkObject } from '../instrumentation';
|
||||||
|
|
||||||
export class CRBrowser extends Browser {
|
export class CRBrowser extends Browser {
|
||||||
readonly _connection: CRConnection;
|
readonly _connection: CRConnection;
|
||||||
|
|
@ -51,11 +52,11 @@ export class CRBrowser extends Browser {
|
||||||
private _tracingClient: CRSession | undefined;
|
private _tracingClient: CRSession | undefined;
|
||||||
private _userAgent: string = '';
|
private _userAgent: string = '';
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, options: BrowserOptions, devtools?: CRDevTools): Promise<CRBrowser> {
|
static async connect(parent: SdkObject, transport: ConnectionTransport, options: BrowserOptions, devtools?: CRDevTools): Promise<CRBrowser> {
|
||||||
// Make a copy in case we need to update `headful` property below.
|
// Make a copy in case we need to update `headful` property below.
|
||||||
options = { ...options };
|
options = { ...options };
|
||||||
const connection = new CRConnection(transport, options.protocolLogger, options.browserLogsCollector);
|
const connection = new CRConnection(transport, options.protocolLogger, options.browserLogsCollector);
|
||||||
const browser = new CRBrowser(connection, options);
|
const browser = new CRBrowser(parent, connection, options);
|
||||||
browser._devtools = devtools;
|
browser._devtools = devtools;
|
||||||
const session = connection.rootSession;
|
const session = connection.rootSession;
|
||||||
if ((options as any).__testHookOnConnectToBrowser)
|
if ((options as any).__testHookOnConnectToBrowser)
|
||||||
|
|
@ -85,8 +86,8 @@ export class CRBrowser extends Browser {
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(connection: CRConnection, options: BrowserOptions) {
|
constructor(parent: SdkObject, connection: CRConnection, options: BrowserOptions) {
|
||||||
super(options);
|
super(parent, options);
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._session = this._connection.rootSession;
|
this._session = this._connection.rootSession;
|
||||||
this._connection.on(ConnectionEvents.Disconnected, () => this._didClose());
|
this._connection.on(ConnectionEvents.Disconnected, () => this._didClose());
|
||||||
|
|
|
||||||
|
|
@ -922,7 +922,7 @@ class FrameSession {
|
||||||
|
|
||||||
async _createVideoRecorder(screencastId: string, options: types.PageScreencastOptions): Promise<void> {
|
async _createVideoRecorder(screencastId: string, options: types.PageScreencastOptions): Promise<void> {
|
||||||
assert(!this._screencastId);
|
assert(!this._screencastId);
|
||||||
const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePathOrDie(this._page._browserContext._browser.options.sdkLanguage);
|
const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePathOrDie(this._page.attribution.playwright.options.sdkLanguage);
|
||||||
this._videoRecorder = await VideoRecorder.launch(this._crPage._page, ffmpegPath, options);
|
this._videoRecorder = await VideoRecorder.launch(this._crPage._page, ffmpegPath, options);
|
||||||
this._screencastId = screencastId;
|
this._screencastId = screencastId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ export class FrameExecutionContext extends js.ExecutionContext {
|
||||||
const selectorsRegistry = this.frame._page.context().selectors();
|
const selectorsRegistry = this.frame._page.context().selectors();
|
||||||
for (const [name, { source }] of selectorsRegistry._engines)
|
for (const [name, { source }] of selectorsRegistry._engines)
|
||||||
custom.push(`{ name: '${name}', engine: (${source}) }`);
|
custom.push(`{ name: '${name}', engine: (${source}) }`);
|
||||||
const sdkLanguage = this.frame._page.context()._browser.options.sdkLanguage;
|
const sdkLanguage = this.frame.attribution.playwright.options.sdkLanguage;
|
||||||
const source = `
|
const source = `
|
||||||
(() => {
|
(() => {
|
||||||
const module = {};
|
const module = {};
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ import type { Progress } from '../progress';
|
||||||
import { ProgressController } from '../progress';
|
import { ProgressController } from '../progress';
|
||||||
import { helper } from '../helper';
|
import { helper } from '../helper';
|
||||||
import { eventsHelper } from '../../utils/eventsHelper';
|
import { eventsHelper } from '../../utils/eventsHelper';
|
||||||
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
|
import type { BrowserOptions, BrowserProcess } from '../browser';
|
||||||
|
import type { Playwright } from '../playwright';
|
||||||
import type * as childProcess from 'child_process';
|
import type * as childProcess from 'child_process';
|
||||||
import * as readline from 'readline';
|
import * as readline from 'readline';
|
||||||
import { RecentLogsCollector } from '../../common/debugLogger';
|
import { RecentLogsCollector } from '../../common/debugLogger';
|
||||||
|
|
@ -116,11 +117,8 @@ export class ElectronApplication extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Electron extends SdkObject {
|
export class Electron extends SdkObject {
|
||||||
private _playwrightOptions: PlaywrightOptions;
|
constructor(playwright: Playwright) {
|
||||||
|
super(playwright, 'electron');
|
||||||
constructor(playwrightOptions: PlaywrightOptions) {
|
|
||||||
super(playwrightOptions.rootSdkObject, 'electron');
|
|
||||||
this._playwrightOptions = playwrightOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(options: channels.ElectronLaunchParams): Promise<ElectronApplication> {
|
async launch(options: channels.ElectronLaunchParams): Promise<ElectronApplication> {
|
||||||
|
|
@ -224,7 +222,6 @@ export class Electron extends SdkObject {
|
||||||
noDefaultViewport: true,
|
noDefaultViewport: true,
|
||||||
};
|
};
|
||||||
const browserOptions: BrowserOptions = {
|
const browserOptions: BrowserOptions = {
|
||||||
...this._playwrightOptions,
|
|
||||||
name: 'electron',
|
name: 'electron',
|
||||||
isChromium: true,
|
isChromium: true,
|
||||||
headful: true,
|
headful: true,
|
||||||
|
|
@ -238,7 +235,7 @@ export class Electron extends SdkObject {
|
||||||
originalLaunchOptions: {},
|
originalLaunchOptions: {},
|
||||||
};
|
};
|
||||||
validateBrowserContextOptions(contextOptions, browserOptions);
|
validateBrowserContextOptions(contextOptions, browserOptions);
|
||||||
const browser = await CRBrowser.connect(chromeTransport, browserOptions);
|
const browser = await CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions);
|
||||||
app = new ElectronApplication(this, browser, nodeConnection, launchedProcess);
|
app = new ElectronApplication(this, browser, nodeConnection, launchedProcess);
|
||||||
await app.initialize();
|
await app.initialize();
|
||||||
return app;
|
return app;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import type * as channels from '@protocol/channels';
|
||||||
import { ConnectionEvents, FFConnection } from './ffConnection';
|
import { ConnectionEvents, FFConnection } from './ffConnection';
|
||||||
import { FFPage } from './ffPage';
|
import { FFPage } from './ffPage';
|
||||||
import type { Protocol } from './protocol';
|
import type { Protocol } from './protocol';
|
||||||
|
import type { SdkObject } from '../instrumentation';
|
||||||
|
|
||||||
export class FFBrowser extends Browser {
|
export class FFBrowser extends Browser {
|
||||||
_connection: FFConnection;
|
_connection: FFConnection;
|
||||||
|
|
@ -36,9 +37,9 @@ export class FFBrowser extends Browser {
|
||||||
private _version = '';
|
private _version = '';
|
||||||
private _userAgent: string = '';
|
private _userAgent: string = '';
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
|
static async connect(parent: SdkObject, transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
|
||||||
const connection = new FFConnection(transport, options.protocolLogger, options.browserLogsCollector);
|
const connection = new FFConnection(transport, options.protocolLogger, options.browserLogsCollector);
|
||||||
const browser = new FFBrowser(connection, options);
|
const browser = new FFBrowser(parent, connection, options);
|
||||||
if ((options as any).__testHookOnConnectToBrowser)
|
if ((options as any).__testHookOnConnectToBrowser)
|
||||||
await (options as any).__testHookOnConnectToBrowser();
|
await (options as any).__testHookOnConnectToBrowser();
|
||||||
let firefoxUserPrefs = options.persistent ? {} : options.originalLaunchOptions.firefoxUserPrefs ?? {};
|
let firefoxUserPrefs = options.persistent ? {} : options.originalLaunchOptions.firefoxUserPrefs ?? {};
|
||||||
|
|
@ -61,8 +62,8 @@ export class FFBrowser extends Browser {
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(connection: FFConnection, options: BrowserOptions) {
|
constructor(parent: SdkObject, connection: FFConnection, options: BrowserOptions) {
|
||||||
super(options);
|
super(parent, options);
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._ffPages = new Map();
|
this._ffPages = new Map();
|
||||||
this._contexts = new Map();
|
this._contexts = new Map();
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,19 @@ import { kBrowserCloseMessageId } from './ffConnection';
|
||||||
import { BrowserType, kNoXServerRunningError } from '../browserType';
|
import { BrowserType, kNoXServerRunningError } from '../browserType';
|
||||||
import type { Env } from '../../utils/processLauncher';
|
import type { Env } from '../../utils/processLauncher';
|
||||||
import type { ConnectionTransport } from '../transport';
|
import type { ConnectionTransport } from '../transport';
|
||||||
import type { BrowserOptions, PlaywrightOptions } from '../browser';
|
import type { BrowserOptions } from '../browser';
|
||||||
import type * as types from '../types';
|
import type * as types from '../types';
|
||||||
import { rewriteErrorMessage } from '../../utils/stackTrace';
|
import { rewriteErrorMessage } from '../../utils/stackTrace';
|
||||||
import { wrapInASCIIBox } from '../../utils';
|
import { wrapInASCIIBox } from '../../utils';
|
||||||
|
import type { SdkObject } from '../instrumentation';
|
||||||
|
|
||||||
export class Firefox extends BrowserType {
|
export class Firefox extends BrowserType {
|
||||||
constructor(playwrightOptions: PlaywrightOptions) {
|
constructor(parent: SdkObject) {
|
||||||
super('firefox', playwrightOptions);
|
super(parent, 'firefox');
|
||||||
}
|
}
|
||||||
|
|
||||||
_connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
|
_connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
|
||||||
return FFBrowser.connect(transport, options);
|
return FFBrowser.connect(this.attribution.playwright, transport, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewriteStartupError(error: Error): Error {
|
_rewriteStartupError(error: Error): Error {
|
||||||
|
|
|
||||||
|
|
@ -1675,7 +1675,7 @@ export class Frame extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _asLocator(selector: string) {
|
private _asLocator(selector: string) {
|
||||||
return asLocator(this._page.context()._browser.options.sdkLanguage, selector);
|
return asLocator(this._page.attribution.playwright.options.sdkLanguage, selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ import type { BrowserType } from './browserType';
|
||||||
import type { ElementHandle } from './dom';
|
import type { ElementHandle } from './dom';
|
||||||
import type { Frame } from './frames';
|
import type { Frame } from './frames';
|
||||||
import type { Page } from './page';
|
import type { Page } from './page';
|
||||||
|
import type { Playwright } from './playwright';
|
||||||
|
|
||||||
export type Attribution = {
|
export type Attribution = {
|
||||||
isInternalPlaywright: boolean,
|
playwright: Playwright;
|
||||||
browserType?: BrowserType;
|
browserType?: BrowserType;
|
||||||
browser?: Browser;
|
browser?: Browser;
|
||||||
context?: BrowserContext | APIRequestContext;
|
context?: BrowserContext | APIRequestContext;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { Android } from './android/android';
|
import { Android } from './android/android';
|
||||||
import { AdbBackend } from './android/backendAdb';
|
import { AdbBackend } from './android/backendAdb';
|
||||||
import type { Browser, PlaywrightOptions } from './browser';
|
import type { Browser } from './browser';
|
||||||
import { Chromium } from './chromium/chromium';
|
import { Chromium } from './chromium/chromium';
|
||||||
import { Electron } from './electron/electron';
|
import { Electron } from './electron/electron';
|
||||||
import { Firefox } from './firefox/firefox';
|
import { Firefox } from './firefox/firefox';
|
||||||
|
|
@ -29,6 +29,13 @@ import type { Page } from './page';
|
||||||
import { DebugController } from './debugController';
|
import { DebugController } from './debugController';
|
||||||
import type { Language } from '../utils/isomorphic/locatorGenerators';
|
import type { Language } from '../utils/isomorphic/locatorGenerators';
|
||||||
|
|
||||||
|
type PlaywrightOptions = {
|
||||||
|
socksProxyPort?: number;
|
||||||
|
sdkLanguage: Language;
|
||||||
|
isInternalPlaywright?: boolean;
|
||||||
|
isServer?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export class Playwright extends SdkObject {
|
export class Playwright extends SdkObject {
|
||||||
readonly selectors: Selectors;
|
readonly selectors: Selectors;
|
||||||
readonly chromium: Chromium;
|
readonly chromium: Chromium;
|
||||||
|
|
@ -41,8 +48,10 @@ export class Playwright extends SdkObject {
|
||||||
private _allPages = new Set<Page>();
|
private _allPages = new Set<Page>();
|
||||||
private _allBrowsers = new Set<Browser>();
|
private _allBrowsers = new Set<Browser>();
|
||||||
|
|
||||||
constructor(sdkLanguage: Language, isInternalPlaywright: boolean) {
|
constructor(options: PlaywrightOptions) {
|
||||||
super({ attribution: { isInternalPlaywright }, instrumentation: createInstrumentation() } as any, undefined, 'Playwright');
|
super({ attribution: {}, instrumentation: createInstrumentation() } as any, undefined, 'Playwright');
|
||||||
|
this.options = options;
|
||||||
|
this.attribution.playwright = this;
|
||||||
this.instrumentation.addListener({
|
this.instrumentation.addListener({
|
||||||
onBrowserOpen: browser => this._allBrowsers.add(browser),
|
onBrowserOpen: browser => this._allBrowsers.add(browser),
|
||||||
onBrowserClose: browser => this._allBrowsers.delete(browser),
|
onBrowserClose: browser => this._allBrowsers.delete(browser),
|
||||||
|
|
@ -52,17 +61,12 @@ export class Playwright extends SdkObject {
|
||||||
debugLogger.log(logName as any, message);
|
debugLogger.log(logName as any, message);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
this.options = {
|
this.chromium = new Chromium(this);
|
||||||
rootSdkObject: this,
|
this.firefox = new Firefox(this);
|
||||||
selectors: new Selectors(),
|
this.webkit = new WebKit(this);
|
||||||
sdkLanguage: sdkLanguage,
|
this.electron = new Electron(this);
|
||||||
};
|
this.android = new Android(this, new AdbBackend());
|
||||||
this.chromium = new Chromium(this.options);
|
this.selectors = new Selectors();
|
||||||
this.firefox = new Firefox(this.options);
|
|
||||||
this.webkit = new WebKit(this.options);
|
|
||||||
this.electron = new Electron(this.options);
|
|
||||||
this.android = new Android(new AdbBackend(), this.options);
|
|
||||||
this.selectors = this.options.selectors;
|
|
||||||
this.debugController = new DebugController(this);
|
this.debugController = new DebugController(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,6 +83,6 @@ export class Playwright extends SdkObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPlaywright(sdkLanguage: Language, isInternalPlaywright: boolean = false) {
|
export function createPlaywright(options: PlaywrightOptions) {
|
||||||
return new Playwright(sdkLanguage, isInternalPlaywright);
|
return new Playwright(options);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ class ContextRecorder extends EventEmitter {
|
||||||
this._context = context;
|
this._context = context;
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._recorderSources = [];
|
this._recorderSources = [];
|
||||||
const language = params.language || context._browser.options.sdkLanguage;
|
const language = params.language || context.attribution.playwright.options.sdkLanguage;
|
||||||
this.setOutput(language, params.outputFile);
|
this.setOutput(language, params.outputFile);
|
||||||
const generator = new CodeGenerator(context._browser.options.name, params.mode === 'recording', params.launchOptions || {}, params.contextOptions || {}, params.device, params.saveStorage);
|
const generator = new CodeGenerator(context._browser.options.name, params.mode === 'recording', params.launchOptions || {}, params.contextOptions || {}, params.device, params.saveStorage);
|
||||||
generator.on('change', () => {
|
generator.on('change', () => {
|
||||||
|
|
|
||||||
|
|
@ -114,9 +114,9 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async open(recorder: Recorder, inspectedContext: BrowserContext, handleSIGINT: boolean | undefined): Promise<IRecorderApp> {
|
static async open(recorder: Recorder, inspectedContext: BrowserContext, handleSIGINT: boolean | undefined): Promise<IRecorderApp> {
|
||||||
const sdkLanguage = inspectedContext._browser.options.sdkLanguage;
|
const sdkLanguage = inspectedContext.attribution.playwright.options.sdkLanguage;
|
||||||
const headed = !!inspectedContext._browser.options.headful;
|
const headed = !!inspectedContext._browser.options.headful;
|
||||||
const recorderPlaywright = (require('../playwright').createPlaywright as typeof import('../playwright').createPlaywright)('javascript', true);
|
const recorderPlaywright = (require('../playwright').createPlaywright as typeof import('../playwright').createPlaywright)({ sdkLanguage: 'javascript', isInternalPlaywright: true });
|
||||||
const args = [
|
const args = [
|
||||||
'--app=data:text/html,',
|
'--app=data:text/html,',
|
||||||
'--window-size=600,600',
|
'--window-size=600,600',
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
options: {},
|
options: {},
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
wallTime: 0,
|
wallTime: 0,
|
||||||
sdkLanguage: (context as BrowserContext)?._browser?.options?.sdkLanguage,
|
sdkLanguage: context.attribution.playwright.options.sdkLanguage,
|
||||||
testIdAttributeName
|
testIdAttributeName
|
||||||
};
|
};
|
||||||
if (context instanceof BrowserContext) {
|
if (context instanceof BrowserContext) {
|
||||||
|
|
@ -119,7 +119,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
throw new Error('Cannot start tracing while stopping');
|
throw new Error('Cannot start tracing while stopping');
|
||||||
|
|
||||||
// Re-write for testing.
|
// Re-write for testing.
|
||||||
this._contextCreatedEvent.sdkLanguage = (this._context as BrowserContext)?._browser?.options?.sdkLanguage;
|
this._contextCreatedEvent.sdkLanguage = this._context.attribution.playwright.options.sdkLanguage;
|
||||||
|
|
||||||
if (this._state) {
|
if (this._state) {
|
||||||
const o = this._state.options;
|
const o = this._state.options;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ export async function showTraceViewer(traceUrls: string[], browserName: string,
|
||||||
|
|
||||||
const urlPrefix = await server.start({ preferredPort: port, host });
|
const urlPrefix = await server.start({ preferredPort: port, host });
|
||||||
|
|
||||||
const traceViewerPlaywright = createPlaywright('javascript', true);
|
const traceViewerPlaywright = createPlaywright({ sdkLanguage: 'javascript', isInternalPlaywright: true });
|
||||||
const traceViewerBrowser = isUnderTest() ? 'chromium' : browserName;
|
const traceViewerBrowser = isUnderTest() ? 'chromium' : browserName;
|
||||||
const args = traceViewerBrowser === 'chromium' ? [
|
const args = traceViewerBrowser === 'chromium' ? [
|
||||||
'--app=data:text/html,',
|
'--app=data:text/html,',
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,19 @@ import path from 'path';
|
||||||
import { kBrowserCloseMessageId } from './wkConnection';
|
import { kBrowserCloseMessageId } from './wkConnection';
|
||||||
import { BrowserType, kNoXServerRunningError } from '../browserType';
|
import { BrowserType, kNoXServerRunningError } from '../browserType';
|
||||||
import type { ConnectionTransport } from '../transport';
|
import type { ConnectionTransport } from '../transport';
|
||||||
import type { BrowserOptions, PlaywrightOptions } from '../browser';
|
import type { BrowserOptions } from '../browser';
|
||||||
import type * as types from '../types';
|
import type * as types from '../types';
|
||||||
import { rewriteErrorMessage } from '../../utils/stackTrace';
|
import { rewriteErrorMessage } from '../../utils/stackTrace';
|
||||||
import { wrapInASCIIBox } from '../../utils';
|
import { wrapInASCIIBox } from '../../utils';
|
||||||
|
import type { SdkObject } from '../instrumentation';
|
||||||
|
|
||||||
export class WebKit extends BrowserType {
|
export class WebKit extends BrowserType {
|
||||||
constructor(playwrightOptions: PlaywrightOptions) {
|
constructor(parent: SdkObject) {
|
||||||
super('webkit', playwrightOptions);
|
super(parent, 'webkit');
|
||||||
}
|
}
|
||||||
|
|
||||||
_connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<WKBrowser> {
|
_connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<WKBrowser> {
|
||||||
return WKBrowser.connect(transport, options);
|
return WKBrowser.connect(this.attribution.playwright, transport, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env {
|
_amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import type { PageProxyMessageReceivedPayload } from './wkConnection';
|
||||||
import { kPageProxyMessageReceived, WKConnection, WKSession } from './wkConnection';
|
import { kPageProxyMessageReceived, WKConnection, WKSession } from './wkConnection';
|
||||||
import { WKPage } from './wkPage';
|
import { WKPage } from './wkPage';
|
||||||
import { kBrowserClosedError } from '../../common/errors';
|
import { kBrowserClosedError } from '../../common/errors';
|
||||||
|
import type { SdkObject } from '../instrumentation';
|
||||||
|
|
||||||
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15';
|
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15';
|
||||||
const BROWSER_VERSION = '16.4';
|
const BROWSER_VERSION = '16.4';
|
||||||
|
|
@ -42,8 +43,8 @@ export class WKBrowser extends Browser {
|
||||||
readonly _wkPages = new Map<string, WKPage>();
|
readonly _wkPages = new Map<string, WKPage>();
|
||||||
private readonly _eventListeners: RegisteredListener[];
|
private readonly _eventListeners: RegisteredListener[];
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise<WKBrowser> {
|
static async connect(parent: SdkObject, transport: ConnectionTransport, options: BrowserOptions): Promise<WKBrowser> {
|
||||||
const browser = new WKBrowser(transport, options);
|
const browser = new WKBrowser(parent, transport, options);
|
||||||
if ((options as any).__testHookOnConnectToBrowser)
|
if ((options as any).__testHookOnConnectToBrowser)
|
||||||
await (options as any).__testHookOnConnectToBrowser();
|
await (options as any).__testHookOnConnectToBrowser();
|
||||||
const promises: Promise<any>[] = [
|
const promises: Promise<any>[] = [
|
||||||
|
|
@ -58,8 +59,8 @@ export class WKBrowser extends Browser {
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, options: BrowserOptions) {
|
constructor(parent: SdkObject, transport: ConnectionTransport, options: BrowserOptions) {
|
||||||
super(options);
|
super(parent, options);
|
||||||
this._connection = new WKConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector);
|
this._connection = new WKConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector);
|
||||||
this._browserSession = this._connection.browserSession;
|
this._browserSession = this._connection.browserSession;
|
||||||
this._eventListeners = [
|
this._eventListeners = [
|
||||||
|
|
|
||||||
|
|
@ -774,7 +774,7 @@ test('should display waitForLoadState even if did not wait for it', async ({ run
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display language-specific locators', async ({ runAndTrace, server, page, toImpl }) => {
|
test('should display language-specific locators', async ({ runAndTrace, server, page, toImpl }) => {
|
||||||
toImpl(page.context())._browser.options.sdkLanguage = 'python';
|
toImpl(page).attribution.playwright.options.sdkLanguage = 'python';
|
||||||
const traceViewer = await runAndTrace(async () => {
|
const traceViewer = await runAndTrace(async () => {
|
||||||
await page.setContent('<button>Submit</button>');
|
await page.setContent('<button>Submit</button>');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
@ -783,6 +783,7 @@ test('should display language-specific locators', async ({ runAndTrace, server,
|
||||||
/page.setContent/,
|
/page.setContent/,
|
||||||
/locator.clickget_by_role\("button", name="Submit"\)/,
|
/locator.clickget_by_role\("button", name="Submit"\)/,
|
||||||
]);
|
]);
|
||||||
|
toImpl(page).attribution.playwright.options.sdkLanguage = 'javascript';
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should pick locator', async ({ page, runAndTrace, server }) => {
|
test('should pick locator', async ({ page, runAndTrace, server }) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue