mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(electron): return a ChromiumBrowserContext for electron (#4913)
This commit is contained in:
parent
df53cb2f83
commit
decf373c81
@ -27,6 +27,7 @@ import { Page } from './page';
|
||||
import { TimeoutSettings } from '../utils/timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import { EventEmitter } from 'events';
|
||||
import { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||
|
||||
type Direction = 'down' | 'up' | 'left' | 'right';
|
||||
type SpeedOptions = { speed?: number };
|
||||
@ -233,11 +234,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
|
||||
});
|
||||
}
|
||||
|
||||
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<BrowserContext> {
|
||||
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<ChromiumBrowserContext> {
|
||||
return this._wrapApiCall('androidDevice.launchBrowser', async () => {
|
||||
const contextOptions = await prepareBrowserContextOptions(options);
|
||||
const { context } = await this._channel.launchBrowser(contextOptions);
|
||||
return BrowserContext.from(context);
|
||||
return BrowserContext.from(context) as ChromiumBrowserContext;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
_pages = new Set<Page>();
|
||||
private _routes: { url: URLMatch, handler: network.RouteHandler }[] = [];
|
||||
readonly _browser: Browser | null = null;
|
||||
readonly _browserName: string;
|
||||
readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
|
||||
_timeoutSettings = new TimeoutSettings();
|
||||
_ownerPage: Page | undefined;
|
||||
@ -55,11 +54,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
return context ? BrowserContext.from(context) : null;
|
||||
}
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserContextInitializer, browserName: string) {
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserContextInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
if (parent instanceof Browser)
|
||||
this._browser = parent;
|
||||
this._browserName = browserName;
|
||||
|
||||
this._channel.on('bindingCall', ({binding}) => this._onBinding(BindingCall.from(binding)));
|
||||
this._channel.on('close', () => this._onClose());
|
||||
|
@ -27,9 +27,10 @@ import * as api from '../../types/types';
|
||||
export class ChromiumBrowserContext extends BrowserContext implements api.ChromiumBrowserContext {
|
||||
_backgroundPages = new Set<Page>();
|
||||
_serviceWorkers = new Set<Worker>();
|
||||
_isChromium = true;
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserContextInitializer) {
|
||||
super(parent, type, guid, initializer, 'chromium');
|
||||
super(parent, type, guid, initializer);
|
||||
this._channel.on('crBackgroundPage', ({ page }) => {
|
||||
const backgroundPage = Page.from(page);
|
||||
this._backgroundPages.add(backgroundPage);
|
||||
|
@ -173,11 +173,11 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
case 'BrowserContext': {
|
||||
const browserName = (initializer as channels.BrowserContextInitializer).browserName;
|
||||
if (browserName === 'chromium')
|
||||
const {isChromium} = (initializer as channels.BrowserContextInitializer);
|
||||
if (isChromium)
|
||||
result = new ChromiumBrowserContext(parent, type, guid, initializer);
|
||||
else
|
||||
result = new BrowserContext(parent, type, guid, initializer, browserName);
|
||||
result = new BrowserContext(parent, type, guid, initializer);
|
||||
break;
|
||||
}
|
||||
case 'BrowserType':
|
||||
|
@ -46,6 +46,7 @@ import { evaluationScript, urlMatches } from './clientHelper';
|
||||
import { isString, isRegExp, isObject, mkdirIfNeeded, headersObjectToArray } from '../utils/utils';
|
||||
import { isSafeCloseError } from '../utils/errors';
|
||||
import { Video } from './video';
|
||||
import type { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||
|
||||
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
|
||||
const mkdirAsync = util.promisify(fs.mkdir);
|
||||
@ -133,7 +134,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
|
||||
this._channel.on('webSocket', ({ webSocket }) => this.emit(Events.Page.WebSocket, WebSocket.from(webSocket)));
|
||||
this._channel.on('worker', ({ worker }) => this._onWorker(Worker.from(worker)));
|
||||
|
||||
if (this._browserContext._browserName === 'chromium') {
|
||||
if ((this._browserContext as ChromiumBrowserContext)._isChromium) {
|
||||
this.coverage = new ChromiumCoverage(this._channel);
|
||||
this.pdf = options => this._pdf(options);
|
||||
} else {
|
||||
|
@ -27,7 +27,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||
private _context: BrowserContext;
|
||||
|
||||
constructor(scope: DispatcherScope, context: BrowserContext) {
|
||||
super(scope, context, 'BrowserContext', { browserName: context._browser._options.name }, true);
|
||||
super(scope, context, 'BrowserContext', { isChromium: context._browser._options.isChromium }, true);
|
||||
this._context = context;
|
||||
|
||||
for (const page of context.pages())
|
||||
@ -131,7 +131,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||
}
|
||||
|
||||
async crNewCDPSession(params: channels.BrowserContextCrNewCDPSessionParams): Promise<channels.BrowserContextCrNewCDPSessionResult> {
|
||||
if (this._object._browser._options.name !== 'chromium')
|
||||
if (!this._object._browser._options.isChromium)
|
||||
throw new Error(`CDP session is only available in Chromium`);
|
||||
const crBrowserContext = this._object as CRBrowserContext;
|
||||
return { session: new CDPSessionDispatcher(this._scope, await crBrowserContext.newCDPSession((params.page as PageDispatcher)._object)) };
|
||||
|
@ -45,21 +45,21 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserIniti
|
||||
}
|
||||
|
||||
async crNewBrowserCDPSession(): Promise<channels.BrowserCrNewBrowserCDPSessionResult> {
|
||||
if (this._object._options.name !== 'chromium')
|
||||
if (!this._object._options.isChromium)
|
||||
throw new Error(`CDP session is only available in Chromium`);
|
||||
const crBrowser = this._object as CRBrowser;
|
||||
return { session: new CDPSessionDispatcher(this._scope, await crBrowser.newBrowserCDPSession()) };
|
||||
}
|
||||
|
||||
async crStartTracing(params: channels.BrowserCrStartTracingParams): Promise<void> {
|
||||
if (this._object._options.name !== 'chromium')
|
||||
if (!this._object._options.isChromium)
|
||||
throw new Error(`Tracing is only available in Chromium`);
|
||||
const crBrowser = this._object as CRBrowser;
|
||||
await crBrowser.startTracing(params.page ? (params.page as PageDispatcher)._object : undefined, params);
|
||||
}
|
||||
|
||||
async crStopTracing(): Promise<channels.BrowserCrStopTracingResult> {
|
||||
if (this._object._options.name !== 'chromium')
|
||||
if (!this._object._options.isChromium)
|
||||
throw new Error(`Tracing is only available in Chromium`);
|
||||
const crBrowser = this._object as CRBrowser;
|
||||
const buffer = await crBrowser.stopTracing();
|
||||
|
@ -530,7 +530,7 @@ export type BrowserCrStopTracingResult = {
|
||||
|
||||
// ----------- BrowserContext -----------
|
||||
export type BrowserContextInitializer = {
|
||||
browserName: string,
|
||||
isChromium: boolean,
|
||||
};
|
||||
export interface BrowserContextChannel extends Channel {
|
||||
on(event: 'bindingCall', callback: (params: BrowserContextBindingCallEvent) => void): this;
|
||||
|
@ -507,7 +507,7 @@ BrowserContext:
|
||||
type: interface
|
||||
|
||||
initializer:
|
||||
browserName: string
|
||||
isChromium: boolean
|
||||
|
||||
commands:
|
||||
|
||||
|
@ -256,6 +256,7 @@ export class AndroidDevice extends EventEmitter {
|
||||
|
||||
const browserOptions: BrowserOptions = {
|
||||
name: 'clank',
|
||||
isChromium: true,
|
||||
slowMo: 0,
|
||||
persistent: { ...options, noDefaultViewport: true },
|
||||
downloadsPath: undefined,
|
||||
|
@ -32,6 +32,7 @@ export interface BrowserProcess {
|
||||
|
||||
export type BrowserOptions = types.UIOptions & {
|
||||
name: string,
|
||||
isChromium: boolean,
|
||||
downloadsPath?: string,
|
||||
headful?: boolean,
|
||||
persistent?: types.BrowserContextOptions, // Undefined means no persistent context.
|
||||
|
@ -38,7 +38,7 @@ const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => f
|
||||
const DOWNLOADS_FOLDER = path.join(os.tmpdir(), 'playwright_downloads-');
|
||||
|
||||
export abstract class BrowserType {
|
||||
private _name: string;
|
||||
private _name: browserPaths.BrowserName;
|
||||
private _executablePath: string;
|
||||
private _browserDescriptor: browserPaths.BrowserDescriptor;
|
||||
readonly _browserPath: string;
|
||||
@ -88,6 +88,7 @@ export abstract class BrowserType {
|
||||
await (options as any).__testHookBeforeCreateBrowser();
|
||||
const browserOptions: BrowserOptions = {
|
||||
name: this._name,
|
||||
isChromium: this._name === 'chromium',
|
||||
slowMo: options.slowMo,
|
||||
persistent,
|
||||
headful: !options.headless,
|
||||
|
@ -191,6 +191,7 @@ export class Electron {
|
||||
};
|
||||
const browserOptions: BrowserOptions = {
|
||||
name: 'electron',
|
||||
isChromium: true,
|
||||
headful: true,
|
||||
persistent: { noDefaultViewport: true },
|
||||
browserProcess,
|
||||
|
@ -21,7 +21,7 @@ import * as path from 'path';
|
||||
import { getUbuntuVersionSync } from './ubuntuVersion';
|
||||
import { getFromENV } from './utils';
|
||||
|
||||
export type BrowserName = 'chromium'|'webkit'|'firefox'|'clank';
|
||||
export type BrowserName = 'chromium'|'webkit'|'firefox';
|
||||
export type BrowserPlatform = 'win32'|'win64'|'mac10.13'|'mac10.14'|'mac10.15'|'mac11.0'|'mac11.0-arm64'|'mac11.1'|'mac11.1-arm64'|'ubuntu18.04'|'ubuntu20.04';
|
||||
export type BrowserDescriptor = {
|
||||
name: BrowserName,
|
||||
|
@ -48,4 +48,12 @@ if (process.env.PW_ANDROID_TESTS) {
|
||||
await page.close();
|
||||
await context.close();
|
||||
});
|
||||
it('should be able to send CDP messages', async ({ device }) => {
|
||||
const context = await device.launchBrowser();
|
||||
const [page] = context.pages();
|
||||
const client = await context.newCDPSession(page);
|
||||
await client.send('Runtime.enable');
|
||||
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
||||
expect(evalResponse.result.value).toBe(3);
|
||||
});
|
||||
}
|
||||
|
@ -124,4 +124,12 @@ describe('electron app', (suite, { browserName }) => {
|
||||
const clipboardContentRead = await application.evaluate(async ({clipboard}) => clipboard.readText());
|
||||
await expect(clipboardContentRead).toEqual(clipboardContentToWrite);
|
||||
});
|
||||
|
||||
it('should be able to send CDP messages', async ({application, window}) => {
|
||||
const context = await application.context();
|
||||
const client = await context.newCDPSession(window);
|
||||
await client.send('Runtime.enable');
|
||||
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
||||
expect(evalResponse.result.value).toBe(3);
|
||||
});
|
||||
});
|
||||
|
4
types/android.d.ts
vendored
4
types/android.d.ts
vendored
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { BrowserContextOptions, BrowserContext, Page } from './types';
|
||||
import { BrowserContextOptions, Page, ChromiumBrowserContext } from './types';
|
||||
|
||||
export interface Android extends EventEmitter {
|
||||
setDefaultTimeout(timeout: number): void;
|
||||
@ -37,7 +37,7 @@ export interface AndroidDevice extends EventEmitter {
|
||||
open(command: string): Promise<AndroidSocket>;
|
||||
installApk(file: string | Buffer, options?: { args?: string[] }): Promise<void>;
|
||||
push(file: string | Buffer, path: string, options?: { mode?: number }): Promise<void>;
|
||||
launchBrowser(options?: BrowserContextOptions & { pkg?: string }): Promise<BrowserContext>;
|
||||
launchBrowser(options?: BrowserContextOptions & { pkg?: string }): Promise<ChromiumBrowserContext>;
|
||||
close(): Promise<void>;
|
||||
|
||||
wait(selector: AndroidSelector, options?: { state?: 'gone' } & { timeout?: number }): Promise<void>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user