mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 21:53:35 +03:00
feat(rpc): ensure feature-detection works as before (#2898)
For this, some tests are migrated from skip() to feature detection, like our users would do.
This commit is contained in:
parent
2151757621
commit
9fd30e58e2
@ -98,11 +98,7 @@ export interface BrowserContextChannel extends Channel {
|
||||
on(event: 'crServiceWorker', callback: (params: WorkerChannel) => void): this;
|
||||
crNewCDPSession(params: { page: PageChannel }): Promise<CDPSessionChannel>;
|
||||
}
|
||||
export type BrowserContextInitializer = {
|
||||
pages: PageChannel[],
|
||||
crBackgroundPages: PageChannel[],
|
||||
crServiceWorkers: WorkerChannel[],
|
||||
};
|
||||
export type BrowserContextInitializer = {};
|
||||
|
||||
|
||||
export interface PageChannel extends Channel {
|
||||
@ -117,7 +113,6 @@ export interface PageChannel extends Channel {
|
||||
on(event: 'frameAttached', callback: (params: FrameChannel) => void): this;
|
||||
on(event: 'frameDetached', callback: (params: FrameChannel) => void): this;
|
||||
on(event: 'frameNavigated', callback: (params: { frame: FrameChannel, url: string, name: string }) => void): this;
|
||||
on(event: 'frameNavigated', callback: (params: { frame: FrameChannel, url: string, name: string }) => void): this;
|
||||
on(event: 'load', callback: () => void): this;
|
||||
on(event: 'pageError', callback: (params: { error: types.Error }) => void): this;
|
||||
on(event: 'popup', callback: (params: PageChannel) => void): this;
|
||||
|
@ -20,14 +20,15 @@ import { BrowserContext } from './browserContext';
|
||||
import { Page } from './page';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Events } from '../../events';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { LoggerSink } from '../../loggerSink';
|
||||
import { BrowserType } from './browserType';
|
||||
|
||||
export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||
readonly _contexts = new Set<BrowserContext>();
|
||||
private _isConnected = true;
|
||||
private _isClosedOrClosing = false;
|
||||
private _closedPromise: Promise<void>;
|
||||
readonly _browserType: BrowserType;
|
||||
|
||||
static from(browser: BrowserChannel): Browser {
|
||||
return (browser as any)._object;
|
||||
@ -39,6 +40,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserInitializer) {
|
||||
super(parent, type, guid, initializer, true);
|
||||
this._browserType = parent as BrowserType;
|
||||
this._channel.on('close', () => {
|
||||
this._isConnected = false;
|
||||
this.emit(Events.Browser.Disconnected);
|
||||
@ -54,7 +56,6 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||
const context = BrowserContext.from(await this._channel.newContext(options));
|
||||
this._contexts.add(context);
|
||||
context._logger = logger || this._logger;
|
||||
context._browser = this;
|
||||
return context;
|
||||
}
|
||||
|
||||
@ -81,16 +82,4 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||
}
|
||||
await this._closedPromise;
|
||||
}
|
||||
|
||||
async newBrowserCDPSession(): Promise<CDPSession> {
|
||||
return CDPSession.from(await this._channel.crNewBrowserCDPSession());
|
||||
}
|
||||
|
||||
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
|
||||
await this._channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<Buffer> {
|
||||
return Buffer.from(await this._channel.crStopTracing(), 'base64');
|
||||
}
|
||||
}
|
||||
|
@ -25,16 +25,13 @@ import { helper } from '../../helper';
|
||||
import { Browser } from './browser';
|
||||
import { Events } from '../../events';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Events as ChromiumEvents } from '../../chromium/events';
|
||||
import { Worker } from './worker';
|
||||
import { BrowserType } from './browserType';
|
||||
|
||||
export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
|
||||
_pages = new Set<Page>();
|
||||
_crBackgroundPages = new Set<Page>();
|
||||
_crServiceWorkers = new Set<Worker>();
|
||||
private _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
|
||||
_browser: Browser | undefined;
|
||||
readonly _browser: Browser | undefined;
|
||||
readonly _browserType: BrowserType;
|
||||
readonly _bindings = new Map<string, frames.FunctionWithSource>();
|
||||
private _pendingWaitForEvents = new Map<(error: Error) => void, string>();
|
||||
_timeoutSettings = new TimeoutSettings();
|
||||
@ -52,43 +49,22 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserContextInitializer) {
|
||||
super(parent, type, guid, initializer, true);
|
||||
initializer.pages.forEach(p => {
|
||||
const page = Page.from(p);
|
||||
this._pages.add(page);
|
||||
page._setBrowserContext(this);
|
||||
});
|
||||
if (parent instanceof Browser) {
|
||||
this._browser = parent;
|
||||
this._browserType = this._browser._browserType;
|
||||
} else {
|
||||
// Launching persistent context does not produce a browser at all.
|
||||
this._browserType = parent as BrowserType;
|
||||
}
|
||||
|
||||
this._channel.on('bindingCall', bindingCall => this._onBinding(BindingCall.from(bindingCall)));
|
||||
this._channel.on('close', () => this._onClose());
|
||||
this._channel.on('page', page => this._onPage(Page.from(page)));
|
||||
this._channel.on('route', ({ route, request }) => this._onRoute(network.Route.from(route), network.Request.from(request)));
|
||||
this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));
|
||||
|
||||
initializer.crBackgroundPages.forEach(p => {
|
||||
const page = Page.from(p);
|
||||
this._crBackgroundPages.add(page);
|
||||
page._setBrowserContext(this);
|
||||
});
|
||||
this._channel.on('crBackgroundPage', pageChannel => {
|
||||
const page = Page.from(pageChannel);
|
||||
page._setBrowserContext(this);
|
||||
this._crBackgroundPages.add(page);
|
||||
this.emit(ChromiumEvents.CRBrowserContext.BackgroundPage, page);
|
||||
});
|
||||
initializer.crServiceWorkers.forEach(w => {
|
||||
const worker = Worker.from(w);
|
||||
worker._context = this;
|
||||
this._crServiceWorkers.add(worker);
|
||||
});
|
||||
this._channel.on('crServiceWorker', serviceWorkerChannel => {
|
||||
const worker = Worker.from(serviceWorkerChannel);
|
||||
worker._context = this;
|
||||
this._crServiceWorkers.add(worker);
|
||||
this.emit(ChromiumEvents.CRBrowserContext.ServiceWorker, worker);
|
||||
});
|
||||
}
|
||||
|
||||
private _onPage(page: Page): void {
|
||||
page._setBrowserContext(this);
|
||||
this._pages.add(page);
|
||||
this.emit(Events.BrowserContext.Page, page);
|
||||
}
|
||||
@ -234,16 +210,4 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
||||
}
|
||||
await this._closedPromise;
|
||||
}
|
||||
|
||||
async newCDPSession(page: Page): Promise<CDPSession> {
|
||||
return CDPSession.from(await this._channel.crNewCDPSession({ page: page._channel }));
|
||||
}
|
||||
|
||||
backgroundPages(): Page[] {
|
||||
return [...this._crBackgroundPages];
|
||||
}
|
||||
|
||||
serviceWorkers(): Worker[] {
|
||||
return [...this._crServiceWorkers];
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
||||
}
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserTypeInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
super(parent, type, guid, initializer, true);
|
||||
}
|
||||
|
||||
executablePath(): string {
|
||||
|
33
src/rpc/client/chromiumBrowser.ts
Normal file
33
src/rpc/client/chromiumBrowser.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Page } from './page';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Browser } from './browser';
|
||||
|
||||
export class ChromiumBrowser extends Browser {
|
||||
async newBrowserCDPSession(): Promise<CDPSession> {
|
||||
return CDPSession.from(await this._channel.crNewBrowserCDPSession());
|
||||
}
|
||||
|
||||
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
|
||||
await this._channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<Buffer> {
|
||||
return Buffer.from(await this._channel.crStopTracing(), 'base64');
|
||||
}
|
||||
}
|
56
src/rpc/client/chromiumBrowserContext.ts
Normal file
56
src/rpc/client/chromiumBrowserContext.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Page } from './page';
|
||||
import { BrowserContextInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Events as ChromiumEvents } from '../../chromium/events';
|
||||
import { Worker } from './worker';
|
||||
import { BrowserContext } from './browserContext';
|
||||
|
||||
export class ChromiumBrowserContext extends BrowserContext {
|
||||
_backgroundPages = new Set<Page>();
|
||||
_serviceWorkers = new Set<Worker>();
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserContextInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._channel.on('crBackgroundPage', pageChannel => {
|
||||
const page = Page.from(pageChannel);
|
||||
this._backgroundPages.add(page);
|
||||
this.emit(ChromiumEvents.CRBrowserContext.BackgroundPage, page);
|
||||
});
|
||||
this._channel.on('crServiceWorker', serviceWorkerChannel => {
|
||||
const worker = Worker.from(serviceWorkerChannel);
|
||||
worker._context = this;
|
||||
this._serviceWorkers.add(worker);
|
||||
this.emit(ChromiumEvents.CRBrowserContext.ServiceWorker, worker);
|
||||
});
|
||||
}
|
||||
|
||||
backgroundPages(): Page[] {
|
||||
return [...this._backgroundPages];
|
||||
}
|
||||
|
||||
serviceWorkers(): Worker[] {
|
||||
return [...this._serviceWorkers];
|
||||
}
|
||||
|
||||
async newCDPSession(page: Page): Promise<CDPSession> {
|
||||
return CDPSession.from(await this._channel.crNewCDPSession({ page: page._channel }));
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ import { BrowserServer } from './browserServer';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Playwright } from './playwright';
|
||||
import { Channel } from '../channels';
|
||||
import { ChromiumBrowser } from './chromiumBrowser';
|
||||
import { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||
|
||||
class Root extends ChannelOwner<Channel, {}> {
|
||||
constructor(connection: Connection) {
|
||||
@ -133,7 +135,10 @@ export class Connection {
|
||||
result = new BindingCall(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'browser':
|
||||
result = new Browser(parent, type, guid, initializer);
|
||||
if ((parent as BrowserType).name() === 'chromium')
|
||||
result = new ChromiumBrowser(parent, type, guid, initializer);
|
||||
else
|
||||
result = new Browser(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'browserServer':
|
||||
result = new BrowserServer(parent, type, guid, initializer);
|
||||
@ -145,7 +150,12 @@ export class Connection {
|
||||
result = new CDPSession(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'context':
|
||||
result = new BrowserContext(parent, type, guid, initializer);
|
||||
// Launching persistent context produces BrowserType parent directly for BrowserContext.
|
||||
const browserType = parent instanceof Browser ? parent._browserType : parent as BrowserType;
|
||||
if (browserType.name() === 'chromium')
|
||||
result = new ChromiumBrowserContext(parent, type, guid, initializer);
|
||||
else
|
||||
result = new BrowserContext(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'consoleMessage':
|
||||
result = new ConsoleMessage(parent, type, guid, initializer);
|
||||
|
@ -40,8 +40,7 @@ import { Buffer } from 'buffer';
|
||||
import { Coverage } from './coverage';
|
||||
|
||||
export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
|
||||
private _browserContext: BrowserContext | undefined;
|
||||
private _browserContext: BrowserContext;
|
||||
_ownedContext: BrowserContext | undefined;
|
||||
|
||||
private _mainFrame: Frame;
|
||||
@ -54,10 +53,12 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
readonly accessibility: Accessibility;
|
||||
readonly keyboard: Keyboard;
|
||||
readonly mouse: Mouse;
|
||||
readonly coverage: Coverage;
|
||||
coverage: Coverage | null = null;
|
||||
pdf?: (options?: types.PDFOptions) => Promise<Buffer>;
|
||||
|
||||
readonly _bindings = new Map<string, FunctionWithSource>();
|
||||
private _pendingWaitForEvents = new Map<(error: Error) => void, string>();
|
||||
private _timeoutSettings = new TimeoutSettings();
|
||||
private _timeoutSettings: TimeoutSettings;
|
||||
_isPageCall = false;
|
||||
|
||||
static from(page: PageChannel): Page {
|
||||
@ -70,10 +71,12 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: PageInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._browserContext = parent as BrowserContext;
|
||||
this._timeoutSettings = new TimeoutSettings(this._browserContext._timeoutSettings);
|
||||
|
||||
this.accessibility = new Accessibility(this._channel);
|
||||
this.keyboard = new Keyboard(this._channel);
|
||||
this.mouse = new Mouse(this._channel);
|
||||
this.coverage = new Coverage(this._channel);
|
||||
|
||||
this._mainFrame = Frame.from(initializer.mainFrame);
|
||||
this._mainFrame._page = this;
|
||||
@ -101,11 +104,11 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
this._channel.on('response', response => this.emit(Events.Page.Response, Response.from(response)));
|
||||
this._channel.on('route', ({ route, request }) => this._onRoute(Route.from(route), Request.from(request)));
|
||||
this._channel.on('worker', worker => this._onWorker(Worker.from(worker)));
|
||||
}
|
||||
|
||||
_setBrowserContext(context: BrowserContext) {
|
||||
this._browserContext = context;
|
||||
this._timeoutSettings = new TimeoutSettings(context._timeoutSettings);
|
||||
if (this._browserContext._browserType.name() === 'chromium') {
|
||||
this.coverage = new Coverage(this._channel);
|
||||
this.pdf = options => this._pdf(options);
|
||||
}
|
||||
}
|
||||
|
||||
private _onRequestFailed(request: Request, failureText: string | null) {
|
||||
@ -142,7 +145,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._browserContext!._onRoute(route, request);
|
||||
this._browserContext._onRoute(route, request);
|
||||
}
|
||||
|
||||
async _onBinding(bindingCall: BindingCall) {
|
||||
@ -151,7 +154,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
bindingCall.call(func);
|
||||
return;
|
||||
}
|
||||
this._browserContext!._onBinding(bindingCall);
|
||||
this._browserContext._onBinding(bindingCall);
|
||||
}
|
||||
|
||||
_onWorker(worker: Worker): void {
|
||||
@ -162,7 +165,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
|
||||
private _onClose() {
|
||||
this._closed = true;
|
||||
this._browserContext!._pages.delete(this);
|
||||
this._browserContext._pages.delete(this);
|
||||
this._rejectPendingOperations(false);
|
||||
this.emit(Events.Page.Close);
|
||||
}
|
||||
@ -184,7 +187,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
}
|
||||
|
||||
context(): BrowserContext {
|
||||
return this._browserContext!;
|
||||
return this._browserContext;
|
||||
}
|
||||
|
||||
async opener(): Promise<Page | null> {
|
||||
@ -280,7 +283,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
async exposeBinding(name: string, binding: FunctionWithSource) {
|
||||
if (this._bindings.has(name))
|
||||
throw new Error(`Function "${name}" has been already registered`);
|
||||
if (this._browserContext!._bindings.has(name))
|
||||
if (this._browserContext._bindings.has(name))
|
||||
throw new Error(`Function "${name}" has been already registered in the browser context`);
|
||||
this._bindings.set(name, binding);
|
||||
await this._channel.exposeBinding({ name });
|
||||
@ -499,7 +502,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||
return this;
|
||||
}
|
||||
|
||||
async pdf(options: types.PDFOptions = {}): Promise<Buffer> {
|
||||
async _pdf(options: types.PDFOptions = {}): Promise<Buffer> {
|
||||
const transportOptions: PDFOptions = { ...options } as PDFOptions;
|
||||
if (transportOptions.margin)
|
||||
transportOptions.margin = { ...transportOptions.margin };
|
||||
|
@ -21,6 +21,7 @@ import { ChannelOwner } from './channelOwner';
|
||||
import { Func1, JSHandle, parseResult, serializeArgument, SmartHandle } from './jsHandle';
|
||||
import { Page } from './page';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||
|
||||
export class Worker extends ChannelOwner<WorkerChannel, WorkerInitializer> {
|
||||
_page: Page | undefined; // Set for web workers.
|
||||
@ -36,7 +37,7 @@ export class Worker extends ChannelOwner<WorkerChannel, WorkerInitializer> {
|
||||
if (this._page)
|
||||
this._page._workers.delete(this);
|
||||
if (this._context)
|
||||
this._context._crServiceWorkers.delete(this);
|
||||
(this._context as ChromiumBrowserContext)._serviceWorkers.delete(this);
|
||||
this.emit(Events.Worker.Close, this);
|
||||
});
|
||||
}
|
||||
|
@ -30,26 +30,25 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
|
||||
private _context: BrowserContextBase;
|
||||
|
||||
constructor(scope: DispatcherScope, context: BrowserContextBase) {
|
||||
let crBackgroundPages: PageDispatcher[] = [];
|
||||
let crServiceWorkers: WorkerDispatcher[] = [];
|
||||
if (context._browserBase._options.name === 'chromium') {
|
||||
crBackgroundPages = (context as CRBrowserContext).backgroundPages().map(p => new PageDispatcher(scope, p));
|
||||
context.on(ChromiumEvents.CRBrowserContext.BackgroundPage, page => this._dispatchEvent('crBackgroundPage', new PageDispatcher(this._scope, page)));
|
||||
crServiceWorkers = (context as CRBrowserContext).serviceWorkers().map(w => new WorkerDispatcher(scope, w));
|
||||
context.on(ChromiumEvents.CRBrowserContext.ServiceWorker, serviceWorker => this._dispatchEvent('crServiceWorker', new WorkerDispatcher(this._scope, serviceWorker)));
|
||||
}
|
||||
|
||||
super(scope, context, 'context', {
|
||||
pages: context.pages().map(p => new PageDispatcher(scope, p)),
|
||||
crBackgroundPages,
|
||||
crServiceWorkers,
|
||||
}, true);
|
||||
super(scope, context, 'context', {}, true);
|
||||
this._context = context;
|
||||
|
||||
for (const page of context.pages())
|
||||
this._dispatchEvent('page', new PageDispatcher(this._scope, page));
|
||||
context.on(Events.BrowserContext.Page, page => this._dispatchEvent('page', new PageDispatcher(this._scope, page)));
|
||||
context.on(Events.BrowserContext.Close, () => {
|
||||
this._dispatchEvent('close');
|
||||
this._dispose();
|
||||
});
|
||||
|
||||
if (context._browserBase._options.name === 'chromium') {
|
||||
for (const page of (context as CRBrowserContext).backgroundPages())
|
||||
this._dispatchEvent('crBackgroundPage', new PageDispatcher(this._scope, page));
|
||||
context.on(ChromiumEvents.CRBrowserContext.BackgroundPage, page => this._dispatchEvent('crBackgroundPage', new PageDispatcher(this._scope, page)));
|
||||
for (const serviceWorker of (context as CRBrowserContext).serviceWorkers())
|
||||
this._dispatchEvent('crServiceWorker', new WorkerDispatcher(this._scope, serviceWorker));
|
||||
context.on(ChromiumEvents.CRBrowserContext.ServiceWorker, serviceWorker => this._dispatchEvent('crServiceWorker', new WorkerDispatcher(this._scope, serviceWorker)));
|
||||
}
|
||||
}
|
||||
|
||||
async setDefaultNavigationTimeoutNoReply(params: { timeout: number }) {
|
||||
|
@ -29,7 +29,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
||||
super(scope, browserType, 'browserType', {
|
||||
executablePath: browserType.executablePath(),
|
||||
name: browserType.name()
|
||||
}, false, browserType.name());
|
||||
}, true, browserType.name());
|
||||
}
|
||||
|
||||
async launch(params: types.LaunchOptions): Promise<BrowserChannel> {
|
||||
|
@ -37,6 +37,8 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
||||
private _page: Page;
|
||||
|
||||
constructor(scope: DispatcherScope, page: Page) {
|
||||
// TODO: theoretically, there could be more than one frame already.
|
||||
// If we split pageCreated and pageReady, there should be no main frame during pageCreated.
|
||||
super(scope, page, 'page', {
|
||||
mainFrame: FrameDispatcher.from(scope, page.mainFrame()),
|
||||
viewportSize: page.viewportSize(),
|
||||
|
@ -22,15 +22,16 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
expect(!!browser._connection).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should scope context handles', async({browser, server}) => {
|
||||
it('should scope context handles', async({browserType, browser, server}) => {
|
||||
const GOLDEN_PRECONDITION = {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [] }
|
||||
] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [] },
|
||||
]
|
||||
};
|
||||
await expectScopeState(browser, GOLDEN_PRECONDITION);
|
||||
@ -41,18 +42,19 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
await expectScopeState(browser, {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'context', objects: [
|
||||
{ _guid: 'frame' },
|
||||
{ _guid: 'page' },
|
||||
{ _guid: 'request' },
|
||||
{ _guid: 'response' },
|
||||
]},
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'context', objects: [
|
||||
{ _guid: 'frame' },
|
||||
{ _guid: 'page' },
|
||||
{ _guid: 'request' },
|
||||
{ _guid: 'response' },
|
||||
]},
|
||||
] },
|
||||
] },
|
||||
{ _guid: 'playwright' },
|
||||
]
|
||||
});
|
||||
|
||||
@ -64,11 +66,12 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
const GOLDEN_PRECONDITION = {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [] }
|
||||
] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [] },
|
||||
]
|
||||
};
|
||||
await expectScopeState(browserType, GOLDEN_PRECONDITION);
|
||||
@ -77,13 +80,14 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
await expectScopeState(browserType, {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'cdpSession', objects: [] },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'cdpSession', objects: [] },
|
||||
] },
|
||||
] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'playwright' },
|
||||
]
|
||||
});
|
||||
|
||||
@ -95,11 +99,12 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
const GOLDEN_PRECONDITION = {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [] }
|
||||
] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [] },
|
||||
]
|
||||
};
|
||||
await expectScopeState(browserType, GOLDEN_PRECONDITION);
|
||||
@ -109,14 +114,15 @@ describe.skip(!CHANNEL)('Channels', function() {
|
||||
await expectScopeState(browserType, {
|
||||
_guid: '',
|
||||
objects: [
|
||||
{ _guid: 'chromium' },
|
||||
{ _guid: 'firefox' },
|
||||
{ _guid: 'webkit' },
|
||||
{ _guid: 'playwright' },
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'context', objects: [] },
|
||||
{ _guid: 'browserType', objects: [
|
||||
{ _guid: 'browser', objects: [
|
||||
{ _guid: 'context', objects: [] }
|
||||
] },
|
||||
{ _guid: 'browser', objects: [] },
|
||||
] },
|
||||
{ _guid: 'browser', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'browserType', objects: [] },
|
||||
{ _guid: 'playwright' },
|
||||
]
|
||||
});
|
||||
|
||||
@ -152,6 +158,8 @@ function trimGuids(object) {
|
||||
const result = {};
|
||||
for (const key in object)
|
||||
result[key] = trimGuids(object[key]);
|
||||
if (result._guid === 'chromium' || result._guid === 'firefox' || result._guid === 'webkit')
|
||||
result._guid = 'browserType';
|
||||
return result;
|
||||
}
|
||||
if (typeof object === 'string')
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = require('../utils').testOptions(browserType);
|
||||
|
||||
describe('ChromiumBrowserContext', function() {
|
||||
describe('Service Worker', function() {
|
||||
it('should create a worker from a service worker', async({browser, page, server, context}) => {
|
||||
const [worker] = await Promise.all([
|
||||
context.waitForEvent('serviceworker'),
|
||||
|
@ -14,10 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = require('../utils').testOptions(browserType);
|
||||
const {FFOX, CHROMIUM, WEBKIT} = require('./utils').testOptions(browserType);
|
||||
|
||||
describe('JSCoverage', function() {
|
||||
describe.skip(CHROMIUM)('Page.coverage missing', function() {
|
||||
it('should work', async function({page, server}) {
|
||||
expect(page.coverage).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip(!CHROMIUM)('JSCoverage', function() {
|
||||
it('should work', async function({browserType, page, server}) {
|
||||
await page.coverage.startJSCoverage();
|
||||
await page.goto(server.PREFIX + '/jscoverage/simple.html', { waitUntil: 'load' });
|
||||
const coverage = await page.coverage.stopJSCoverage();
|
||||
@ -88,8 +94,8 @@ describe('JSCoverage', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('CSSCoverage', function() {
|
||||
it('should work', async function({page, server}) {
|
||||
describe.skip(!CHROMIUM)('CSSCoverage', function() {
|
||||
it('should work', async function({browserType, page, server}) {
|
||||
await page.coverage.startCSSCoverage();
|
||||
await page.goto(server.PREFIX + '/csscoverage/simple.html');
|
||||
const coverage = await page.coverage.stopCSSCoverage();
|
@ -374,4 +374,19 @@ describe('launchPersistentContext()', function() {
|
||||
await close(state);
|
||||
expect(closed).toBe(true);
|
||||
});
|
||||
it.skip(!CHROMIUM)('coverage should work', async state => {
|
||||
const { page, server } = await launch(state);
|
||||
await page.coverage.startJSCoverage();
|
||||
await page.goto(server.PREFIX + '/jscoverage/simple.html', { waitUntil: 'load' });
|
||||
const coverage = await page.coverage.stopJSCoverage();
|
||||
expect(coverage.length).toBe(1);
|
||||
expect(coverage[0].url).toContain('/jscoverage/simple.html');
|
||||
expect(coverage[0].functions.find(f => f.functionName === 'foo').ranges[0].count).toEqual(1);
|
||||
await close(state);
|
||||
});
|
||||
it.skip(CHROMIUM)('coverage should be missing', async state => {
|
||||
const { page } = await launch(state);
|
||||
expect(page.coverage).toBe(null);
|
||||
await close(state);
|
||||
});
|
||||
});
|
||||
|
@ -16,10 +16,10 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {FFOX, CHROMIUM, WEBKIT, OUTPUT_DIR} = require('../utils').testOptions(browserType);
|
||||
const {FFOX, CHROMIUM, WEBKIT, OUTPUT_DIR} = require('./utils').testOptions(browserType);
|
||||
|
||||
// Printing to pdf is currently only supported in headless
|
||||
describe.skip(!HEADLESS)('Page.pdf', function() {
|
||||
// Printing to pdf is currently only supported in headless chromium.
|
||||
describe.skip(!(HEADLESS && CHROMIUM))('Page.pdf', function() {
|
||||
it('should be able to save file', async({page, server}) => {
|
||||
const outputFile = path.join(OUTPUT_DIR, 'output.pdf');
|
||||
await page.pdf({path: outputFile});
|
||||
@ -27,3 +27,9 @@ describe.skip(!HEADLESS)('Page.pdf', function() {
|
||||
fs.unlinkSync(outputFile);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip(CHROMIUM)('Page.pdf missing', function() {
|
||||
it('should be able to save file', async({page, server}) => {
|
||||
expect(page.pdf).toBe(undefined);
|
||||
});
|
||||
});
|
@ -75,6 +75,7 @@ module.exports = {
|
||||
'./autowaiting.spec.js',
|
||||
'./click.spec.js',
|
||||
'./cookies.spec.js',
|
||||
'./coverage.spec.js',
|
||||
'./dialog.spec.js',
|
||||
'./dispatchevent.spec.js',
|
||||
'./download.spec.js',
|
||||
@ -90,6 +91,7 @@ module.exports = {
|
||||
'./navigation.spec.js',
|
||||
'./network.spec.js',
|
||||
'./page.spec.js',
|
||||
'./pdf.spec.js',
|
||||
'./queryselector.spec.js',
|
||||
'./screenshot.spec.js',
|
||||
'./waittask.spec.js',
|
||||
@ -105,8 +107,6 @@ module.exports = {
|
||||
{
|
||||
files: [
|
||||
'./chromium/chromium.spec.js',
|
||||
'./chromium/coverage.spec.js',
|
||||
'./chromium/pdf.spec.js',
|
||||
'./chromium/session.spec.js',
|
||||
],
|
||||
browsers: ['chromium'],
|
||||
|
Loading…
Reference in New Issue
Block a user