api: remove Chromium* classes (#6040)

This commit is contained in:
Pavel Feldman 2021-04-02 09:47:14 +08:00 committed by GitHub
parent d862deeadf
commit a7630c91d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 586 additions and 960 deletions

View File

@ -100,7 +100,7 @@ Either a path to the apk file, or apk file content.
Optional arguments to pass to the `shell:cmd package install` call. Defaults to `-r -t -S`.
## async method: AndroidDevice.launchBrowser
- returns: <[ChromiumBrowserContext]>
- returns: <[BrowserContext]>
Launches Chrome browser on the device, and returns its persistent context.

View File

@ -117,6 +117,16 @@ print(len(browser.contexts())) # prints `1`
Indicates that the browser is connected.
## async method: Browser.newBrowserCDPSession
* langs: js, python
- returns: <[CDPSession]>
:::note
CDP Sessions are only supported on Chromium-based browsers.
:::
Returns the newly created browser session.
## async method: Browser.newContext
- returns: <[BrowserContext]>
@ -189,6 +199,64 @@ testing frameworks should explicitly create [`method: Browser.newContext`] follo
### option: Browser.newPage.storageStatePath = %%-csharp-java-context-option-storage-state-path-%%
## async method: Browser.startTracing
* langs: js, python
:::note
Tracing is only supported on Chromium-based browsers.
:::
You can use [`method: Browser.startTracing`] and [`method: Browser.stopTracing`] to create a trace file that can
be opened in Chrome DevTools performance panel.
```js
await browser.startTracing(page, {path: 'trace.json'});
await page.goto('https://www.google.com');
await browser.stopTracing();
```
```python async
await browser.start_tracing(page, path="trace.json")
await page.goto("https://www.google.com")
await browser.stop_tracing()
```
```python sync
browser.start_tracing(page, path="trace.json")
page.goto("https://www.google.com")
browser.stop_tracing()
```
### param: Browser.startTracing.page
- `page` <[Page]>
Optional, if specified, tracing includes screenshots of the given page.
### option: Browser.startTracing.path
- `path` <[path]>
A path to write the trace file to.
### option: Browser.startTracing.screenshots
- `screenshots` <[boolean]>
captures screenshots in the trace.
### option: Browser.startTracing.categories
- `categories` <[Array]<[string]>>
specify custom categories to use instead of default.
## async method: Browser.stopTracing
* langs: js, python
- returns: <[Buffer]>
:::note
Tracing is only supported on Chromium-based browsers.
:::
Returns the buffer with trace data.
## method: Browser.version
- returns: <[string]>

View File

@ -49,6 +49,29 @@ page.goto("https://example.com")
context.close()
```
## event: BrowserContext.backgroundPage
* langs: js, python
- argument: <[Page]>
:::note
Only works with Chromium browser's persistent context.
:::
Emitted when new background page is created in the context.
```js
const backgroundPage = await context.waitForEvent('backgroundpage');
```
```python async
background_page = await context.wait_for_event("backgroundpage")
```
```python sync
background_page = context.wait_for_event("backgroundpage")
```
## event: BrowserContext.close
- argument: <[BrowserContext]>
@ -101,6 +124,16 @@ Use [`method: Page.waitForLoadState`] to wait until the page gets to a particula
cases).
:::
## event: BrowserContext.serviceWorker
* langs: js, python
- argument: <[Worker]>
:::note
Service workers are only supported on Chromium-based browsers.
:::
Emitted when new service worker is created in the context.
## async method: BrowserContext.addCookies
Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be
@ -199,6 +232,16 @@ Script to be evaluated in all pages in the browser context.
Optional argument to pass to [`param: script`] (only supported when passing a function).
## method: BrowserContext.backgroundPages
* langs: js, python
- returns: <[Array]<[Page]>>
:::note
Background pages are only supported on Chromium-based browsers.
:::
All existing background pages in the context.
## method: BrowserContext.browser
- returns: <[null]|[Browser]>
@ -630,6 +673,21 @@ A permission or an array of permissions to grant. Permissions can be one of the
The [origin] to grant permissions to, e.g. "https://example.com".
## async method: BrowserContext.newCDPSession
* langs: js, python
- returns: <[CDPSession]>
:::note
CDP sessions are only supported on Chromium-based browsers.
:::
Returns the newly created session.
### param: BrowserContext.newCDPSession.page
- `page` <[Page]>
Page to create new session for.
## async method: BrowserContext.newPage
- returns: <[Page]>
@ -742,6 +800,16 @@ handler function to route the request.
handler function to route the request.
## method: BrowserContext.serviceWorkers
* langs: js, python
- returns: <[Array]<[Worker]>>
:::note
Service workers are only supported on Chromium-based browsers.
:::
All existing service workers in the context.
## method: BrowserContext.setDefaultNavigationTimeout
This setting will change the default maximum navigation time for the following methods and related shortcuts:

View File

@ -181,7 +181,7 @@ Whether to run browser in headless mode. More details for
### option: BrowserType.launch.channel
- `channel` <[BrowserChannel]<"chrome"|"chrome-beta"|"chrome-dev"|"chrome-canary"|"msedge"|"msedge-beta"|"msedge-dev"|"msedge-canary">>
Browser distribution channel. Read more about using [Google Chrome and Microsoft Edge](./browsers#google-chrome--microsoft-edge).
Browser distribution channel. Read more about using [Google Chrome and Microsoft Edge](./browsers.md#google-chrome--microsoft-edge).
### option: BrowserType.launch.executablePath
- `executablePath` <[path]>

View File

@ -1,73 +0,0 @@
# class: ChromiumBrowser
* langs: js
* extends: [Browser]
Chromium-specific features including Tracing, service worker support, etc. You can use [`method:
ChromiumBrowser.startTracing`] and [`method: ChromiumBrowser.stopTracing`] to create a trace file which can be
opened in Chrome DevTools or [timeline viewer](https://chromedevtools.github.io/timeline-viewer/).
```js
await browser.startTracing(page, {path: 'trace.json'});
await page.goto('https://www.google.com');
await browser.stopTracing();
```
[ChromiumBrowser] can also be used for testing Chrome Extensions.
:::note
Extensions in Chrome / Chromium currently only work in non-headless mode.
:::
The following is code for getting a handle to the [background page](https://developer.chrome.com/extensions/background_pages) of an extension whose source is located in `./my-extension`:
```js
const { chromium } = require('playwright');
(async () => {
const pathToExtension = require('path').join(__dirname, 'my-extension');
const userDataDir = '/tmp/test-user-data-dir';
const browserContext = await chromium.launchPersistentContext(userDataDir,{
headless: false,
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
]
});
const backgroundPage = browserContext.backgroundPages()[0];
// Test the background page as you would any other page.
await browserContext.close();
})();
```
## async method: ChromiumBrowser.newBrowserCDPSession
- returns: <[CDPSession]>
Returns the newly created browser session.
## async method: ChromiumBrowser.startTracing
Only one trace can be active at a time per browser.
### param: ChromiumBrowser.startTracing.page
- `page` <[Page]>
Optional, if specified, tracing includes screenshots of the given page.
### option: ChromiumBrowser.startTracing.path
- `path` <[path]>
A path to write the trace file to.
### option: ChromiumBrowser.startTracing.screenshots
- `screenshots` <[boolean]>
captures screenshots in the trace.
### option: ChromiumBrowser.startTracing.categories
- `categories` <[Array]<[string]>>
specify custom categories to use instead of default.
## async method: ChromiumBrowser.stopTracing
- returns: <[Buffer]>
Returns the buffer with trace data.

View File

@ -1,51 +0,0 @@
# class: ChromiumBrowserContext
* langs: js, python
* extends: [BrowserContext]
Chromium-specific features including background pages, service worker support, etc.
```js
const backgroundPage = await context.waitForEvent('backgroundpage');
```
```python async
background_page = await context.wait_for_event("backgroundpage")
```
```python sync
background_page = context.wait_for_event("backgroundpage")
```
## event: ChromiumBrowserContext.backgroundPage
- argument: <[Page]>
Emitted when new background page is created in the context.
:::note
Only works with persistent context.
:::
## event: ChromiumBrowserContext.serviceWorker
- argument: <[Worker]>
Emitted when new service worker is created in the context.
## method: ChromiumBrowserContext.backgroundPages
- returns: <[Array]<[Page]>>
All existing background pages in the context.
## async method: ChromiumBrowserContext.newCDPSession
- returns: <[CDPSession]>
Returns the newly created session.
### param: ChromiumBrowserContext.newCDPSession.page
- `page` <[Page]>
Page to create new session for.
## method: ChromiumBrowserContext.serviceWorkers
- returns: <[Array]<[Worker]>>
All existing service workers in the context.

View File

@ -1,10 +1,14 @@
# class: ChromiumCoverage
# class: Coverage
* langs: js
Coverage gathers information about parts of JavaScript and CSS that were used by the page.
An example of using JavaScript coverage to produce Istanbul report for page load:
:::note
Coverage APIs are only supported on Chromium-based browsers.
:::
```js
const { chromium } = require('playwright');
const v8toIstanbul = require('v8-to-istanbul');
@ -25,16 +29,16 @@ const v8toIstanbul = require('v8-to-istanbul');
})();
```
## async method: ChromiumCoverage.startCSSCoverage
## async method: Coverage.startCSSCoverage
Returns coverage is started
### option: ChromiumCoverage.startCSSCoverage.resetOnNavigation
### option: Coverage.startCSSCoverage.resetOnNavigation
- `resetOnNavigation` <[boolean]>
Whether to reset coverage on every navigation. Defaults to `true`.
## async method: ChromiumCoverage.startJSCoverage
## async method: Coverage.startJSCoverage
Returns coverage is started
@ -44,17 +48,17 @@ on the page using `eval` or `new Function`. If [`option: reportAnonymousScripts`
will have `__playwright_evaluation_script__` as their URL.
:::
### option: ChromiumCoverage.startJSCoverage.resetOnNavigation
### option: Coverage.startJSCoverage.resetOnNavigation
- `resetOnNavigation` <[boolean]>
Whether to reset coverage on every navigation. Defaults to `true`.
### option: ChromiumCoverage.startJSCoverage.reportAnonymousScripts
### option: Coverage.startJSCoverage.reportAnonymousScripts
- `reportAnonymousScripts` <[boolean]>
Whether anonymous scripts generated by the page should be reported. Defaults to `false`.
## async method: ChromiumCoverage.stopCSSCoverage
## async method: Coverage.stopCSSCoverage
- returns: <[Array]<[Object]>>
- `url` <[string]> StyleSheet URL
- `text` <[string]> StyleSheet content, if available.
@ -68,7 +72,7 @@ Returns the array of coverage reports for all stylesheets
CSS Coverage doesn't include dynamically injected style tags without sourceURLs.
:::
## async method: ChromiumCoverage.stopJSCoverage
## async method: Coverage.stopJSCoverage
- returns: <[Array]<[Object]>>
- `url` <[string]> Script URL
- `scriptId` <[string]> Script ID

View File

@ -73,7 +73,7 @@ Returns download error if any. Will wait for the download to finish if necessary
- returns: <[null]|[path]>
Returns path to the downloaded file in case of successful download. The method will
wait for the download to finish if necessary. The method throws when connected remotely via [`method: BrowserType.connect`].
wait for the download to finish if necessary. The method throws when connected remotely.
## async method: Download.saveAs

View File

@ -1,5 +0,0 @@
# class: FirefoxBrowser
* langs: js
* extends: [Browser]
Firefox browser instance does not expose Firefox-specific features.

View File

@ -597,10 +597,13 @@ Get the browser context that the page belongs to.
## property: Page.coverage
* langs: js
- type: <[null]|[ChromiumCoverage]>
- type: <[Coverage]>
Browser-specific Coverage implementation, only available for Chromium atm. See
[ChromiumCoverage](#class-chromiumcoverage) for more details.
:::note
Only available for Chromium atm.
:::
Browser-specific Coverage implementation. See [Coverage](#class-coverage) for more details.
## async method: Page.dblclick

View File

@ -68,7 +68,7 @@ with sync_playwright() as playwright:
## property: Playwright.chromium
- type: <[BrowserType]>
This object can be used to launch or connect to Chromium, returning instances of [ChromiumBrowser].
This object can be used to launch or connect to Chromium, returning instances of [Browser].
## property: Playwright.devices
* langs: js, python
@ -169,7 +169,7 @@ except TimeoutError as e:
## property: Playwright.firefox
- type: <[BrowserType]>
This object can be used to launch or connect to Firefox, returning instances of [FirefoxBrowser].
This object can be used to launch or connect to Firefox, returning instances of [Browser].
## property: Playwright.selectors
- type: <[Selectors]>
@ -180,4 +180,4 @@ Selectors can be used to install custom selector engines. See
## property: Playwright.webkit
- type: <[BrowserType]>
This object can be used to launch or connect to WebKit, returning instances of [WebKitBrowser].
This object can be used to launch or connect to WebKit, returning instances of [Browser].

View File

@ -26,7 +26,7 @@ Deletes the video file. Will wait for the video to finish if necessary.
- returns: <[path]>
Returns the file system path this video will be recorded to. The video is guaranteed to be written to the filesystem
upon closing the browser context. This method throws when connected remotely via [`method: BrowserType.connect`].
upon closing the browser context. This method throws when connected remotely.
## async method: Video.saveAs

View File

@ -1,5 +0,0 @@
# class: WebKitBrowser
* langs: js
* extends: [Browser]
WebKit browser instance does not expose WebKit-specific features.

6
index.d.ts vendored
View File

@ -17,8 +17,8 @@
import * as types from './types/types';
export * from './types/types';
export const webkit: types.BrowserType<types.WebKitBrowser>;
export const chromium: types.BrowserType<types.ChromiumBrowser>;
export const firefox: types.BrowserType<types.FirefoxBrowser>;
export const webkit: types.BrowserType<types.Browser>;
export const chromium: types.BrowserType<types.Browser>;
export const firefox: types.BrowserType<types.Browser>;
export const _electron: types.Electron;
export const _android: types.Android;

View File

@ -17,8 +17,8 @@
import * as types from './types/types';
export * from './types/types';
export const chromium: types.BrowserType<types.ChromiumBrowser>;
export const firefox: types.BrowserType<types.FirefoxBrowser>;
export const webkit: types.BrowserType<types.WebKitBrowser>;
export const chromium: types.BrowserType<types.Browser>;
export const firefox: types.BrowserType<types.Browser>;
export const webkit: types.BrowserType<types.Browser>;
export const _electron: types.Electron;
export const _android: types.Android;

View File

@ -27,7 +27,6 @@ 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 };
@ -228,11 +227,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
});
}
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<ChromiumBrowserContext> {
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<BrowserContext> {
return this._wrapApiCall('androidDevice.launchBrowser', async (channel: channels.AndroidDeviceChannel) => {
const contextOptions = await prepareBrowserContextParams(options);
const { context } = await channel.launchBrowser(contextOptions);
return BrowserContext.from(context) as ChromiumBrowserContext;
return BrowserContext.from(context) as BrowserContext;
});
}

View File

@ -21,6 +21,7 @@ export { BrowserContext } from './browserContext';
export { BrowserServer } from './browserType';
export { BrowserType } from './browserType';
export { ConsoleMessage } from './consoleMessage';
export { Coverage } from './coverage';
export { Dialog } from './dialog';
export { Download } from './download';
export { Electron, ElectronApplication } from './electron';
@ -36,13 +37,5 @@ export { Page } from './page';
export { Selectors } from './selectors';
export { Video } from './video';
export { Worker } from './worker';
export { ChromiumBrowser } from './chromiumBrowser';
export { ChromiumBrowserContext } from './chromiumBrowserContext';
export { ChromiumCoverage } from './chromiumCoverage';
export { CDPSession } from './cdpSession';
export { WebKitBrowser } from './webkitBrowser';
export { FirefoxBrowser } from './firefoxBrowser';
export { Playwright } from './playwright';

View File

@ -22,12 +22,14 @@ import { Events } from './events';
import { BrowserContextOptions } from './types';
import { isSafeCloseError } from '../utils/errors';
import * as api from '../../types/types';
import { CDPSession } from './cdpSession';
export class Browser extends ChannelOwner<channels.BrowserChannel, channels.BrowserInitializer> implements api.Browser {
readonly _contexts = new Set<BrowserContext>();
private _isConnected = true;
private _closedPromise: Promise<void>;
_isRemote = false;
readonly _name: string;
static from(browser: channels.BrowserChannel): Browser {
return (browser as any)._object;
@ -39,6 +41,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel, channels.Brow
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserInitializer) {
super(parent, type, guid, initializer);
this._name = initializer.name;
this._channel.on('close', () => this._didClose());
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
}
@ -76,6 +79,24 @@ export class Browser extends ChannelOwner<channels.BrowserChannel, channels.Brow
return this._isConnected;
}
async newBrowserCDPSession(): Promise<api.CDPSession> {
return this._wrapApiCall('browser.newBrowserCDPSession', async (channel: channels.BrowserChannel) => {
return CDPSession.from((await channel.newBrowserCDPSession()).session);
});
}
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
return this._wrapApiCall('browser.startTracing', async (channel: channels.BrowserChannel) => {
await channel.startTracing({ ...options, page: page ? page._channel : undefined });
});
}
async stopTracing(): Promise<Buffer> {
return this._wrapApiCall('browser.stopTracing', async (channel: channels.BrowserChannel) => {
return Buffer.from((await channel.stopTracing()).binary, 'base64');
});
}
async close(): Promise<void> {
try {
await this._wrapApiCall('browser.close', async (channel: channels.BrowserChannel) => {

View File

@ -23,6 +23,7 @@ import fs from 'fs';
import { ChannelOwner } from './channelOwner';
import { deprecate, evaluationScript, urlMatches } from './clientHelper';
import { Browser } from './browser';
import { Worker } from './worker';
import { Events } from './events';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { Waiter } from './waiter';
@ -31,6 +32,7 @@ import { isUnderTest, headersObjectToArray, mkdirIfNeeded } from '../utils/utils
import { isSafeCloseError } from '../utils/errors';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
import { CDPSession } from './cdpSession';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
@ -47,6 +49,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
sdkLanguage: 'javascript'
};
readonly _backgroundPages = new Set<Page>();
readonly _serviceWorkers = new Set<Worker>();
readonly _isChromium: boolean;
static from(context: channels.BrowserContextChannel): BrowserContext {
return (context as any)._object;
}
@ -59,11 +65,23 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
super(parent, type, guid, initializer);
if (parent instanceof Browser)
this._browser = parent;
this._isChromium = this._browser?._name === 'chromium';
this._channel.on('bindingCall', ({binding}) => this._onBinding(BindingCall.from(binding)));
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._channel.on('backgroundPage', ({ page }) => {
const backgroundPage = Page.from(page);
this._backgroundPages.add(backgroundPage);
this.emit(Events.BrowserContext.BackgroundPage, backgroundPage);
});
this._channel.on('serviceWorker', ({worker}) => {
const serviceWorker = Worker.from(worker);
serviceWorker._context = this;
this._serviceWorkers.add(serviceWorker);
this.emit(Events.BrowserContext.ServiceWorker, serviceWorker);
});
this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));
}
@ -238,6 +256,21 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
});
}
backgroundPages(): Page[] {
return [...this._backgroundPages];
}
serviceWorkers(): Worker[] {
return [...this._serviceWorkers];
}
async newCDPSession(page: Page): Promise<api.CDPSession> {
return this._wrapApiCall('browserContext.newCDPSession', async (channel: channels.BrowserContextChannel) => {
const result = await channel.newCDPSession({ page: page._channel });
return CDPSession.from(result.session);
});
}
_onClose() {
if (this._browser)
this._browser._contexts.delete(this);

View File

@ -1,51 +0,0 @@
/**
* 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 * as channels from '../protocol/channels';
import { Page } from './page';
import { CDPSession } from './cdpSession';
import { Browser } from './browser';
import * as api from '../../types/types';
import { ChromiumBrowserContext } from './chromiumBrowserContext';
import { BrowserContextOptions } from './types';
export class ChromiumBrowser extends Browser implements api.ChromiumBrowser {
contexts(): ChromiumBrowserContext[] {
return super.contexts() as ChromiumBrowserContext[];
}
newContext(options?: BrowserContextOptions): Promise<ChromiumBrowserContext> {
return super.newContext(options) as Promise<ChromiumBrowserContext>;
}
async newBrowserCDPSession(): Promise<CDPSession> {
return this._wrapApiCall('chromiumBrowser.newBrowserCDPSession', async (channel: channels.BrowserChannel) => {
return CDPSession.from((await channel.crNewBrowserCDPSession()).session);
});
}
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
return this._wrapApiCall('chromiumBrowser.startTracing', async (channel: channels.BrowserChannel) => {
await channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
});
}
async stopTracing(): Promise<Buffer> {
return this._wrapApiCall('chromiumBrowser.stopTracing', async (channel: channels.BrowserChannel) => {
return Buffer.from((await channel.crStopTracing()).binary, 'base64');
});
}
}

View File

@ -1,61 +0,0 @@
/**
* 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 * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner';
import { CDPSession } from './cdpSession';
import { Events } from './events';
import { Worker } from './worker';
import { BrowserContext } from './browserContext';
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);
this._channel.on('crBackgroundPage', ({ page }) => {
const backgroundPage = Page.from(page);
this._backgroundPages.add(backgroundPage);
this.emit(Events.ChromiumBrowserContext.BackgroundPage, backgroundPage);
});
this._channel.on('crServiceWorker', ({worker}) => {
const serviceWorker = Worker.from(worker);
serviceWorker._context = this;
this._serviceWorkers.add(serviceWorker);
this.emit(Events.ChromiumBrowserContext.ServiceWorker, serviceWorker);
});
}
backgroundPages(): Page[] {
return [...this._backgroundPages];
}
serviceWorkers(): Worker[] {
return [...this._serviceWorkers];
}
async newCDPSession(page: Page): Promise<CDPSession> {
return this._wrapApiCall('chromiumBrowserContext.newCDPSession', async (channel: channels.BrowserContextChannel) => {
const result = await channel.crNewCDPSession({ page: page._channel });
return CDPSession.from(result.session);
});
}
}

View File

@ -31,11 +31,7 @@ import { CDPSession } from './cdpSession';
import { Playwright } from './playwright';
import { Electron, ElectronApplication } from './electron';
import * as channels from '../protocol/channels';
import { ChromiumBrowser } from './chromiumBrowser';
import { ChromiumBrowserContext } from './chromiumBrowserContext';
import { Stream } from './stream';
import { WebKitBrowser } from './webkitBrowser';
import { FirefoxBrowser } from './firefoxBrowser';
import { debugLogger } from '../utils/debugLogger';
import { SelectorsOwner } from './selectors';
import { isUnderTest } from '../utils/utils';
@ -162,26 +158,12 @@ export class Connection {
case 'BindingCall':
result = new BindingCall(parent, type, guid, initializer);
break;
case 'Browser': {
const browserName = (initializer as channels.BrowserInitializer).name;
if (browserName === 'chromium')
result = new ChromiumBrowser(parent, type, guid, initializer);
else if (browserName === 'webkit')
result = new WebKitBrowser(parent, type, guid, initializer);
else if (browserName === 'firefox')
result = new FirefoxBrowser(parent, type, guid, initializer);
else
result = new Browser(parent, type, guid, initializer);
case 'Browser':
result = new Browser(parent, type, guid, initializer);
break;
}
case 'BrowserContext': {
const {isChromium} = (initializer as channels.BrowserContextInitializer);
if (isChromium)
result = new ChromiumBrowserContext(parent, type, guid, initializer);
else
result = new BrowserContext(parent, type, guid, initializer);
case 'BrowserContext':
result = new BrowserContext(parent, type, guid, initializer);
break;
}
case 'BrowserType':
result = new BrowserType(parent, type, guid, initializer);
break;

View File

@ -17,26 +17,26 @@
import * as channels from '../protocol/channels';
import * as api from '../../types/types';
export class ChromiumCoverage implements api.ChromiumCoverage {
export class Coverage implements api.Coverage {
private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) {
this._channel = channel;
}
async startJSCoverage(options: channels.PageCrStartJSCoverageOptions = {}) {
await this._channel.crStartJSCoverage(options);
async startJSCoverage(options: channels.PageStartJSCoverageOptions = {}) {
await this._channel.startJSCoverage(options);
}
async stopJSCoverage(): Promise<channels.PageCrStopJSCoverageResult['entries']> {
return (await this._channel.crStopJSCoverage()).entries;
async stopJSCoverage(): Promise<channels.PageStopJSCoverageResult['entries']> {
return (await this._channel.stopJSCoverage()).entries;
}
async startCSSCoverage(options: channels.PageCrStartCSSCoverageOptions = {}) {
await this._channel.crStartCSSCoverage(options);
async startCSSCoverage(options: channels.PageStartCSSCoverageOptions = {}) {
await this._channel.startCSSCoverage(options);
}
async stopCSSCoverage(): Promise<channels.PageCrStopCSSCoverageResult['entries']> {
return (await this._channel.crStopCSSCoverage()).entries;
async stopCSSCoverage(): Promise<channels.PageStopCSSCoverageResult['entries']> {
return (await this._channel.stopCSSCoverage()).entries;
}
}

View File

@ -20,7 +20,6 @@ import * as channels from '../protocol/channels';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import type { ChromiumBrowserContext } from './chromiumBrowserContext';
import { envObjectToArray } from './clientHelper';
import { Events } from './events';
import { JSHandle, parseResult, serializeArgument } from './jsHandle';
@ -90,8 +89,8 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
});
}
context(): ChromiumBrowserContext {
return this._context! as ChromiumBrowserContext;
context(): BrowserContext {
return this._context! as BrowserContext;
}
async close() {

View File

@ -37,6 +37,8 @@ export const Events = {
BrowserContext: {
Close: 'close',
Page: 'page',
BackgroundPage: 'backgroundpage',
ServiceWorker: 'serviceworker',
},
BrowserServer: {
@ -78,11 +80,6 @@ export const Events = {
Close: 'close',
},
ChromiumBrowserContext: {
BackgroundPage: 'backgroundpage',
ServiceWorker: 'serviceworker',
},
ElectronApplication: {
Close: 'close',
Window: 'window',

View File

@ -1,21 +0,0 @@
/**
* 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 { Browser } from './browser';
import * as api from '../../types/types';
export class FirefoxBrowser extends Browser implements api.FirefoxBrowser {
}

View File

@ -34,7 +34,7 @@ import { assertMaxArguments, serializeArgument, parseResult, JSHandle } from './
import { Request, Response, Route, RouteHandler, WebSocket, validateHeaders } from './network';
import { FileChooser } from './fileChooser';
import { Buffer } from 'buffer';
import { ChromiumCoverage } from './chromiumCoverage';
import { Coverage } from './coverage';
import { Waiter } from './waiter';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
@ -46,7 +46,6 @@ 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';
import { Artifact } from './artifact';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
@ -78,11 +77,10 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
private _routes: { url: URLMatch, handler: RouteHandler }[] = [];
readonly accessibility: Accessibility;
readonly coverage: Coverage;
readonly keyboard: Keyboard;
readonly mouse: Mouse;
readonly touchscreen: Touchscreen;
coverage: ChromiumCoverage | null = null;
pdf: (options?: PDFOptions) => Promise<Buffer>;
readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
readonly _timeoutSettings: TimeoutSettings;
@ -145,12 +143,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 as ChromiumBrowserContext)._isChromium) {
this.coverage = new ChromiumCoverage(this._channel);
this.pdf = options => this._pdf(options);
} else {
this.pdf = undefined as any;
}
this.coverage = new Coverage(this._channel);
this._closedOrCrashedPromise = Promise.race([
new Promise<void>(f => this.once(Events.Page.Close, f)),
@ -670,7 +663,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
});
}
async _pdf(options: PDFOptions = {}): Promise<Buffer> {
async pdf(options: PDFOptions = {}): Promise<Buffer> {
return this._wrapApiCall('page.pdf', async (channel: channels.PageChannel) => {
const transportOptions: channels.PagePdfParams = { ...options } as channels.PagePdfParams;
if (transportOptions.margin)

View File

@ -1,21 +0,0 @@
/**
* 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 { Browser } from './browser';
import * as api from '../../types/types';
export class WebKitBrowser extends Browser implements api.WebKitBrowser {
}

View File

@ -20,7 +20,6 @@ import { ChannelOwner } from './channelOwner';
import { assertMaxArguments, JSHandle, parseResult, serializeArgument } from './jsHandle';
import { Page } from './page';
import { BrowserContext } from './browserContext';
import { ChromiumBrowserContext } from './chromiumBrowserContext';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
@ -38,7 +37,7 @@ export class Worker extends ChannelOwner<channels.WorkerChannel, channels.Worker
if (this._page)
this._page._workers.delete(this);
if (this._context)
(this._context as ChromiumBrowserContext)._serviceWorkers.delete(this);
this._context._serviceWorkers.delete(this);
this.emit(Events.Worker.Close, this);
});
}

View File

@ -57,11 +57,11 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
if (context._browser.options.name === 'chromium') {
for (const page of (context as CRBrowserContext).backgroundPages())
this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) });
context.on(CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) }));
this._dispatchEvent('backgroundPage', { page: new PageDispatcher(this._scope, page) });
context.on(CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('backgroundPage', { page: new PageDispatcher(this._scope, page) }));
for (const serviceWorker of (context as CRBrowserContext).serviceWorkers())
this._dispatchEvent('crServiceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker)});
context.on(CRBrowserContext.CREvents.ServiceWorker, serviceWorker => this._dispatchEvent('crServiceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker) }));
this._dispatchEvent('serviceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker)});
context.on(CRBrowserContext.CREvents.ServiceWorker, serviceWorker => this._dispatchEvent('serviceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker) }));
}
}
@ -151,7 +151,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
// Inspector controller will take care of this.
}
async crNewCDPSession(params: channels.BrowserContextCrNewCDPSessionParams): Promise<channels.BrowserContextCrNewCDPSessionResult> {
async newCDPSession(params: channels.BrowserContextNewCDPSessionParams): Promise<channels.BrowserContextNewCDPSessionResult> {
if (!this._object._browser.options.isChromium)
throw new Error(`CDP session is only available in Chromium`);
const crBrowserContext = this._object as CRBrowserContext;

View File

@ -45,21 +45,21 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserIniti
await this._object.close();
}
async crNewBrowserCDPSession(): Promise<channels.BrowserCrNewBrowserCDPSessionResult> {
async newBrowserCDPSession(): Promise<channels.BrowserNewBrowserCDPSessionResult> {
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> {
async startTracing(params: channels.BrowserStartTracingParams): Promise<void> {
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> {
async stopTracing(): Promise<channels.BrowserStopTracingResult> {
if (!this._object.options.isChromium)
throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object as CRBrowser;

View File

@ -217,22 +217,22 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageInitializer> i
await this._page.bringToFront();
}
async crStartJSCoverage(params: channels.PageCrStartJSCoverageParams, metadata: CallMetadata): Promise<void> {
async startJSCoverage(params: channels.PageStartJSCoverageParams, metadata: CallMetadata): Promise<void> {
const coverage = this._page.coverage as CRCoverage;
await coverage.startJSCoverage(params);
}
async crStopJSCoverage(params: channels.PageCrStopJSCoverageParams, metadata: CallMetadata): Promise<channels.PageCrStopJSCoverageResult> {
async stopJSCoverage(params: channels.PageStopJSCoverageParams, metadata: CallMetadata): Promise<channels.PageStopJSCoverageResult> {
const coverage = this._page.coverage as CRCoverage;
return { entries: await coverage.stopJSCoverage() };
}
async crStartCSSCoverage(params: channels.PageCrStartCSSCoverageParams, metadata: CallMetadata): Promise<void> {
async startCSSCoverage(params: channels.PageStartCSSCoverageParams, metadata: CallMetadata): Promise<void> {
const coverage = this._page.coverage as CRCoverage;
await coverage.startCSSCoverage(params);
}
async crStopCSSCoverage(params: channels.PageCrStopCSSCoverageParams, metadata: CallMetadata): Promise<channels.PageCrStopCSSCoverageResult> {
async stopCSSCoverage(params: channels.PageStopCSSCoverageParams, metadata: CallMetadata): Promise<channels.PageStopCSSCoverageResult> {
const coverage = this._page.coverage as CRCoverage;
return { entries: await coverage.stopCSSCoverage() };
}

View File

@ -430,9 +430,9 @@ export interface BrowserChannel extends Channel {
on(event: 'close', callback: (params: BrowserCloseEvent) => void): this;
close(params?: BrowserCloseParams, metadata?: Metadata): Promise<BrowserCloseResult>;
newContext(params: BrowserNewContextParams, metadata?: Metadata): Promise<BrowserNewContextResult>;
crNewBrowserCDPSession(params?: BrowserCrNewBrowserCDPSessionParams, metadata?: Metadata): Promise<BrowserCrNewBrowserCDPSessionResult>;
crStartTracing(params: BrowserCrStartTracingParams, metadata?: Metadata): Promise<BrowserCrStartTracingResult>;
crStopTracing(params?: BrowserCrStopTracingParams, metadata?: Metadata): Promise<BrowserCrStopTracingResult>;
newBrowserCDPSession(params?: BrowserNewBrowserCDPSessionParams, metadata?: Metadata): Promise<BrowserNewBrowserCDPSessionResult>;
startTracing(params: BrowserStartTracingParams, metadata?: Metadata): Promise<BrowserStartTracingResult>;
stopTracing(params?: BrowserStopTracingParams, metadata?: Metadata): Promise<BrowserStopTracingResult>;
}
export type BrowserCloseEvent = {};
export type BrowserCloseParams = {};
@ -556,27 +556,27 @@ export type BrowserNewContextOptions = {
export type BrowserNewContextResult = {
context: BrowserContextChannel,
};
export type BrowserCrNewBrowserCDPSessionParams = {};
export type BrowserCrNewBrowserCDPSessionOptions = {};
export type BrowserCrNewBrowserCDPSessionResult = {
export type BrowserNewBrowserCDPSessionParams = {};
export type BrowserNewBrowserCDPSessionOptions = {};
export type BrowserNewBrowserCDPSessionResult = {
session: CDPSessionChannel,
};
export type BrowserCrStartTracingParams = {
export type BrowserStartTracingParams = {
page?: PageChannel,
path?: string,
screenshots?: boolean,
categories?: string[],
};
export type BrowserCrStartTracingOptions = {
export type BrowserStartTracingOptions = {
page?: PageChannel,
path?: string,
screenshots?: boolean,
categories?: string[],
};
export type BrowserCrStartTracingResult = void;
export type BrowserCrStopTracingParams = {};
export type BrowserCrStopTracingOptions = {};
export type BrowserCrStopTracingResult = {
export type BrowserStartTracingResult = void;
export type BrowserStopTracingParams = {};
export type BrowserStopTracingOptions = {};
export type BrowserStopTracingResult = {
binary: Binary,
};
@ -590,8 +590,8 @@ export interface BrowserContextChannel extends Channel {
on(event: 'page', callback: (params: BrowserContextPageEvent) => void): this;
on(event: 'route', callback: (params: BrowserContextRouteEvent) => void): this;
on(event: 'video', callback: (params: BrowserContextVideoEvent) => void): this;
on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this;
on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this;
on(event: 'backgroundPage', callback: (params: BrowserContextBackgroundPageEvent) => void): this;
on(event: 'serviceWorker', callback: (params: BrowserContextServiceWorkerEvent) => void): this;
addCookies(params: BrowserContextAddCookiesParams, metadata?: Metadata): Promise<BrowserContextAddCookiesResult>;
addInitScript(params: BrowserContextAddInitScriptParams, metadata?: Metadata): Promise<BrowserContextAddInitScriptResult>;
clearCookies(params?: BrowserContextClearCookiesParams, metadata?: Metadata): Promise<BrowserContextClearCookiesResult>;
@ -611,7 +611,7 @@ export interface BrowserContextChannel extends Channel {
storageState(params?: BrowserContextStorageStateParams, metadata?: Metadata): Promise<BrowserContextStorageStateResult>;
pause(params?: BrowserContextPauseParams, metadata?: Metadata): Promise<BrowserContextPauseResult>;
recorderSupplementEnable(params: BrowserContextRecorderSupplementEnableParams, metadata?: Metadata): Promise<BrowserContextRecorderSupplementEnableResult>;
crNewCDPSession(params: BrowserContextCrNewCDPSessionParams, metadata?: Metadata): Promise<BrowserContextCrNewCDPSessionResult>;
newCDPSession(params: BrowserContextNewCDPSessionParams, metadata?: Metadata): Promise<BrowserContextNewCDPSessionResult>;
}
export type BrowserContextBindingCallEvent = {
binding: BindingCallChannel,
@ -627,10 +627,10 @@ export type BrowserContextRouteEvent = {
export type BrowserContextVideoEvent = {
artifact: ArtifactChannel,
};
export type BrowserContextCrBackgroundPageEvent = {
export type BrowserContextBackgroundPageEvent = {
page: PageChannel,
};
export type BrowserContextCrServiceWorkerEvent = {
export type BrowserContextServiceWorkerEvent = {
worker: WorkerChannel,
};
export type BrowserContextAddCookiesParams = {
@ -779,13 +779,13 @@ export type BrowserContextRecorderSupplementEnableOptions = {
outputFile?: string,
};
export type BrowserContextRecorderSupplementEnableResult = void;
export type BrowserContextCrNewCDPSessionParams = {
export type BrowserContextNewCDPSessionParams = {
page: PageChannel,
};
export type BrowserContextCrNewCDPSessionOptions = {
export type BrowserContextNewCDPSessionOptions = {
};
export type BrowserContextCrNewCDPSessionResult = {
export type BrowserContextNewCDPSessionResult = {
session: CDPSessionChannel,
};
@ -847,10 +847,10 @@ export interface PageChannel extends Channel {
touchscreenTap(params: PageTouchscreenTapParams, metadata?: Metadata): Promise<PageTouchscreenTapResult>;
accessibilitySnapshot(params: PageAccessibilitySnapshotParams, metadata?: Metadata): Promise<PageAccessibilitySnapshotResult>;
pdf(params: PagePdfParams, metadata?: Metadata): Promise<PagePdfResult>;
crStartJSCoverage(params: PageCrStartJSCoverageParams, metadata?: Metadata): Promise<PageCrStartJSCoverageResult>;
crStopJSCoverage(params?: PageCrStopJSCoverageParams, metadata?: Metadata): Promise<PageCrStopJSCoverageResult>;
crStartCSSCoverage(params: PageCrStartCSSCoverageParams, metadata?: Metadata): Promise<PageCrStartCSSCoverageResult>;
crStopCSSCoverage(params?: PageCrStopCSSCoverageParams, metadata?: Metadata): Promise<PageCrStopCSSCoverageResult>;
startJSCoverage(params: PageStartJSCoverageParams, metadata?: Metadata): Promise<PageStartJSCoverageResult>;
stopJSCoverage(params?: PageStopJSCoverageParams, metadata?: Metadata): Promise<PageStopJSCoverageResult>;
startCSSCoverage(params: PageStartCSSCoverageParams, metadata?: Metadata): Promise<PageStartCSSCoverageResult>;
stopCSSCoverage(params?: PageStopCSSCoverageParams, metadata?: Metadata): Promise<PageStopCSSCoverageResult>;
bringToFront(params?: PageBringToFrontParams, metadata?: Metadata): Promise<PageBringToFrontResult>;
}
export type PageBindingCallEvent = {
@ -1185,18 +1185,18 @@ export type PagePdfOptions = {
export type PagePdfResult = {
pdf: Binary,
};
export type PageCrStartJSCoverageParams = {
export type PageStartJSCoverageParams = {
resetOnNavigation?: boolean,
reportAnonymousScripts?: boolean,
};
export type PageCrStartJSCoverageOptions = {
export type PageStartJSCoverageOptions = {
resetOnNavigation?: boolean,
reportAnonymousScripts?: boolean,
};
export type PageCrStartJSCoverageResult = void;
export type PageCrStopJSCoverageParams = {};
export type PageCrStopJSCoverageOptions = {};
export type PageCrStopJSCoverageResult = {
export type PageStartJSCoverageResult = void;
export type PageStopJSCoverageParams = {};
export type PageStopJSCoverageOptions = {};
export type PageStopJSCoverageResult = {
entries: {
url: string,
scriptId: string,
@ -1212,16 +1212,16 @@ export type PageCrStopJSCoverageResult = {
}[],
}[],
};
export type PageCrStartCSSCoverageParams = {
export type PageStartCSSCoverageParams = {
resetOnNavigation?: boolean,
};
export type PageCrStartCSSCoverageOptions = {
export type PageStartCSSCoverageOptions = {
resetOnNavigation?: boolean,
};
export type PageCrStartCSSCoverageResult = void;
export type PageCrStopCSSCoverageParams = {};
export type PageCrStopCSSCoverageOptions = {};
export type PageCrStopCSSCoverageResult = {
export type PageStartCSSCoverageResult = void;
export type PageStopCSSCoverageParams = {};
export type PageStopCSSCoverageOptions = {};
export type PageStopCSSCoverageResult = {
entries: {
url: string,
text?: string,

View File

@ -462,11 +462,11 @@ Browser:
returns:
context: BrowserContext
crNewBrowserCDPSession:
newBrowserCDPSession:
returns:
session: CDPSession
crStartTracing:
startTracing:
parameters:
page: Page?
path: string?
@ -475,7 +475,7 @@ Browser:
type: array?
items: string
crStopTracing:
stopTracing:
returns:
binary: binary
@ -598,7 +598,7 @@ BrowserContext:
saveStorage: string?
outputFile: string?
crNewCDPSession:
newCDPSession:
parameters:
page: Page
returns:
@ -625,11 +625,11 @@ BrowserContext:
parameters:
artifact: Artifact
crBackgroundPage:
backgroundPage:
parameters:
page: Page
crServiceWorker:
serviceWorker:
parameters:
worker: Worker
@ -859,12 +859,12 @@ Page:
returns:
pdf: binary
crStartJSCoverage:
startJSCoverage:
parameters:
resetOnNavigation: boolean?
reportAnonymousScripts: boolean?
crStopJSCoverage:
stopJSCoverage:
returns:
entries:
type: array
@ -890,11 +890,11 @@ Page:
endOffset: number
count: number
crStartCSSCoverage:
startCSSCoverage:
parameters:
resetOnNavigation: boolean?
crStopCSSCoverage:
stopCSSCoverage:
returns:
entries:
type: array

View File

@ -312,14 +312,14 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
origins: tOptional(tArray(tType('OriginStorage'))),
})),
});
scheme.BrowserCrNewBrowserCDPSessionParams = tOptional(tObject({}));
scheme.BrowserCrStartTracingParams = tObject({
scheme.BrowserNewBrowserCDPSessionParams = tOptional(tObject({}));
scheme.BrowserStartTracingParams = tObject({
page: tOptional(tChannel('Page')),
path: tOptional(tString),
screenshots: tOptional(tBoolean),
categories: tOptional(tArray(tString)),
});
scheme.BrowserCrStopTracingParams = tOptional(tObject({}));
scheme.BrowserStopTracingParams = tOptional(tObject({}));
scheme.BrowserContextAddCookiesParams = tObject({
cookies: tArray(tType('SetNetworkCookie')),
});
@ -381,7 +381,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
saveStorage: tOptional(tString),
outputFile: tOptional(tString),
});
scheme.BrowserContextCrNewCDPSessionParams = tObject({
scheme.BrowserContextNewCDPSessionParams = tObject({
page: tChannel('Page'),
});
scheme.PageSetDefaultNavigationTimeoutNoReplyParams = tObject({
@ -504,15 +504,15 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
right: tOptional(tString),
})),
});
scheme.PageCrStartJSCoverageParams = tObject({
scheme.PageStartJSCoverageParams = tObject({
resetOnNavigation: tOptional(tBoolean),
reportAnonymousScripts: tOptional(tBoolean),
});
scheme.PageCrStopJSCoverageParams = tOptional(tObject({}));
scheme.PageCrStartCSSCoverageParams = tObject({
scheme.PageStopJSCoverageParams = tOptional(tObject({}));
scheme.PageStartCSSCoverageParams = tObject({
resetOnNavigation: tOptional(tBoolean),
});
scheme.PageCrStopCSSCoverageParams = tOptional(tObject({}));
scheme.PageStopCSSCoverageParams = tOptional(tObject({}));
scheme.PageBringToFrontParams = tOptional(tObject({}));
scheme.FrameEvalOnSelectorParams = tObject({
selector: tString,

View File

@ -17,7 +17,6 @@
import domain from 'domain';
import { folio } from './fixtures';
import type { ChromiumBrowser } from '..';
const { it, expect } = folio;
it('should work', async ({browser}) => {
@ -90,7 +89,7 @@ it('should scope CDPSession handles', (test, { browserName }) => {
};
await expectScopeState(browserType, GOLDEN_PRECONDITION);
const session = await (browser as ChromiumBrowser).newBrowserCDPSession();
const session = await browser.newBrowserCDPSession();
await expectScopeState(browserType, {
_guid: '',
objects: [

View File

@ -25,7 +25,7 @@ let api = new Set(installCoverageHooks(browserName).coverage.keys());
if (browserName === 'chromium') {
// Sometimes we already have a background page while launching, before adding a listener.
api.delete('chromiumBrowserContext.emit("backgroundpage")');
api.delete('browserContext.emit("backgroundpage")');
}
if (browserName !== 'chromium') {

View File

@ -16,13 +16,6 @@
import { it, expect, describe } from './fixtures';
it('should be missing', (test, { browserName }) => {
test.skip(browserName === 'chromium');
},
async function({page}) {
expect(page.coverage).toBe(null);
});
describe('JS Coverage', (suite, { browserName }) => {
suite.skip(browserName !== 'chromium');
}, () => {

View File

@ -15,7 +15,6 @@
* limitations under the License.
*/
import { it, expect, describe } from '../fixtures';
import type { ChromiumBrowserContext } from '../..';
import http from 'http';
describe('chromium', (suite, { browserName }) => {
@ -23,7 +22,7 @@ describe('chromium', (suite, { browserName }) => {
}, () => {
it('should create a worker from a service worker', async ({page, server, context}) => {
const [worker] = await Promise.all([
(context as ChromiumBrowserContext).waitForEvent('serviceworker'),
context.waitForEvent('serviceworker'),
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
]);
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
@ -31,17 +30,17 @@ describe('chromium', (suite, { browserName }) => {
it('serviceWorkers() should return current workers', async ({page, server, context}) => {
const [worker1] = await Promise.all([
(context as ChromiumBrowserContext).waitForEvent('serviceworker'),
context.waitForEvent('serviceworker'),
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
]);
let workers = (context as ChromiumBrowserContext).serviceWorkers();
let workers = context.serviceWorkers();
expect(workers.length).toBe(1);
const [worker2] = await Promise.all([
(context as ChromiumBrowserContext).waitForEvent('serviceworker'),
context.waitForEvent('serviceworker'),
page.goto(server.CROSS_PROCESS_PREFIX + '/serviceworkers/empty/sw.html')
]);
workers = (context as ChromiumBrowserContext).serviceWorkers();
workers = context.serviceWorkers();
expect(workers.length).toBe(2);
expect(workers).toContain(worker1);
expect(workers).toContain(worker2);
@ -50,7 +49,7 @@ describe('chromium', (suite, { browserName }) => {
it('should not create a worker from a shared worker', async ({page, server, context}) => {
await page.goto(server.EMPTY_PAGE);
let serviceWorkerCreated;
(context as ChromiumBrowserContext).once('serviceworker', () => serviceWorkerCreated = true);
context.once('serviceworker', () => serviceWorkerCreated = true);
await page.evaluate(() => {
new SharedWorker('data:text/javascript,console.log("hi")');
});
@ -58,7 +57,7 @@ describe('chromium', (suite, { browserName }) => {
});
it('should close service worker together with the context', async ({browser, server}) => {
const context = await browser.newContext() as ChromiumBrowserContext;
const context = await browser.newContext();
const page = await context.newPage();
const [worker] = await Promise.all([
context.waitForEvent('serviceworker'),
@ -175,7 +174,7 @@ describe('chromium', (suite, { browserName }) => {
const cdpBrowser1 = await browserType.connectOverCDP({
wsEndpoint: JSON.parse(json).webSocketDebuggerUrl,
});
const context = cdpBrowser1.contexts()[0] as ChromiumBrowserContext;
const context = cdpBrowser1.contexts()[0];
const page = await cdpBrowser1.contexts()[0].newPage();
const [worker] = await Promise.all([
context.waitForEvent('serviceworker'),
@ -187,7 +186,7 @@ describe('chromium', (suite, { browserName }) => {
const cdpBrowser2 = await browserType.connectOverCDP({
wsEndpoint: JSON.parse(json).webSocketDebuggerUrl,
});
const context2 = cdpBrowser2.contexts()[0] as ChromiumBrowserContext;
const context2 = cdpBrowser2.contexts()[0];
expect(context2.serviceWorkers().length).toBe(1);
await cdpBrowser2.close();
} finally {

View File

@ -16,7 +16,6 @@
import { it, expect } from '../fixtures';
import path from 'path';
import type { ChromiumBrowser, ChromiumBrowserContext } from '../..';
it('should throw with remote-debugging-pipe argument', (test, { browserName, mode }) => {
test.skip(mode !== 'default' || browserName !== 'chromium');
@ -66,7 +65,7 @@ it('should return background pages', (test, { browserName }) => {
`--load-extension=${extensionPath}`,
],
};
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions) as ChromiumBrowserContext;
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions);
const backgroundPages = context.backgroundPages();
const backgroundPage = backgroundPages.length
? backgroundPages[0]
@ -92,7 +91,7 @@ it('should return background pages when recording video', (test, { browserName }
dir: testInfo.outputPath(''),
},
};
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions) as ChromiumBrowserContext;
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions);
const backgroundPages = context.backgroundPages();
const backgroundPage = backgroundPages.length
? backgroundPages[0]
@ -107,7 +106,7 @@ it('should not create pages automatically', (test, { browserName }) => {
test.skip(browserName !== 'chromium');
}, async ({browserType, browserOptions}) => {
const browser = await browserType.launch(browserOptions);
const browserSession = await (browser as ChromiumBrowser).newBrowserCDPSession();
const browserSession = await browser.newBrowserCDPSession();
const targets = [];
browserSession.on('Target.targetCreated', async ({targetInfo}) => {
if (targetInfo.type !== 'browser')

View File

@ -14,13 +14,12 @@
* limitations under the License.
*/
import { it, expect, describe } from '../fixtures';
import type { ChromiumBrowserContext, ChromiumBrowser } from '../../types/types';
describe('session', (suite, { browserName }) => {
suite.skip(browserName !== 'chromium');
}, () => {
it('should work', async function({page}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const client = await page.context().newCDPSession(page);
await Promise.all([
client.send('Runtime.enable'),
@ -31,7 +30,7 @@ describe('session', (suite, { browserName }) => {
});
it('should send events', async function({page, server}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const client = await page.context().newCDPSession(page);
await client.send('Network.enable');
const events = [];
client.on('Network.requestWillBeSent', event => events.push(event));
@ -41,12 +40,12 @@ describe('session', (suite, { browserName }) => {
it('should only accept a page', async function({page}) {
// @ts-expect-error newCDPSession expects a Page
const error = await (page.context() as ChromiumBrowserContext).newCDPSession(page.context()).catch(e => e);
const error = await page.context().newCDPSession(page.context()).catch(e => e);
expect(error.message).toContain('page: expected Page');
});
it('should enable and disable domains independently', async function({page}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const client = await page.context().newCDPSession(page);
await client.send('Runtime.enable');
await client.send('Debugger.enable');
// JS coverage enables and then disables Debugger domain.
@ -64,7 +63,7 @@ describe('session', (suite, { browserName }) => {
});
it('should be able to detach session', async function({page}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const client = await page.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);
@ -79,7 +78,7 @@ describe('session', (suite, { browserName }) => {
});
it('should throw nice errors', async function({page}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const client = await page.context().newCDPSession(page);
const error = await theSourceOfTheProblems().catch(error => error);
expect(error.stack).toContain('theSourceOfTheProblems');
expect(error.message).toContain('ThisCommand.DoesNotExist');
@ -93,14 +92,14 @@ describe('session', (suite, { browserName }) => {
it('should not break page.close()', async function({browser}) {
const context = await browser.newContext();
const page = await context.newPage();
const session = await (page.context() as ChromiumBrowserContext).newCDPSession(page);
const session = await page.context().newCDPSession(page);
await session.detach();
await page.close();
await context.close();
});
it('should detach when page closes', async function({browser}) {
const context = await browser.newContext() as ChromiumBrowserContext;
const context = await browser.newContext();
const page = await context.newPage();
const session = await context.newCDPSession(page);
await page.close();
@ -111,7 +110,7 @@ describe('session', (suite, { browserName }) => {
});
it('should work with newBrowserCDPSession', async function({browser}) {
const session = await (browser as ChromiumBrowser).newBrowserCDPSession();
const session = await browser.newBrowserCDPSession();
const version = await session.send('Browser.getVersion');
expect(version.userAgent).toBeTruthy();

View File

@ -17,7 +17,6 @@
import { folio } from '../fixtures';
import fs from 'fs';
import path from 'path';
import type { ChromiumBrowser } from '../..';
const { it, expect, describe } = folio;
describe('tracing', (suite, { browserName }) => {
@ -25,24 +24,24 @@ describe('tracing', (suite, { browserName }) => {
}, () => {
it('should output a trace', async ({browser, page, server, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile});
await browser.startTracing(page, {screenshots: true, path: outputTraceFile});
await page.goto(server.PREFIX + '/grid.html');
await (browser as ChromiumBrowser).stopTracing();
await browser.stopTracing();
expect(fs.existsSync(outputTraceFile)).toBe(true);
});
it('should create directories as needed', async ({browser, page, server, testInfo}) => {
const filePath = testInfo.outputPath(path.join('these', 'are', 'directories', 'trace.json'));
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: filePath});
await browser.startTracing(page, {screenshots: true, path: filePath});
await page.goto(server.PREFIX + '/grid.html');
await (browser as ChromiumBrowser).stopTracing();
await browser.stopTracing();
expect(fs.existsSync(filePath)).toBe(true);
});
it('should run with custom categories if provided', async ({browser, page, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
await (browser as ChromiumBrowser).stopTracing();
await browser.startTracing(page, {path: outputTraceFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
await browser.stopTracing();
const traceJson = JSON.parse(fs.readFileSync(outputTraceFile).toString());
expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires');
@ -50,35 +49,35 @@ describe('tracing', (suite, { browserName }) => {
it('should throw if tracing on two pages', async ({browser, page, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile});
await browser.startTracing(page, {path: outputTraceFile});
const newPage = await browser.newPage();
let error = null;
await (browser as ChromiumBrowser).startTracing(newPage, {path: outputTraceFile}).catch(e => error = e);
await browser.startTracing(newPage, {path: outputTraceFile}).catch(e => error = e);
await newPage.close();
expect(error).toBeTruthy();
await (browser as ChromiumBrowser).stopTracing();
await browser.stopTracing();
});
it('should return a buffer', async ({browser, page, server, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile});
await browser.startTracing(page, {screenshots: true, path: outputTraceFile});
await page.goto(server.PREFIX + '/grid.html');
const trace = await (browser as ChromiumBrowser).stopTracing();
const trace = await browser.stopTracing();
const buf = fs.readFileSync(outputTraceFile);
expect(trace.toString()).toEqual(buf.toString());
});
it('should work without options', async ({browser, page, server}) => {
await (browser as ChromiumBrowser).startTracing(page);
await browser.startTracing(page);
await page.goto(server.PREFIX + '/grid.html');
const trace = await (browser as ChromiumBrowser).stopTracing();
const trace = await browser.stopTracing();
expect(trace).toBeTruthy();
});
it('should support a buffer without a path', async ({browser, page, server}) => {
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true});
await browser.startTracing(page, {screenshots: true});
await page.goto(server.PREFIX + '/grid.html');
const trace = await (browser as ChromiumBrowser).stopTracing();
const trace = await browser.stopTracing();
expect(trace.toString()).toContain('screenshot');
});
});

View File

@ -40,18 +40,17 @@ function traceAPICoverage(apiCoverage, api, events) {
uninstalls.push(() => Reflect.set(classType.prototype, methodName, method));
}
if (events[name]) {
const emitClassType = (name === 'BrowserContext' ? api['ChromiumBrowserContext'] : undefined) || classType;
for (const event of Object.values(events[name])) {
if (typeof event !== 'symbol')
apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, false);
}
const method = Reflect.get(emitClassType.prototype, 'emit');
Reflect.set(emitClassType.prototype, 'emit', function(event, ...args) {
const method = Reflect.get(classType.prototype, 'emit');
Reflect.set(classType.prototype, 'emit', function(event, ...args) {
if (typeof event !== 'symbol' && this.listenerCount(event))
apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, true);
return method.call(this, event, ...args);
});
uninstalls.push(() => Reflect.set(emitClassType.prototype, 'emit', method));
uninstalls.push(() => Reflect.set(classType.prototype, 'emit', method));
}
}
return () => uninstalls.forEach(u => u());

View File

@ -206,13 +206,6 @@ it('coverage should work', (test, { browserName }) => {
expect(coverage[0].functions.find(f => f.functionName === 'foo').ranges[0].count).toEqual(1);
});
it('coverage should be missing', (test, { browserName }) => {
test.skip(browserName === 'chromium');
}, async ({launchPersistent}) => {
const {page} = await launchPersistent();
expect(page.coverage).toBe(null);
});
it('should respect selectors', async ({playwright, launchPersistent}) => {
const {page} = await launchPersistent();

View File

@ -26,9 +26,3 @@ it('should be able to save file', (test, { browserName, headful }) => {
await page.pdf({path: outputFile});
expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0);
});
it('should only have pdf in chromium', (test, { browserName }) => {
test.skip(browserName === 'chromium');
}, async ({page}) => {
expect(page.pdf).toBe(undefined);
});

674
types/types.d.ts vendored
View File

@ -1484,10 +1484,11 @@ export interface Page {
context(): BrowserContext;
/**
* Browser-specific Coverage implementation, only available for Chromium atm. See
* [ChromiumCoverage](#class-chromiumcoverage) for more details.
* > NOTE: Only available for Chromium atm.
*
* Browser-specific Coverage implementation. See [Coverage](#class-coverage) for more details.
*/
coverage: null|ChromiumCoverage;
coverage: Coverage;
/**
* This method double clicks an element matching `selector` by performing the following steps:
@ -4625,6 +4626,18 @@ export interface BrowserContext {
*/
exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise<void>;
exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise<void>;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
on(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -4656,6 +4669,25 @@ export interface BrowserContext {
*/
on(event: 'page', listener: (page: Page) => void): this;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
on(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
once(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -4687,6 +4719,25 @@ export interface BrowserContext {
*/
once(event: 'page', listener: (page: Page) => void): this;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
once(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
addListener(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -4718,6 +4769,25 @@ export interface BrowserContext {
*/
addListener(event: 'page', listener: (page: Page) => void): this;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
addListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
removeListener(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -4749,6 +4819,25 @@ export interface BrowserContext {
*/
removeListener(event: 'page', listener: (page: Page) => void): this;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
removeListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
off(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -4780,6 +4869,13 @@ export interface BrowserContext {
*/
off(event: 'page', listener: (page: Page) => void): this;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
off(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be
* obtained via
@ -4875,6 +4971,13 @@ export interface BrowserContext {
content?: string;
}, arg?: Serializable): Promise<void>;
/**
* > NOTE: Background pages are only supported on Chromium-based browsers.
*
* All existing background pages in the context.
*/
backgroundPages(): Array<Page>;
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
*/
@ -4978,6 +5081,14 @@ export interface BrowserContext {
origin?: string;
}): Promise<void>;
/**
* > NOTE: CDP sessions are only supported on Chromium-based browsers.
*
* Returns the newly created session.
* @param page Page to create new session for.
*/
newCDPSession(page: Page): Promise<CDPSession>;
/**
* Creates a new page in the browser context.
*/
@ -5024,6 +5135,13 @@ export interface BrowserContext {
*/
route(url: string|RegExp|((url: URL) => boolean), handler: ((route: Route, request: Request) => void)): Promise<void>;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* All existing service workers in the context.
*/
serviceWorkers(): Array<Worker>;
/**
* This setting will change the default maximum navigation time for the following methods and related shortcuts:
* - [page.goBack([options])](https://playwright.dev/docs/api/class-page#pagegobackoptions)
@ -5165,6 +5283,18 @@ export interface BrowserContext {
*/
unroute(url: string|RegExp|((url: URL) => boolean), handler?: ((route: Route, request: Request) => void)): Promise<void>;
/**
* > NOTE: Only works with Chromium browser's persistent context.
*
* Emitted when new background page is created in the context.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
*/
waitForEvent(event: 'backgroundpage', optionsOrPredicate?: { predicate?: (page: Page) => boolean, timeout?: number } | ((page: Page) => boolean)): Promise<Page>;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
@ -5195,6 +5325,13 @@ export interface BrowserContext {
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
waitForEvent(event: 'page', optionsOrPredicate?: { predicate?: (page: Page) => boolean, timeout?: number } | ((page: Page) => boolean)): Promise<Page>;
/**
* > NOTE: Service workers are only supported on Chromium-based browsers.
*
* Emitted when new service worker is created in the context.
*/
waitForEvent(event: 'serviceworker', optionsOrPredicate?: { predicate?: (worker: Worker) => boolean, timeout?: number } | ((worker: Worker) => boolean)): Promise<Worker>;
}
/**
@ -6865,112 +7002,6 @@ export interface BrowserType<Browser> {
*/
name(): string;}
/**
* - extends: [Browser]
*
* Chromium-specific features including Tracing, service worker support, etc. You can use
* [chromiumBrowser.startTracing([page, options])](https://playwright.dev/docs/api/class-chromiumbrowser#chromiumbrowserstarttracingpage-options)
* and [chromiumBrowser.stopTracing()](https://playwright.dev/docs/api/class-chromiumbrowser#chromiumbrowserstoptracing) to
* create a trace file which can be opened in Chrome DevTools or
* [timeline viewer](https://chromedevtools.github.io/timeline-viewer/).
*
* ```js
* await browser.startTracing(page, {path: 'trace.json'});
* await page.goto('https://www.google.com');
* await browser.stopTracing();
* ```
*
* [ChromiumBrowser] can also be used for testing Chrome Extensions.
*
* > NOTE: Extensions in Chrome / Chromium currently only work in non-headless mode.
*
* The following is code for getting a handle to the
* [background page](https://developer.chrome.com/extensions/background_pages) of an extension whose source is located in
* `./my-extension`:
*
* ```js
* const { chromium } = require('playwright');
*
* (async () => {
* const pathToExtension = require('path').join(__dirname, 'my-extension');
* const userDataDir = '/tmp/test-user-data-dir';
* const browserContext = await chromium.launchPersistentContext(userDataDir,{
* headless: false,
* args: [
* `--disable-extensions-except=${pathToExtension}`,
* `--load-extension=${pathToExtension}`
* ]
* });
* const backgroundPage = browserContext.backgroundPages()[0];
* // Test the background page as you would any other page.
* await browserContext.close();
* })();
* ```
*
*/
export interface ChromiumBrowser extends Browser {
/**
* Returns an array of all open browser contexts. In a newly created browser, this will return zero browser contexts.
*
* ```js
* const browser = await pw.webkit.launch();
* console.log(browser.contexts().length); // prints `0`
*
* const context = await browser.newContext();
* console.log(browser.contexts().length); // prints `1`
* ```
*
*/
contexts(): Array<ChromiumBrowserContext>;
/**
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
*
* ```js
* (async () => {
* const browser = await playwright.firefox.launch(); // Or 'chromium' or 'webkit'.
* // Create a new incognito browser context.
* const context = await browser.newContext();
* // Create a new page in a pristine context.
* const page = await context.newPage();
* await page.goto('https://example.com');
* })();
* ```
*
* @param options
*/
newContext(options?: BrowserContextOptions): Promise<ChromiumBrowserContext>;
/**
* Returns the newly created browser session.
*/
newBrowserCDPSession(): Promise<CDPSession>;
/**
* Only one trace can be active at a time per browser.
* @param page Optional, if specified, tracing includes screenshots of the given page.
* @param options
*/
startTracing(page?: Page, options?: {
/**
* specify custom categories to use instead of default.
*/
categories?: Array<string>;
/**
* A path to write the trace file to.
*/
path?: string;
/**
* captures screenshots in the trace.
*/
screenshots?: boolean;
}): Promise<void>;
/**
* Returns the buffer with trace data.
*/
stopTracing(): Promise<Buffer>;}
/**
* - extends: [EventEmitter]
*
@ -7817,7 +7848,7 @@ export interface AndroidDevice {
*/
height: number;
};
}): Promise<ChromiumBrowserContext>;
}): Promise<BrowserContext>;
/**
* Performs a long tap on the widget defined by `selector`.
@ -8320,6 +8351,13 @@ export interface Browser extends EventEmitter {
*/
isConnected(): boolean;
/**
* > NOTE: CDP Sessions are only supported on Chromium-based browsers.
*
* Returns the newly created browser session.
*/
newBrowserCDPSession(): Promise<CDPSession>;
/**
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
*
@ -8652,6 +8690,47 @@ export interface Browser extends EventEmitter {
};
}): Promise<Page>;
/**
* > NOTE: Tracing is only supported on Chromium-based browsers.
*
* You can use
* [browser.startTracing([page, options])](https://playwright.dev/docs/api/class-browser#browserstarttracingpage-options)
* and [browser.stopTracing()](https://playwright.dev/docs/api/class-browser#browserstoptracing) to create a trace file
* that can be opened in Chrome DevTools performance panel.
*
* ```js
* await browser.startTracing(page, {path: 'trace.json'});
* await page.goto('https://www.google.com');
* await browser.stopTracing();
* ```
*
* @param page Optional, if specified, tracing includes screenshots of the given page.
* @param options
*/
startTracing(page?: Page, options?: {
/**
* specify custom categories to use instead of default.
*/
categories?: Array<string>;
/**
* A path to write the trace file to.
*/
path?: string;
/**
* captures screenshots in the trace.
*/
screenshots?: boolean;
}): Promise<void>;
/**
* > NOTE: Tracing is only supported on Chromium-based browsers.
*
* Returns the buffer with trace data.
*/
stopTracing(): Promise<Buffer>;
/**
* Returns the browser version.
*/
@ -8710,290 +8789,37 @@ export interface BrowserServer {
}
/**
* - extends: [BrowserContext]
*
* Chromium-specific features including background pages, service worker support, etc.
*
* ```js
* const backgroundPage = await context.waitForEvent('backgroundpage');
* ```
*
* [ConsoleMessage] objects are dispatched by page via the
* [page.on('console')](https://playwright.dev/docs/api/class-page#pageonconsole) event.
*/
export interface ChromiumBrowserContext extends BrowserContext {
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
on(event: 'backgroundpage', listener: (page: Page) => void): this;
export interface ConsoleMessage {
args(): Array<JSHandle>;
location(): {
/**
* URL of the resource.
*/
url: string;
/**
* 0-based line number in the resource.
*/
lineNumber: number;
/**
* 0-based column number in the resource.
*/
columnNumber: number;
};
text(): string;
/**
* Emitted when new service worker is created in the context.
* One of the following values: `'log'`, `'debug'`, `'info'`, `'error'`, `'warning'`, `'dir'`, `'dirxml'`, `'table'`,
* `'trace'`, `'clear'`, `'startGroup'`, `'startGroupCollapsed'`, `'endGroup'`, `'assert'`, `'profile'`, `'profileEnd'`,
* `'count'`, `'timeEnd'`.
*/
on(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
on(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
on(event: 'page', listener: (page: Page) => void): this;
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
once(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when new service worker is created in the context.
*/
once(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
once(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
once(event: 'page', listener: (page: Page) => void): this;
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
addListener(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when new service worker is created in the context.
*/
addListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
addListener(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
addListener(event: 'page', listener: (page: Page) => void): this;
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
removeListener(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when new service worker is created in the context.
*/
removeListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
removeListener(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
removeListener(event: 'page', listener: (page: Page) => void): this;
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
off(event: 'backgroundpage', listener: (page: Page) => void): this;
/**
* Emitted when new service worker is created in the context.
*/
off(event: 'serviceworker', listener: (worker: Worker) => void): this;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
off(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
off(event: 'page', listener: (page: Page) => void): this;
/**
* All existing background pages in the context.
*/
backgroundPages(): Array<Page>;
/**
* Returns the newly created session.
* @param page Page to create new session for.
*/
newCDPSession(page: Page): Promise<CDPSession>;
/**
* All existing service workers in the context.
*/
serviceWorkers(): Array<Worker>;
/**
* Emitted when new background page is created in the context.
*
* > NOTE: Only works with persistent context.
*/
waitForEvent(event: 'backgroundpage', optionsOrPredicate?: { predicate?: (page: Page) => boolean, timeout?: number } | ((page: Page) => boolean)): Promise<Page>;
/**
* Emitted when new service worker is created in the context.
*/
waitForEvent(event: 'serviceworker', optionsOrPredicate?: { predicate?: (worker: Worker) => boolean, timeout?: number } | ((worker: Worker) => boolean)): Promise<Worker>;
/**
* Emitted when Browser context gets closed. This might happen because of one of the following:
* - Browser context is closed.
* - Browser application is closed or crashed.
* - The [browser.close()](https://playwright.dev/docs/api/class-browser#browserclose) method was called.
*/
waitForEvent(event: 'close', optionsOrPredicate?: { predicate?: (browserContext: BrowserContext) => boolean, timeout?: number } | ((browserContext: BrowserContext) => boolean)): Promise<BrowserContext>;
/**
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
* also fire for popup pages. See also [page.on('popup')](https://playwright.dev/docs/api/class-page#pageonpopup) to
* receive events about popups relevant to a specific page.
*
* The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with `window.open('http://example.com')`, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
*
* ```js
* const [newPage] = await Promise.all([
* context.waitForEvent('page'),
* page.click('a[target=_blank]'),
* ]);
* console.log(await newPage.evaluate('location.href'));
* ```
*
* > NOTE: Use
* [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#pagewaitforloadstatestate-options)
* to wait until the page gets to a particular state (you should not need it in most cases).
*/
waitForEvent(event: 'page', optionsOrPredicate?: { predicate?: (page: Page) => boolean, timeout?: number } | ((page: Page) => boolean)): Promise<Page>;
type(): string;
}
/**
@ -9001,6 +8827,8 @@ export interface ChromiumBrowserContext extends BrowserContext {
*
* An example of using JavaScript coverage to produce Istanbul report for page load:
*
* > NOTE: Coverage APIs are only supported on Chromium-based browsers.
*
* ```js
* const { chromium } = require('playwright');
* const v8toIstanbul = require('v8-to-istanbul');
@ -9022,7 +8850,7 @@ export interface ChromiumBrowserContext extends BrowserContext {
* ```
*
*/
export interface ChromiumCoverage {
export interface Coverage {
/**
* Returns coverage is started
* @param options
@ -9126,40 +8954,6 @@ export interface ChromiumCoverage {
}>>;
}
/**
* [ConsoleMessage] objects are dispatched by page via the
* [page.on('console')](https://playwright.dev/docs/api/class-page#pageonconsole) event.
*/
export interface ConsoleMessage {
args(): Array<JSHandle>;
location(): {
/**
* URL of the resource.
*/
url: string;
/**
* 0-based line number in the resource.
*/
lineNumber: number;
/**
* 0-based column number in the resource.
*/
columnNumber: number;
};
text(): string;
/**
* One of the following values: `'log'`, `'debug'`, `'info'`, `'error'`, `'warning'`, `'dir'`, `'dirxml'`, `'table'`,
* `'trace'`, `'clear'`, `'startGroup'`, `'startGroupCollapsed'`, `'endGroup'`, `'assert'`, `'profile'`, `'profileEnd'`,
* `'count'`, `'timeEnd'`.
*/
type(): string;
}
/**
* [Dialog] objects are dispatched by page via the
* [page.on('dialog')](https://playwright.dev/docs/api/class-page#pageondialog) event.
@ -9256,8 +9050,7 @@ export interface Download {
/**
* Returns path to the downloaded file in case of successful download. The method will wait for the download to finish if
* necessary. The method throws when connected remotely via
* [browserType.connect(params)](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams).
* necessary. The method throws when connected remotely.
*/
path(): Promise<null|string>;
@ -9438,15 +9231,6 @@ export interface FileChooser {
}): Promise<void>;
}
/**
* - extends: [Browser]
*
* Firefox browser instance does not expose Firefox-specific features.
*/
export interface FirefoxBrowser extends Browser {
}
/**
* Keyboard provides an api for managing a virtual keyboard. The high level api is
* [keyboard.type(text[, options])](https://playwright.dev/docs/api/class-keyboard#keyboardtypetext-options), which takes
@ -10241,8 +10025,7 @@ export interface Video {
/**
* Returns the file system path this video will be recorded to. The video is guaranteed to be written to the filesystem
* upon closing the browser context. This method throws when connected remotely via
* [browserType.connect(params)](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams).
* upon closing the browser context. This method throws when connected remotely.
*/
path(): Promise<string>;
@ -10254,15 +10037,6 @@ export interface Video {
saveAs(path: string): Promise<void>;
}
/**
* - extends: [Browser]
*
* WebKit browser instance does not expose WebKit-specific features.
*/
export interface WebKitBrowser extends Browser {
}
/**
* The [WebSocket] class represents websocket connections in the page.
*/
@ -11100,3 +10874,9 @@ type Devices = {
"Pixel 5 landscape": DeviceDescriptor;
[key: string]: DeviceDescriptor;
}
export interface ChromiumBrowserContext extends BrowserContext { }
export interface ChromiumBrowser extends Browser { }
export interface FirefoxBrowser extends Browser { }
export interface WebKitBrowser extends Browser { }
export interface ChromiumCoverage extends Coverage { }

View File

@ -97,6 +97,12 @@ ${overrides}
${classes.map(classDesc => classToString(classDesc)).join('\n')}
${objectDefinitionsToString(overrides)}
${generateDevicesTypes()}
export interface ChromiumBrowserContext extends BrowserContext { }
export interface ChromiumBrowser extends Browser { }
export interface FirefoxBrowser extends Browser { }
export interface WebKitBrowser extends Browser { }
export interface ChromiumCoverage extends Coverage { }
`;
for (const [key, value] of Object.entries(exported))
output = output.replace(new RegExp('\\b' + key + '\\b', 'g'), value);

View File

@ -144,11 +144,6 @@ export interface BrowserType<Browser> {
}
export interface ChromiumBrowser extends Browser {
contexts(): Array<ChromiumBrowserContext>;
newContext(options?: BrowserContextOptions): Promise<ChromiumBrowserContext>;
}
export interface CDPSession {
on: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
addListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;