feat(api): use good old inheritance instead of feature detection (#329)

This commit is contained in:
Pavel Feldman 2019-12-21 09:03:52 -08:00 committed by GitHub
parent f82039495c
commit 4638019902
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 166 additions and 157 deletions

View file

@ -142,14 +142,12 @@
* [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args-1) * [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args-1)
* [page.$wait(selector, pageFunction[, options[, ...args]])](#pagewaitselector-pagefunction-options-args) * [page.$wait(selector, pageFunction[, options[, ...args]])](#pagewaitselector-pagefunction-options-args)
* [page.$x(expression)](#pagexexpression) * [page.$x(expression)](#pagexexpression)
* [page.accessibility](#pageaccessibility)
* [page.addScriptTag(options)](#pageaddscripttagoptions) * [page.addScriptTag(options)](#pageaddscripttagoptions)
* [page.addStyleTag(options)](#pageaddstyletagoptions) * [page.addStyleTag(options)](#pageaddstyletagoptions)
* [page.browserContext()](#pagebrowsercontext) * [page.browserContext()](#pagebrowsercontext)
* [page.click(selector[, options])](#pageclickselector-options) * [page.click(selector[, options])](#pageclickselector-options)
* [page.close([options])](#pagecloseoptions) * [page.close([options])](#pagecloseoptions)
* [page.content()](#pagecontent) * [page.content()](#pagecontent)
* [page.coverage](#pagecoverage)
* [page.dblclick(selector[, options])](#pagedblclickselector-options) * [page.dblclick(selector[, options])](#pagedblclickselector-options)
* [page.emulateMedia(options)](#pageemulatemediaoptions) * [page.emulateMedia(options)](#pageemulatemediaoptions)
* [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args) * [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
@ -163,12 +161,10 @@
* [page.goForward([options])](#pagegoforwardoptions) * [page.goForward([options])](#pagegoforwardoptions)
* [page.goto(url[, options])](#pagegotourl-options) * [page.goto(url[, options])](#pagegotourl-options)
* [page.hover(selector[, options])](#pagehoverselector-options) * [page.hover(selector[, options])](#pagehoverselector-options)
* [page.interception](#pageinterception)
* [page.isClosed()](#pageisclosed) * [page.isClosed()](#pageisclosed)
* [page.keyboard](#pagekeyboard) * [page.keyboard](#pagekeyboard)
* [page.mainFrame()](#pagemainframe) * [page.mainFrame()](#pagemainframe)
* [page.mouse](#pagemouse) * [page.mouse](#pagemouse)
* [page.pdf](#pagepdf)
* [page.reload([options])](#pagereloadoptions) * [page.reload([options])](#pagereloadoptions)
* [page.screenshot([options])](#pagescreenshotoptions) * [page.screenshot([options])](#pagescreenshotoptions)
* [page.select(selector, value, options)](#pageselectselector-value-options) * [page.select(selector, value, options)](#pageselectselector-value-options)
@ -191,7 +187,6 @@
* [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options) * [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options)
* [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options) * [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options)
* [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options) * [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
* [page.workers](#pageworkers)
- [class: Request](#class-request) - [class: Request](#class-request)
* [request.failure()](#requestfailure) * [request.failure()](#requestfailure)
* [request.frame()](#requestframe) * [request.frame()](#requestframe)
@ -244,8 +239,6 @@
* [chromiumInterception.setOfflineMode(enabled)](#chromiuminterceptionsetofflinemodeenabled) * [chromiumInterception.setOfflineMode(enabled)](#chromiuminterceptionsetofflinemodeenabled)
- [class: ChromiumOverrides](#class-chromiumoverrides) - [class: ChromiumOverrides](#class-chromiumoverrides)
* [chromiumOverrides.setGeolocation(options)](#chromiumoverridessetgeolocationoptions) * [chromiumOverrides.setGeolocation(options)](#chromiumoverridessetgeolocationoptions)
- [class: ChromiumPDF](#class-chromiumpdf)
* [chromiumPDF.generate([options])](#chromiumpdfgenerateoptions)
- [class: ChromiumPlaywright](#class-chromiumplaywright) - [class: ChromiumPlaywright](#class-chromiumplaywright)
* [chromiumPlaywright.connect(options)](#chromiumplaywrightconnectoptions) * [chromiumPlaywright.connect(options)](#chromiumplaywrightconnectoptions)
* [chromiumPlaywright.createBrowserFetcher([options])](#chromiumplaywrightcreatebrowserfetcheroptions) * [chromiumPlaywright.createBrowserFetcher([options])](#chromiumplaywrightcreatebrowserfetcheroptions)
@ -256,6 +249,14 @@
* [chromiumPlaywright.executablePath()](#chromiumplaywrightexecutablepath) * [chromiumPlaywright.executablePath()](#chromiumplaywrightexecutablepath)
* [chromiumPlaywright.launch([options])](#chromiumplaywrightlaunchoptions) * [chromiumPlaywright.launch([options])](#chromiumplaywrightlaunchoptions)
* [chromiumPlaywright.launchServer([options])](#chromiumplaywrightlaunchserveroptions) * [chromiumPlaywright.launchServer([options])](#chromiumplaywrightlaunchserveroptions)
- [class: ChromiumPage](#class-chromiumpage)
* [event: 'workercreated'](#event-workercreated)
* [event: 'workerdestroyed'](#event-workerdestroyed)
* [chromiumPage.accessibility](#chromiumpageaccessibility)
* [chromiumPage.coverage](#chromiumpagecoverage)
* [chromiumPage.interception](#chromiumpageinterception)
* [chromiumPage.pdf([options])](#chromiumpagepdfoptions)
* [chromiumPage.workers()](#chromiumpageworkers)
- [class: ChromiumSession](#class-chromiumsession) - [class: ChromiumSession](#class-chromiumsession)
* [chromiumSession.detach()](#chromiumsessiondetach) * [chromiumSession.detach()](#chromiumsessiondetach)
* [chromiumSession.send(method[, params])](#chromiumsessionsendmethod-params) * [chromiumSession.send(method[, params])](#chromiumsessionsendmethod-params)
@ -270,10 +271,6 @@
* [chromiumWorker.evaluate(pageFunction[, ...args])](#chromiumworkerevaluatepagefunction-args) * [chromiumWorker.evaluate(pageFunction[, ...args])](#chromiumworkerevaluatepagefunction-args)
* [chromiumWorker.evaluateHandle(pageFunction[, ...args])](#chromiumworkerevaluatehandlepagefunction-args) * [chromiumWorker.evaluateHandle(pageFunction[, ...args])](#chromiumworkerevaluatehandlepagefunction-args)
* [chromiumWorker.url()](#chromiumworkerurl) * [chromiumWorker.url()](#chromiumworkerurl)
- [class: ChromiumWorkers](#class-chromiumworkers)
* [event: 'workercreated'](#event-workercreated)
* [event: 'workerdestroyed'](#event-workerdestroyed)
* [chromiumWorkers.list()](#chromiumworkerslist)
- [class: FirefoxBrowser](#class-firefoxbrowser) - [class: FirefoxBrowser](#class-firefoxbrowser)
- [class: WebKitBrowser](#class-webkitbrowser) - [class: WebKitBrowser](#class-webkitbrowser)
- [Working with selectors](#working-with-selectors) - [Working with selectors](#working-with-selectors)
@ -1897,9 +1894,6 @@ The method evaluates the XPath expression.
Shortcut for [page.mainFrame().$x(expression)](#framexexpression) Shortcut for [page.mainFrame().$x(expression)](#framexexpression)
#### page.accessibility
- returns: <[Accessibility]>
#### page.addScriptTag(options) #### page.addScriptTag(options)
- `options` <[Object]> - `options` <[Object]>
- `url` <[string]> URL of a script to be added. - `url` <[string]> URL of a script to be added.
@ -1975,10 +1969,6 @@ By default, `page.close()` **does not** run beforeunload handlers.
Gets the full HTML contents of the page, including the doctype. Gets the full HTML contents of the page, including the doctype.
#### page.coverage
- returns: <[Coverage]>
#### page.dblclick(selector[, options]) #### page.dblclick(selector[, options])
- `selector` <[string]> A selector to search for element to double click. If there are multiple elements satisfying the selector, the first will be double clicked. - `selector` <[string]> A selector to search for element to double click. If there are multiple elements satisfying the selector, the first will be double clicked.
- `options` <[Object]> - `options` <[Object]>
@ -2281,9 +2271,6 @@ If there's no element matching `selector`, the method throws an error.
Shortcut for [page.mainFrame().hover(selector)](#framehoverselector). Shortcut for [page.mainFrame().hover(selector)](#framehoverselector).
#### page.interception
- returns: <[Interception]>
#### page.isClosed() #### page.isClosed()
- returns: <[boolean]> - returns: <[boolean]>
@ -2303,9 +2290,6 @@ Page is guaranteed to have a main frame which persists during navigations.
- returns: <[Mouse]> - returns: <[Mouse]>
#### page.pdf
- returns: <[PDF]>
#### page.reload([options]) #### page.reload([options])
- `options` <[Object]> Navigation parameters which might have the following properties: - `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods. - `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
@ -2692,11 +2676,6 @@ const playwright = require('playwright');
``` ```
Shortcut for [page.mainFrame().waitForSelector(selector[, options])](#framewaitforselectorselector-options). Shortcut for [page.mainFrame().waitForSelector(selector[, options])](#framewaitforselectorselector-options).
#### page.workers
- returns: <[Workers]>
> **NOTE** This does not contain ServiceWorkers
### class: Request ### class: Request
Whenever the page sends a request, such as for a network resource, the following events are emitted by playwright's page: Whenever the page sends a request, such as for a network resource, the following events are emitted by playwright's page:
@ -3202,76 +3181,6 @@ await browserContext.overrides.setGeolocation({latitude: 59.95, longitude: 30.31
> **NOTE** Consider using [browserContext.setPermissions](#browsercontextsetpermissions-permissions) to grant permissions for the page to read its geolocation. > **NOTE** Consider using [browserContext.setPermissions](#browsercontextsetpermissions-permissions) to grant permissions for the page to read its geolocation.
### class: ChromiumPDF
#### chromiumPDF.generate([options])
- `options` <[Object]> Options object which might have the following properties:
- `path` <[string]> The file path to save the PDF to. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the PDF won't be saved to the disk.
- `scale` <[number]> Scale of the webpage rendering. Defaults to `1`. Scale amount must be between 0.1 and 2.
- `displayHeaderFooter` <[boolean]> Display header and footer. Defaults to `false`.
- `headerTemplate` <[string]> HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them:
- `'date'` formatted print date
- `'title'` document title
- `'url'` document location
- `'pageNumber'` current page number
- `'totalPages'` total pages in the document
- `footerTemplate` <[string]> HTML template for the print footer. Should use the same format as the `headerTemplate`.
- `printBackground` <[boolean]> Print background graphics. Defaults to `false`.
- `landscape` <[boolean]> Paper orientation. Defaults to `false`.
- `pageRanges` <[string]> Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
- `format` <[string]> Paper format. If set, takes priority over `width` or `height` options. Defaults to 'Letter'.
- `width` <[string]|[number]> Paper width, accepts values labeled with units.
- `height` <[string]|[number]> Paper height, accepts values labeled with units.
- `margin` <[Object]> Paper margins, defaults to none.
- `top` <[string]|[number]> Top margin, accepts values labeled with units.
- `right` <[string]|[number]> Right margin, accepts values labeled with units.
- `bottom` <[string]|[number]> Bottom margin, accepts values labeled with units.
- `left` <[string]|[number]> Left margin, accepts values labeled with units.
- `preferCSSPageSize` <[boolean]> Give any CSS `@page` size declared in the page priority over what is declared in `width` and `height` or `format` options. Defaults to `false`, which will scale the content to fit the paper size.
- returns: <[Promise]<[Buffer]>> Promise which resolves with PDF buffer.
> **NOTE** Generating a pdf is currently only supported in Chrome headless.
`pdf.generate()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call [page.emulateMedia({ type: 'screen' })](#pageemulatemedia) before calling `pdf.generate()`:
> **NOTE** By default, `pdf.generate()` generates a pdf with modified colors for printing. Use the [`-webkit-print-color-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust) property to force rendering of exact colors.
```js
// Generates a PDF with 'screen' media type.
await page.emulateMedia({type: 'screen'});
await page.pdf.generate({path: 'page.pdf'});
```
The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels.
A few examples:
- `page.pdf.generate({width: 100})` - prints with width set to 100 pixels
- `page.pdf.generate({width: '100px'})` - prints with width set to 100 pixels
- `page.pdf.generate({width: '10cm'})` - prints with width set to 10 centimeters.
All possible units are:
- `px` - pixel
- `in` - inch
- `cm` - centimeter
- `mm` - millimeter
The `format` options are:
- `Letter`: 8.5in x 11in
- `Legal`: 8.5in x 14in
- `Tabloid`: 11in x 17in
- `Ledger`: 17in x 11in
- `A0`: 33.1in x 46.8in
- `A1`: 23.4in x 33.1in
- `A2`: 16.54in x 23.4in
- `A3`: 11.7in x 16.54in
- `A4`: 8.27in x 11.7in
- `A5`: 5.83in x 8.27in
- `A6`: 4.13in x 5.83in
> **NOTE** `headerTemplate` and `footerTemplate` markup have the following limitations:
> 1. Script tags inside templates are not evaluated.
> 2. Page styles are not visible inside templates.
### class: ChromiumPlaywright ### class: ChromiumPlaywright
Playwright module provides a method to launch a Chromium instance. Playwright module provides a method to launch a Chromium instance.
@ -3431,6 +3340,105 @@ const browser = await playwright.launch({
- `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`. - `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
- returns: <[Promise]<[BrowserServer]>> Promise which resolves to browser server instance. - returns: <[Promise]<[BrowserServer]>> Promise which resolves to browser server instance.
### class: ChromiumPage
* extends: [Page]
The ChromiumPage class represents a Chromium-specific extension of the page.
#### event: 'workercreated'
- <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page.
#### event: 'workerdestroyed'
- <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is terminated.
#### chromiumPage.accessibility
- returns: <[Accessibility]>
#### chromiumPage.coverage
- returns: <[Coverage]>
#### chromiumPage.interception
- returns: <[Interception]>
#### chromiumPage.pdf([options])
- `options` <[Object]> Options object which might have the following properties:
- `path` <[string]> The file path to save the PDF to. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the PDF won't be saved to the disk.
- `scale` <[number]> Scale of the webpage rendering. Defaults to `1`. Scale amount must be between 0.1 and 2.
- `displayHeaderFooter` <[boolean]> Display header and footer. Defaults to `false`.
- `headerTemplate` <[string]> HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them:
- `'date'` formatted print date
- `'title'` document title
- `'url'` document location
- `'pageNumber'` current page number
- `'totalPages'` total pages in the document
- `footerTemplate` <[string]> HTML template for the print footer. Should use the same format as the `headerTemplate`.
- `printBackground` <[boolean]> Print background graphics. Defaults to `false`.
- `landscape` <[boolean]> Paper orientation. Defaults to `false`.
- `pageRanges` <[string]> Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
- `format` <[string]> Paper format. If set, takes priority over `width` or `height` options. Defaults to 'Letter'.
- `width` <[string]|[number]> Paper width, accepts values labeled with units.
- `height` <[string]|[number]> Paper height, accepts values labeled with units.
- `margin` <[Object]> Paper margins, defaults to none.
- `top` <[string]|[number]> Top margin, accepts values labeled with units.
- `right` <[string]|[number]> Right margin, accepts values labeled with units.
- `bottom` <[string]|[number]> Bottom margin, accepts values labeled with units.
- `left` <[string]|[number]> Left margin, accepts values labeled with units.
- `preferCSSPageSize` <[boolean]> Give any CSS `@page` size declared in the page priority over what is declared in `width` and `height` or `format` options. Defaults to `false`, which will scale the content to fit the paper size.
- returns: <[Promise]<[Buffer]>> Promise which resolves with PDF buffer.
> **NOTE** Generating a pdf is currently only supported in Chrome headless.
`page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call [page.emulateMedia({ type: 'screen' })](#pageemulatemedia) before calling `page.pdf()`:
> **NOTE** By default, `page.pdf()` generates a pdf with modified colors for printing. Use the [`-webkit-print-color-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust) property to force rendering of exact colors.
```js
// Generates a PDF with 'screen' media type.
await page.emulateMedia({type: 'screen'});
await page.pdf({path: 'page.pdf'});
```
The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels.
A few examples:
- `page.pdf({width: 100})` - prints with width set to 100 pixels
- `page.pdf({width: '100px'})` - prints with width set to 100 pixels
- `page.pdf({width: '10cm'})` - prints with width set to 10 centimeters.
All possible units are:
- `px` - pixel
- `in` - inch
- `cm` - centimeter
- `mm` - millimeter
The `format` options are:
- `Letter`: 8.5in x 11in
- `Legal`: 8.5in x 14in
- `Tabloid`: 11in x 17in
- `Ledger`: 17in x 11in
- `A0`: 33.1in x 46.8in
- `A1`: 23.4in x 33.1in
- `A2`: 16.54in x 23.4in
- `A3`: 11.7in x 16.54in
- `A4`: 8.27in x 11.7in
- `A5`: 5.83in x 8.27in
- `A6`: 4.13in x 5.83in
> **NOTE** `headerTemplate` and `footerTemplate` markup have the following limitations:
> 1. Script tags inside templates are not evaluated.
> 2. Page styles are not visible inside templates.
#### chromiumPage.workers()
- returns: <[Array]<[Worker]>>
This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) associated with the page.
> **NOTE** This does not contain ServiceWorkers
### class: ChromiumSession ### class: ChromiumSession
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) * extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
@ -3502,8 +3510,8 @@ The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/do
The events `workercreated` and `workerdestroyed` are emitted on the page object to signal the worker lifecycle. The events `workercreated` and `workerdestroyed` are emitted on the page object to signal the worker lifecycle.
```js ```js
page.workers.on('workercreated', worker => console.log('Worker created: ' + worker.url())); page.on('workercreated', worker => console.log('Worker created: ' + worker.url()));
page.workers.on('workerdestroyed', worker => console.log('Worker destroyed: ' + worker.url())); page.on('workerdestroyed', worker => console.log('Worker destroyed: ' + worker.url()));
console.log('Current workers:'); console.log('Current workers:');
for (const worker of page.workers()) for (const worker of page.workers())
@ -3531,26 +3539,6 @@ If the function passed to the `worker.evaluateHandle` returns a [Promise], then
#### chromiumWorker.url() #### chromiumWorker.url()
- returns: <[string]> - returns: <[string]>
### class: ChromiumWorkers
The Workers class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) collection.
#### event: 'workercreated'
- <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page.
#### event: 'workerdestroyed'
- <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is terminated.
#### chromiumWorkers.list()
- returns: <[Array]<[Worker]>>
This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) associated with the page.
> **NOTE** This does not contain ServiceWorkers
### class: FirefoxBrowser ### class: FirefoxBrowser
* extends: [Browser] * extends: [Browser]

View file

@ -3,11 +3,11 @@
export { CRBrowser as ChromiumBrowser } from './crBrowser'; export { CRBrowser as ChromiumBrowser } from './crBrowser';
export { CRSession as ChromiumSession } from './crConnection'; export { CRSession as ChromiumSession } from './crConnection';
export { CRPage as ChromiumPage } from './crFrameManager';
export { CRPlaywright as ChromiumPlaywright } from './crPlaywright'; export { CRPlaywright as ChromiumPlaywright } from './crPlaywright';
export { CRTarget as ChromiumTarget } from './crTarget'; export { CRTarget as ChromiumTarget } from './crTarget';
export { CRAccessibility as ChromiumAccessibility } from './features/crAccessibility'; export { CRAccessibility as ChromiumAccessibility } from './features/crAccessibility';
export { CRCoverage as ChromiumCoverage } from './features/crCoverage'; export { CRCoverage as ChromiumCoverage } from './features/crCoverage';
export { CRInterception as ChromiumInterception } from './features/crInterception'; export { CRInterception as ChromiumInterception } from './features/crInterception';
export { CROverrides as ChromiumOverrides } from './features/crOverrides'; export { CROverrides as ChromiumOverrides } from './features/crOverrides';
export { CRPDF as ChromiumPDF } from './features/crPdf'; export { CRWorker as ChromiumWorker } from './features/crWorkers';
export { CRWorker as ChromiumWorker, CRWorkers as ChromiumWorkers } from './features/crWorkers';

View file

@ -31,8 +31,8 @@ import { PageDelegate } from '../page';
import { RawMouseImpl, RawKeyboardImpl } from './crInput'; import { RawMouseImpl, RawKeyboardImpl } from './crInput';
import { CRAccessibility } from './features/crAccessibility'; import { CRAccessibility } from './features/crAccessibility';
import { CRCoverage } from './features/crCoverage'; import { CRCoverage } from './features/crCoverage';
import { CRPDF } from './features/crPdf'; import { CRPDF, PDFOptions } from './features/crPdf';
import { CRWorkers } from './features/crWorkers'; import { CRWorkers, CRWorker } from './features/crWorkers';
import { CRInterception } from './features/crInterception'; import { CRInterception } from './features/crInterception';
import { CRBrowser } from './crBrowser'; import { CRBrowser } from './crBrowser';
import { BrowserContext } from '../browserContext'; import { BrowserContext } from '../browserContext';
@ -44,7 +44,7 @@ const UTILITY_WORLD_NAME = '__playwright_utility_world__';
export class CRFrameManager implements PageDelegate { export class CRFrameManager implements PageDelegate {
_client: CRSession; _client: CRSession;
private _page: Page; private _page: CRPage;
readonly _networkManager: CRNetworkManager; readonly _networkManager: CRNetworkManager;
private _contextIdToContext = new Map<number, dom.FrameExecutionContext>(); private _contextIdToContext = new Map<number, dom.FrameExecutionContext>();
private _isolatedWorlds = new Set<string>(); private _isolatedWorlds = new Set<string>();
@ -58,13 +58,8 @@ export class CRFrameManager implements PageDelegate {
this._browser = browser; this._browser = browser;
this.rawKeyboard = new RawKeyboardImpl(client); this.rawKeyboard = new RawKeyboardImpl(client);
this.rawMouse = new RawMouseImpl(client); this.rawMouse = new RawMouseImpl(client);
this._page = new Page(this, browserContext); this._page = new CRPage(client, this, browserContext);
this._networkManager = new CRNetworkManager(client, this._page); this._networkManager = this._page._networkManager;
(this._page as any).accessibility = new CRAccessibility(client);
(this._page as any).coverage = new CRCoverage(client);
(this._page as any).pdf = new CRPDF(client);
(this._page as any).workers = new CRWorkers(client, this._page._addConsoleMessage.bind(this._page), error => this._page.emit(Events.Page.PageError, error));
(this._page as any).interception = new CRInterception(this._networkManager);
this._eventListeners = [ this._eventListeners = [
helper.addEventListener(client, 'Inspector.targetCrashed', event => this._onTargetCrashed()), helper.addEventListener(client, 'Inspector.targetCrashed', event => this._onTargetCrashed()),
@ -454,6 +449,33 @@ export class CRFrameManager implements PageDelegate {
} }
} }
export class CRPage extends Page {
readonly accessibility: CRAccessibility;
readonly coverage: CRCoverage;
readonly interception: CRInterception;
private _pdf: CRPDF;
private _workers: CRWorkers;
_networkManager: CRNetworkManager;
constructor(client: CRSession, delegate: CRFrameManager, browserContext: BrowserContext) {
super(delegate, browserContext);
this.accessibility = new CRAccessibility(client);
this.coverage = new CRCoverage(client);
this._pdf = new CRPDF(client);
this._workers = new CRWorkers(client, this, this._addConsoleMessage.bind(this), error => this.emit(Events.Page.PageError, error));
this._networkManager = new CRNetworkManager(client, this);
this.interception = new CRInterception(this._networkManager);
}
async pdf(options?: PDFOptions): Promise<Buffer> {
return this._pdf.generate(options);
}
workers(): CRWorker[] {
return this._workers.list();
}
}
function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject { function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject {
return handle._remoteObject as Protocol.Runtime.RemoteObject; return handle._remoteObject as Protocol.Runtime.RemoteObject;
} }

View file

@ -22,7 +22,7 @@ export const Events = {
TargetChanged: 'targetchanged', TargetChanged: 'targetchanged',
}, },
CRWorkers: { CRPage: {
WorkerCreated: 'workercreated', WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed', WorkerDestroyed: 'workerdestroyed',
} }

View file

@ -19,7 +19,7 @@ import { assert, helper } from '../../helper';
import { CRSession } from '../crConnection'; import { CRSession } from '../crConnection';
import { readProtocolStream } from '../crProtocolHelper'; import { readProtocolStream } from '../crProtocolHelper';
type PDFOptions = { export type PDFOptions = {
scale?: number, scale?: number,
displayHeaderFooter?: boolean, displayHeaderFooter?: boolean,
headerTemplate?: string, headerTemplate?: string,

View file

@ -25,29 +25,28 @@ import * as js from '../../javascript';
import * as console from '../../console'; import * as console from '../../console';
import { CRExecutionContext } from '../crExecutionContext'; import { CRExecutionContext } from '../crExecutionContext';
import { toConsoleMessageLocation, exceptionToError } from '../crProtocolHelper'; import { toConsoleMessageLocation, exceptionToError } from '../crProtocolHelper';
import { CRPage } from '../crFrameManager';
type AddToConsoleCallback = (type: string, args: js.JSHandle[], location: console.ConsoleMessageLocation) => void; type AddToConsoleCallback = (type: string, args: js.JSHandle[], location: console.ConsoleMessageLocation) => void;
type HandleExceptionCallback = (error: Error) => void; type HandleExceptionCallback = (error: Error) => void;
export class CRWorkers extends EventEmitter { export class CRWorkers {
private _workers = new Map<string, CRWorker>(); private _workers = new Map<string, CRWorker>();
constructor(client: CRSession, addToConsole: AddToConsoleCallback, handleException: HandleExceptionCallback) { constructor(client: CRSession, page: CRPage, addToConsole: AddToConsoleCallback, handleException: HandleExceptionCallback) {
super();
client.on('Target.attachedToTarget', event => { client.on('Target.attachedToTarget', event => {
if (event.targetInfo.type !== 'worker') if (event.targetInfo.type !== 'worker')
return; return;
const session = CRConnection.fromSession(client).session(event.sessionId); const session = CRConnection.fromSession(client).session(event.sessionId);
const worker = new CRWorker(session, event.targetInfo.url, addToConsole, handleException); const worker = new CRWorker(session, event.targetInfo.url, addToConsole, handleException);
this._workers.set(event.sessionId, worker); this._workers.set(event.sessionId, worker);
this.emit(Events.CRWorkers.WorkerCreated, worker); page.emit(Events.CRPage.WorkerCreated, worker);
}); });
client.on('Target.detachedFromTarget', event => { client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId); const worker = this._workers.get(event.sessionId);
if (!worker) if (!worker)
return; return;
this.emit(Events.CRWorkers.WorkerDestroyed, worker); page.emit(Events.CRPage.WorkerDestroyed, worker);
this._workers.delete(event.sessionId); this._workers.delete(event.sessionId);
}); });
} }

View file

@ -208,9 +208,9 @@ export class Page extends EventEmitter {
await this._delegate.exposeBinding(name, helper.evaluationString(addPageBinding, name)); await this._delegate.exposeBinding(name, helper.evaluationString(addPageBinding, name));
function addPageBinding(bindingName: string) { function addPageBinding(bindingName: string) {
const binding = window[bindingName]; const binding = (window as any)[bindingName];
window[bindingName] = (...args) => { (window as any)[bindingName] = (...args: any[]) => {
const me = window[bindingName]; const me = (window as any)[bindingName];
let callbacks = me['callbacks']; let callbacks = me['callbacks'];
if (!callbacks) { if (!callbacks) {
callbacks = new Map(); callbacks = new Map();
@ -250,20 +250,20 @@ export class Page extends EventEmitter {
context.evaluate(expression).catch(debugError); context.evaluate(expression).catch(debugError);
function deliverResult(name: string, seq: number, result: any) { function deliverResult(name: string, seq: number, result: any) {
window[name]['callbacks'].get(seq).resolve(result); (window as any)[name]['callbacks'].get(seq).resolve(result);
window[name]['callbacks'].delete(seq); (window as any)[name]['callbacks'].delete(seq);
} }
function deliverError(name: string, seq: number, message: string, stack: string) { function deliverError(name: string, seq: number, message: string, stack: string) {
const error = new Error(message); const error = new Error(message);
error.stack = stack; error.stack = stack;
window[name]['callbacks'].get(seq).reject(error); (window as any)[name]['callbacks'].get(seq).reject(error);
window[name]['callbacks'].delete(seq); (window as any)[name]['callbacks'].delete(seq);
} }
function deliverErrorValue(name: string, seq: number, value: any) { function deliverErrorValue(name: string, seq: number, value: any) {
window[name]['callbacks'].get(seq).reject(value); (window as any)[name]['callbacks'].get(seq).reject(value);
window[name]['callbacks'].delete(seq); (window as any)[name]['callbacks'].delete(seq);
} }
} }

View file

@ -26,7 +26,7 @@ module.exports.describe = function({testRunner, expect, headless, ASSETS_DIR}) {
describe.skip(!headless)('Page.pdf', function() { describe.skip(!headless)('Page.pdf', function() {
it('should be able to save file', async({page, server}) => { it('should be able to save file', async({page, server}) => {
const outputFile = path.join(ASSETS_DIR, 'output.pdf'); const outputFile = path.join(ASSETS_DIR, 'output.pdf');
await page.pdf.generate({path: outputFile}); await page.pdf({path: outputFile});
expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0); expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0);
fs.unlinkSync(outputFile); fs.unlinkSync(outputFile);
}); });

View file

@ -26,22 +26,22 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
describe('Workers', function() { describe('Workers', function() {
it('Page.workers', async function({page, server}) { it('Page.workers', async function({page, server}) {
await Promise.all([ await Promise.all([
new Promise(x => page.workers.once('workercreated', x)), new Promise(x => page.once('workercreated', x)),
page.goto(server.PREFIX + '/worker/worker.html')]); page.goto(server.PREFIX + '/worker/worker.html')]);
const worker = page.workers.list()[0]; const worker = page.workers()[0];
expect(worker.url()).toContain('worker.js'); expect(worker.url()).toContain('worker.js');
expect(await worker.evaluate(() => self['workerFunction']())).toBe('worker function result'); expect(await worker.evaluate(() => self['workerFunction']())).toBe('worker function result');
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expect(page.workers.list().length).toBe(0); expect(page.workers().length).toBe(0);
}); });
it('should emit created and destroyed events', async function({page}) { it('should emit created and destroyed events', async function({page}) {
const workerCreatedPromise = new Promise(x => page.workers.once('workercreated', x)); const workerCreatedPromise = new Promise(x => page.once('workercreated', x));
const workerObj = await page.evaluateHandle(() => new Worker('data:text/javascript,1')); const workerObj = await page.evaluateHandle(() => new Worker('data:text/javascript,1'));
const worker = await workerCreatedPromise; const worker = await workerCreatedPromise;
const workerThisObj = await worker.evaluateHandle(() => this); const workerThisObj = await worker.evaluateHandle(() => this);
const workerDestroyedPromise = new Promise(x => page.workers.once('workerdestroyed', x)); const workerDestroyedPromise = new Promise(x => page.once('workerdestroyed', x));
await page.evaluate(workerObj => workerObj.terminate(), workerObj); await page.evaluate(workerObj => workerObj.terminate(), workerObj);
expect(await workerDestroyedPromise).toBe(worker); expect(await workerDestroyedPromise).toBe(worker);
const error = await workerThisObj.getProperty('self').catch(error => error); const error = await workerThisObj.getProperty('self').catch(error => error);
@ -68,7 +68,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null'); expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null');
}); });
it('should evaluate', async function({page}) { it('should evaluate', async function({page}) {
const workerCreatedPromise = new Promise(x => page.workers.once('workercreated', x)); const workerCreatedPromise = new Promise(x => page.once('workercreated', x));
await page.evaluate(() => new Worker(`data:text/javascript,console.log(1)`)); await page.evaluate(() => new Worker(`data:text/javascript,console.log(1)`));
const worker = await workerCreatedPromise; const worker = await workerCreatedPromise;
expect(await worker.evaluate('1+1')).toBe(2); expect(await worker.evaluate('1+1')).toBe(2);