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:
Dmitry Gozman 2020-07-13 15:26:09 -07:00 committed by GitHub
parent 2151757621
commit 9fd30e58e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 235 additions and 148 deletions

View File

@ -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;

View File

@ -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');
}
}

View File

@ -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];
}
}

View File

@ -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 {

View 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');
}
}

View 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 }));
}
}

View File

@ -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);

View File

@ -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 };

View File

@ -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);
});
}

View File

@ -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 }) {

View File

@ -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> {

View File

@ -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(),

View File

@ -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')

View File

@ -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'),

View File

@ -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();

View File

@ -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);
});
});

View File

@ -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);
});
});

View File

@ -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'],