mirror of
https://github.com/microsoft/playwright.git
synced 2024-09-21 09:27:30 +03:00
chore: make targets chromium feature (#137)
This commit is contained in:
parent
3305363f2a
commit
e1c4eaae28
164
docs/api.md
164
docs/api.md
@ -28,9 +28,6 @@
|
||||
* [browserFetcher.revisionInfo(revision)](#browserfetcherrevisioninforevision)
|
||||
- [class: Browser](#class-browser)
|
||||
* [event: 'disconnected'](#event-disconnected)
|
||||
* [event: 'targetchanged'](#event-targetchanged)
|
||||
* [event: 'targetcreated'](#event-targetcreated)
|
||||
* [event: 'targetdestroyed'](#event-targetdestroyed)
|
||||
* [browser.browserContexts()](#browserbrowsercontexts)
|
||||
* [browser.chromium](#browserchromium)
|
||||
* [browser.close()](#browserclose)
|
||||
@ -41,14 +38,9 @@
|
||||
* [browser.newPage()](#browsernewpage)
|
||||
* [browser.pages()](#browserpages)
|
||||
* [browser.process()](#browserprocess)
|
||||
* [browser.targets()](#browsertargets)
|
||||
* [browser.userAgent()](#browseruseragent)
|
||||
* [browser.version()](#browserversion)
|
||||
* [browser.waitForTarget(predicate[, options])](#browserwaitfortargetpredicate-options)
|
||||
- [class: BrowserContext](#class-browsercontext)
|
||||
* [event: 'targetchanged'](#event-targetchanged-1)
|
||||
* [event: 'targetcreated'](#event-targetcreated-1)
|
||||
* [event: 'targetdestroyed'](#event-targetdestroyed-1)
|
||||
* [browserContext.browser()](#browsercontextbrowser)
|
||||
* [browserContext.clearCookies()](#browsercontextclearcookies)
|
||||
* [browserContext.close()](#browsercontextclose)
|
||||
@ -58,8 +50,6 @@
|
||||
* [browserContext.pages()](#browsercontextpages)
|
||||
* [browserContext.permissions](#browsercontextpermissions)
|
||||
* [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
|
||||
* [browserContext.targets()](#browsercontexttargets)
|
||||
* [browserContext.waitForTarget(predicate[, options])](#browsercontextwaitfortargetpredicate-options)
|
||||
- [class: Overrides](#class-overrides)
|
||||
* [overrides.setGeolocation(options)](#overridessetgeolocationoptions)
|
||||
* [overrides.setTimezone(timezoneId)](#overridessettimezonetimezoneid)
|
||||
@ -129,7 +119,6 @@
|
||||
* [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
|
||||
* [page.setUserAgent(userAgent)](#pagesetuseragentuseragent)
|
||||
* [page.setViewport(viewport)](#pagesetviewportviewport)
|
||||
* [page.target()](#pagetarget)
|
||||
* [page.title()](#pagetitle)
|
||||
* [page.tripleclick(selector[, options])](#pagetripleclickselector-options)
|
||||
* [page.type(selector, text[, options])](#pagetypeselector-text-options)
|
||||
@ -171,11 +160,16 @@
|
||||
- [class: PDF](#class-pdf)
|
||||
* [pdf.generate([options])](#pdfgenerateoptions)
|
||||
- [class: Chromium](#class-chromium)
|
||||
* [chromium.createBrowserCDPSession()](#chromiumcreatebrowsercdpsession)
|
||||
* [chromium.createCDPSession(target)](#chromiumcreatecdpsessiontarget)
|
||||
* [event: 'targetchanged'](#event-targetchanged)
|
||||
* [event: 'targetcreated'](#event-targetcreated)
|
||||
* [event: 'targetdestroyed'](#event-targetdestroyed)
|
||||
* [chromium.browserTarget()](#chromiumbrowsertarget)
|
||||
* [chromium.pageTarget(page)](#chromiumpagetargetpage)
|
||||
* [chromium.serviceWorker(target)](#chromiumserviceworkertarget)
|
||||
* [chromium.startTracing(page, [options])](#chromiumstarttracingpage-options)
|
||||
* [chromium.stopTracing()](#chromiumstoptracing)
|
||||
* [chromium.targets(context)](#chromiumtargetscontext)
|
||||
* [chromium.waitForTarget(predicate[, options])](#chromiumwaitfortargetpredicate-options)
|
||||
* [chromium.wsEndpoint()](#chromiumwsendpoint)
|
||||
- [class: Dialog](#class-dialog)
|
||||
* [dialog.accept([promptText])](#dialogacceptprompttext)
|
||||
@ -297,6 +291,7 @@
|
||||
- [class: Target](#class-target)
|
||||
* [target.browser()](#targetbrowser)
|
||||
* [target.browserContext()](#targetbrowsercontext)
|
||||
* [target.createCDPSession()](#targetcreatecdpsession)
|
||||
* [target.opener()](#targetopener)
|
||||
* [target.page()](#targetpage)
|
||||
* [target.type()](#targettype)
|
||||
@ -353,7 +348,7 @@ const playwright = require('playwright');
|
||||
`--load-extension=${pathToExtension}`
|
||||
]
|
||||
});
|
||||
const targets = await browser.targets();
|
||||
const targets = await browser.chromium.targets();
|
||||
const backgroundPageTarget = targets.find(target => target.type() === 'background_page');
|
||||
const backgroundPage = await backgroundPageTarget.page();
|
||||
// Test the background page as you would any other page.
|
||||
@ -601,28 +596,6 @@ Emitted when Playwright gets disconnected from the Chromium instance. This might
|
||||
- Chromium is closed or crashed
|
||||
- The [`browser.disconnect`](#browserdisconnect) method was called
|
||||
|
||||
#### event: 'targetchanged'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when the url of a target changes.
|
||||
|
||||
> **NOTE** This includes target changes in incognito browser contexts.
|
||||
|
||||
|
||||
#### event: 'targetcreated'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a target is created, for example when a new page is opened by [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) or [`browser.newPage`](#browsernewpage).
|
||||
|
||||
> **NOTE** This includes target creations in incognito browser contexts.
|
||||
|
||||
#### event: 'targetdestroyed'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a target is destroyed, for example when a page is closed.
|
||||
|
||||
> **NOTE** This includes target destructions in incognito browser contexts.
|
||||
|
||||
#### browser.browserContexts()
|
||||
- returns: <[Array]<[BrowserContext]>>
|
||||
|
||||
@ -683,12 +656,6 @@ the method will return an array with all the pages in all browser contexts.
|
||||
#### browser.process()
|
||||
- returns: <?[ChildProcess]> Spawned browser process. Returns `null` if the browser instance was created with [`playwright.connect`](#playwrightconnectoptions) method.
|
||||
|
||||
#### browser.targets()
|
||||
- returns: <[Array]<[Target]>>
|
||||
|
||||
An array of all active targets inside the Browser. In case of multiple browser contexts,
|
||||
the method will return an array with all the targets in all browser contexts.
|
||||
|
||||
#### browser.userAgent()
|
||||
- returns: <[Promise]<[string]>> Promise which resolves to the browser's original user agent.
|
||||
|
||||
@ -699,20 +666,6 @@ the method will return an array with all the targets in all browser contexts.
|
||||
|
||||
> **NOTE** the format of browser.version() might change with future releases of Chromium.
|
||||
|
||||
#### browser.waitForTarget(predicate[, options])
|
||||
- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
|
||||
- `options` <[Object]>
|
||||
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
||||
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
||||
|
||||
This searches for a target in all browser contexts.
|
||||
|
||||
An example of finding a target for a page opened via `window.open`:
|
||||
```js
|
||||
await page.evaluate(() => window.open('https://www.example.com/'));
|
||||
const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
|
||||
```
|
||||
|
||||
### class: BrowserContext
|
||||
|
||||
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
@ -737,21 +690,6 @@ await page.goto('https://example.com');
|
||||
await context.close();
|
||||
```
|
||||
|
||||
#### event: 'targetchanged'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when the url of a target inside the browser context changes.
|
||||
|
||||
#### event: 'targetcreated'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a new target is created inside the browser context, for example when a new page is opened by [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) or [`browserContext.newPage`](#browsercontextnewpage).
|
||||
|
||||
#### event: 'targetdestroyed'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a target inside the browser context is destroyed, for example when a page is closed.
|
||||
|
||||
#### browserContext.browser()
|
||||
- returns: <[Browser]>
|
||||
|
||||
@ -825,25 +763,6 @@ An array of all pages inside the browser context.
|
||||
await browserContext.setCookies([cookieObject1, cookieObject2]);
|
||||
```
|
||||
|
||||
#### browserContext.targets()
|
||||
- returns: <[Array]<[Target]>>
|
||||
|
||||
An array of all active targets inside the browser context.
|
||||
|
||||
#### browserContext.waitForTarget(predicate[, options])
|
||||
- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
|
||||
- `options` <[Object]>
|
||||
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
||||
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
||||
|
||||
This searches for a target in this specific browser context.
|
||||
|
||||
An example of finding a target for a page opened via `window.open`:
|
||||
```js
|
||||
await page.evaluate(() => window.open('https://www.example.com/'));
|
||||
const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
|
||||
```
|
||||
|
||||
### class: Overrides
|
||||
|
||||
#### overrides.setGeolocation(options)
|
||||
@ -1708,9 +1627,6 @@ await page.setViewport({
|
||||
await page.goto('https://example.com');
|
||||
```
|
||||
|
||||
#### page.target()
|
||||
- returns: <[Target]> a target this page was created from.
|
||||
|
||||
#### page.title()
|
||||
- returns: <[Promise]<[string]>> The page's title.
|
||||
|
||||
@ -2368,16 +2284,36 @@ await page.goto('https://www.google.com');
|
||||
await page.chromium.stopTracing();
|
||||
```
|
||||
|
||||
#### chromium.createBrowserCDPSession()
|
||||
- returns: <[Promise]<[CDPSession]>>
|
||||
#### event: 'targetchanged'
|
||||
- <[Target]>
|
||||
|
||||
Creates a Chrome Devtools Protocol session attached to the browser.
|
||||
Emitted when the url of a target changes.
|
||||
|
||||
#### chromium.createCDPSession(target)
|
||||
- `target` <[Target]> Target to return CDP connection for.
|
||||
- returns: <[Promise]<[CDPSession]>>
|
||||
> **NOTE** This includes target changes in incognito browser contexts.
|
||||
|
||||
Creates a Chrome Devtools Protocol session attached to the target.
|
||||
|
||||
#### event: 'targetcreated'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a target is created, for example when a new page is opened by [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) or [`browser.newPage`](#browsernewpage).
|
||||
|
||||
> **NOTE** This includes target creations in incognito browser contexts.
|
||||
|
||||
#### event: 'targetdestroyed'
|
||||
- <[Target]>
|
||||
|
||||
Emitted when a target is destroyed, for example when a page is closed.
|
||||
|
||||
> **NOTE** This includes target destructions in incognito browser contexts.
|
||||
|
||||
#### chromium.browserTarget()
|
||||
- returns: <[Target]>
|
||||
|
||||
Returns browser target.
|
||||
|
||||
#### chromium.pageTarget(page)
|
||||
- `page` <[Page]> Page to return target for.
|
||||
- returns: <[Target]> a target given page was created from.
|
||||
|
||||
#### chromium.serviceWorker(target)
|
||||
- `target` <[Target]> Target to treat as a service worker
|
||||
@ -2398,6 +2334,27 @@ Only one trace can be active at a time per browser.
|
||||
#### chromium.stopTracing()
|
||||
- returns: <[Promise]<[Buffer]>> Promise which resolves to buffer with trace data.
|
||||
|
||||
#### chromium.targets(context)
|
||||
- `context` <[BrowserContext]> Optional, if specified, only targets from this context are returned.
|
||||
- returns: <[Array]<[Target]>>
|
||||
|
||||
An array of all active targets inside the Browser. In case of multiple browser contexts,
|
||||
the method will return an array with all the targets in all browser contexts.
|
||||
|
||||
#### chromium.waitForTarget(predicate[, options])
|
||||
- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
|
||||
- `options` <[Object]>
|
||||
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
||||
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
||||
|
||||
This searches for a target in all browser contexts.
|
||||
|
||||
An example of finding a target for a page opened via `window.open`:
|
||||
```js
|
||||
await page.evaluate(() => window.open('https://www.example.com/'));
|
||||
const newWindowTarget = await browser.chromium.waitForTarget(target => target.url() === 'https://www.example.com/');
|
||||
```
|
||||
|
||||
#### chromium.wsEndpoint()
|
||||
- returns: <[string]> Browser websocket url.
|
||||
|
||||
@ -3712,6 +3669,11 @@ Get the browser the target belongs to.
|
||||
|
||||
The browser context the target belongs to.
|
||||
|
||||
#### target.createCDPSession()
|
||||
- returns: <[Promise]<[CDPSession]>>
|
||||
|
||||
Creates a Chrome Devtools Protocol session attached to the target.
|
||||
|
||||
#### target.opener()
|
||||
- returns: <?[Target]>
|
||||
|
||||
@ -3743,7 +3705,7 @@ Useful links:
|
||||
- Getting Started with DevTools Protocol: https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md
|
||||
|
||||
```js
|
||||
const client = await page.chromium.createCDPSession(target);
|
||||
const client = await page.chromium.pageTarget(page).createCDPSession();
|
||||
await client.send('Animation.enable');
|
||||
client.on('Animation.animationCreated', () => console.log('Animation created!'));
|
||||
const response = await client.send('Animation.getPlaybackRate');
|
||||
|
@ -32,7 +32,7 @@ export class Browser extends EventEmitter {
|
||||
private _defaultViewport: Viewport;
|
||||
private _process: childProcess.ChildProcess;
|
||||
private _screenshotter = new Screenshotter();
|
||||
private _connection: Connection;
|
||||
_connection: Connection;
|
||||
_client: CDPSession;
|
||||
private _closeCallback: () => Promise<void>;
|
||||
private _defaultContext: BrowserContext;
|
||||
@ -66,7 +66,7 @@ export class Browser extends EventEmitter {
|
||||
this._defaultViewport = defaultViewport;
|
||||
this._process = process;
|
||||
this._closeCallback = closeCallback || (() => Promise.resolve());
|
||||
this.chromium = new Chromium(this._connection, this._client);
|
||||
this.chromium = new Chromium(this);
|
||||
|
||||
this._defaultContext = new BrowserContext(this._client, this, null);
|
||||
for (const contextId of contextIds)
|
||||
@ -111,10 +111,8 @@ export class Browser extends EventEmitter {
|
||||
assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated');
|
||||
this._targets.set(event.targetInfo.targetId, target);
|
||||
|
||||
if (await target._initializedPromise) {
|
||||
this.emit(Events.Browser.TargetCreated, target);
|
||||
context.emit(Events.BrowserContext.TargetCreated, target);
|
||||
}
|
||||
if (await target._initializedPromise)
|
||||
this.chromium.emit(Events.Chromium.TargetCreated, target);
|
||||
}
|
||||
|
||||
async _targetDestroyed(event: { targetId: string; }) {
|
||||
@ -122,10 +120,8 @@ export class Browser extends EventEmitter {
|
||||
target._initializedCallback(false);
|
||||
this._targets.delete(event.targetId);
|
||||
target._closedCallback();
|
||||
if (await target._initializedPromise) {
|
||||
this.emit(Events.Browser.TargetDestroyed, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target);
|
||||
}
|
||||
if (await target._initializedPromise)
|
||||
this.chromium.emit(Events.Chromium.TargetDestroyed, target);
|
||||
}
|
||||
|
||||
_targetInfoChanged(event: Protocol.Target.targetInfoChangedPayload) {
|
||||
@ -134,10 +130,8 @@ export class Browser extends EventEmitter {
|
||||
const previousURL = target.url();
|
||||
const wasInitialized = target._isInitialized;
|
||||
target._targetInfoChanged(event.targetInfo);
|
||||
if (wasInitialized && previousURL !== target.url()) {
|
||||
this.emit(Events.Browser.TargetChanged, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetChanged, target);
|
||||
}
|
||||
if (wasInitialized && previousURL !== target.url())
|
||||
this.chromium.emit(Events.Chromium.TargetChanged, target);
|
||||
}
|
||||
|
||||
async newPage(): Promise<Page> {
|
||||
@ -156,28 +150,28 @@ export class Browser extends EventEmitter {
|
||||
await this._client.send('Target.closeTarget', { targetId: target._targetId });
|
||||
}
|
||||
|
||||
targets(): Target[] {
|
||||
_allTargets(): Target[] {
|
||||
return Array.from(this._targets.values()).filter(target => target._isInitialized);
|
||||
}
|
||||
|
||||
async waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined = {}): Promise<Target> {
|
||||
async _waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined = {}): Promise<Target> {
|
||||
const {
|
||||
timeout = 30000
|
||||
} = options;
|
||||
const existingTarget = this.targets().find(predicate);
|
||||
const existingTarget = this._allTargets().find(predicate);
|
||||
if (existingTarget)
|
||||
return existingTarget;
|
||||
let resolve;
|
||||
const targetPromise = new Promise<Target>(x => resolve = x);
|
||||
this.on(Events.Browser.TargetCreated, check);
|
||||
this.on(Events.Browser.TargetChanged, check);
|
||||
this.chromium.on(Events.Chromium.TargetCreated, check);
|
||||
this.chromium.on(Events.Chromium.TargetChanged, check);
|
||||
try {
|
||||
if (!timeout)
|
||||
return await targetPromise;
|
||||
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
|
||||
} finally {
|
||||
this.removeListener(Events.Browser.TargetCreated, check);
|
||||
this.removeListener(Events.Browser.TargetChanged, check);
|
||||
this.chromium.removeListener(Events.Chromium.TargetCreated, check);
|
||||
this.chromium.removeListener(Events.Chromium.TargetChanged, check);
|
||||
}
|
||||
|
||||
function check(target: Target) {
|
||||
|
@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { assert } from '../helper';
|
||||
import { filterCookies, NetworkCookie, rewriteCookies, SetNetworkCookieParam } from '../network';
|
||||
import { Browser } from './Browser';
|
||||
@ -24,30 +23,25 @@ import { Permissions } from './features/permissions';
|
||||
import { Page } from './Page';
|
||||
import { Target } from './Target';
|
||||
|
||||
export class BrowserContext extends EventEmitter {
|
||||
export class BrowserContext {
|
||||
readonly permissions: Permissions;
|
||||
|
||||
private _browser: Browser;
|
||||
private _id: string;
|
||||
|
||||
constructor(client: CDPSession, browser: Browser, contextId: string | null) {
|
||||
super();
|
||||
this._browser = browser;
|
||||
this._id = contextId;
|
||||
this.permissions = new Permissions(client, contextId);
|
||||
}
|
||||
|
||||
targets(): Target[] {
|
||||
return this._browser.targets().filter(target => target.browserContext() === this);
|
||||
}
|
||||
|
||||
waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined): Promise<Target> {
|
||||
return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options);
|
||||
_targets(): Target[] {
|
||||
return this._browser._allTargets().filter(target => target.browserContext() === this);
|
||||
}
|
||||
|
||||
async pages(): Promise<Page[]> {
|
||||
const pages = await Promise.all(
|
||||
this.targets()
|
||||
this._targets()
|
||||
.filter(target => target.type() === 'page')
|
||||
.map(target => target.page())
|
||||
);
|
||||
|
@ -184,7 +184,7 @@ export class Launcher {
|
||||
connection = new Connection('', transport, slowMo);
|
||||
}
|
||||
const browser = await Browser.create(connection, [], ignoreHTTPSErrors, defaultViewport, chromeProcess, gracefullyCloseChrome);
|
||||
await browser.waitForTarget(t => t.type() === 'page');
|
||||
await browser._waitForTarget(t => t.type() === 'page');
|
||||
return browser;
|
||||
} catch (e) {
|
||||
killChrome();
|
||||
|
@ -59,7 +59,7 @@ export type Viewport = {
|
||||
export class Page extends EventEmitter {
|
||||
private _closed = false;
|
||||
_client: CDPSession;
|
||||
private _target: Target;
|
||||
_target: Target;
|
||||
private _keyboard: input.Keyboard;
|
||||
private _mouse: input.Mouse;
|
||||
private _timeoutSettings: TimeoutSettings;
|
||||
@ -178,10 +178,6 @@ export class Page extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
target(): Target {
|
||||
return this._target;
|
||||
}
|
||||
|
||||
browser(): Browser {
|
||||
return this._target.browser();
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ export class Screenshotter {
|
||||
}
|
||||
|
||||
private async _screenshot(page: Page, format: 'png' | 'jpeg', options: ScreenshotOptions): Promise<Buffer | string> {
|
||||
await page._client.send('Target.activateTarget', {targetId: page.target()._targetId});
|
||||
await page._client.send('Target.activateTarget', {targetId: page._target._targetId});
|
||||
let clip = options.clip ? processClip(options.clip) : undefined;
|
||||
const viewport = page.viewport();
|
||||
|
||||
|
@ -28,7 +28,7 @@ export class Target {
|
||||
private _targetInfo: Protocol.Target.TargetInfo;
|
||||
private _browserContext: BrowserContext;
|
||||
_targetId: string;
|
||||
_sessionFactory: () => Promise<CDPSession>;
|
||||
private _sessionFactory: () => Promise<CDPSession>;
|
||||
private _ignoreHTTPSErrors: boolean;
|
||||
private _defaultViewport: Viewport;
|
||||
private _screenshotter: Screenshotter;
|
||||
@ -118,6 +118,10 @@ export class Target {
|
||||
return this.browser()._targets.get(openerId);
|
||||
}
|
||||
|
||||
createCDPSession(): Promise<CDPSession> {
|
||||
return this._sessionFactory();
|
||||
}
|
||||
|
||||
_targetInfoChanged(targetInfo: Protocol.Target.TargetInfo) {
|
||||
this._targetInfo = targetInfo;
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
export { ConsoleMessage } from '../console';
|
||||
export { Dialog } from '../dialog';
|
||||
export { ElementHandle } from '../dom';
|
||||
export { TimeoutError } from '../Errors';
|
||||
export { Frame } from '../frames';
|
||||
export { Keyboard, Mouse } from '../input';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
export { Request, Response } from '../network';
|
||||
export { Browser } from './Browser';
|
||||
export { BrowserContext } from './BrowserContext';
|
||||
export { BrowserFetcher } from './BrowserFetcher';
|
||||
export { Chromium } from './features/chromium';
|
||||
export { CDPSession } from './Connection';
|
||||
export { Dialog } from '../dialog';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
export { ElementHandle } from '../dom';
|
||||
export { Accessibility } from './features/accessibility';
|
||||
export { Chromium } from './features/chromium';
|
||||
export { Coverage } from './features/coverage';
|
||||
export { Overrides } from './features/overrides';
|
||||
export { Interception } from './features/interception';
|
||||
export { Overrides } from './features/overrides';
|
||||
export { PDF } from './features/pdf';
|
||||
export { Permissions } from './features/permissions';
|
||||
export { Worker, Workers } from './features/workers';
|
||||
export { Frame } from '../frames';
|
||||
export { Keyboard, Mouse } from '../input';
|
||||
export { Request, Response } from '../network';
|
||||
export { Page } from './Page';
|
||||
export { Playwright } from './Playwright';
|
||||
export { Target } from './Target';
|
||||
export { ConsoleMessage } from '../console';
|
||||
|
||||
|
@ -37,13 +37,10 @@ export const Events = {
|
||||
},
|
||||
|
||||
Browser: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
Disconnected: 'disconnected'
|
||||
},
|
||||
|
||||
BrowserContext: {
|
||||
Chromium: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
|
@ -14,19 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const utils = require('./utils');
|
||||
const {waitEvent} = utils;
|
||||
const { waitEvent } = require('../../../test/utils');
|
||||
|
||||
module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME, WEBKIT}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('Target', function() {
|
||||
// FIXME(WebKit): need to enable agents in the inspected page to listen for updates.
|
||||
it.skip(WEBKIT)('Browser.targets should return all of the targets', async({page, server, browser}) => {
|
||||
describe('Chromium', function() {
|
||||
it('should work across sessions', async function({browser, server}) {
|
||||
expect(browser.browserContexts().length).toBe(2);
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
expect(browser.browserContexts().length).toBe(3);
|
||||
const remoteBrowser = await playwright.connect({
|
||||
browserWSEndpoint: browser.chromium.wsEndpoint()
|
||||
});
|
||||
const contexts = remoteBrowser.browserContexts();
|
||||
expect(contexts.length).toBe(3);
|
||||
remoteBrowser.disconnect();
|
||||
await context.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Target', function() {
|
||||
it('Chromium.targets should return all of the targets', async({page, server, browser}) => {
|
||||
// The pages will be the testing page and the original newtab page
|
||||
const targets = browser.targets();
|
||||
const targets = browser.chromium.targets();
|
||||
expect(targets.some(target => target.type() === 'page' &&
|
||||
target.url() === 'about:blank')).toBeTruthy('Missing blank page');
|
||||
expect(targets.some(target => target.type() === 'browser')).toBeTruthy('Missing browser target');
|
||||
@ -38,8 +51,8 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages[0]).not.toBe(allPages[1]);
|
||||
});
|
||||
it.skip(WEBKIT)('should contain browser target', async({browser}) => {
|
||||
const targets = browser.targets();
|
||||
it('should contain browser target', async({browser}) => {
|
||||
const targets = browser.chromium.targets();
|
||||
const browserTarget = targets.find(target => target.type() === 'browser');
|
||||
expect(browserTarget).toBeTruthy();
|
||||
});
|
||||
@ -50,10 +63,9 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
expect(await originalPage.evaluate(() => ['Hello', 'world'].join(' '))).toBe('Hello world');
|
||||
expect(await originalPage.$('body')).toBeTruthy();
|
||||
});
|
||||
// FIXME(WebKit): need to enable agents in the inspected page to listen for updates.
|
||||
it.skip(WEBKIT)('should report when a new page is created and closed', async({page, server, context}) => {
|
||||
it('should report when a new page is created and closed', async({browser, page, server, context}) => {
|
||||
const [otherPage] = await Promise.all([
|
||||
context.waitForTarget(target => target.url() === server.CROSS_PROCESS_PREFIX + '/empty.html').then(target => target.page()),
|
||||
browser.chromium.waitForTarget(target => target.url() === server.CROSS_PROCESS_PREFIX + '/empty.html').then(target => target.page()),
|
||||
page.evaluate(url => window.open(url), server.CROSS_PROCESS_PREFIX + '/empty.html'),
|
||||
]);
|
||||
expect(otherPage.url()).toContain(server.CROSS_PROCESS_PREFIX);
|
||||
@ -64,73 +76,73 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).toContain(otherPage);
|
||||
|
||||
const closePagePromise = new Promise(fulfill => context.once('targetdestroyed', target => fulfill(target.page())));
|
||||
const closePagePromise = new Promise(fulfill => browser.chromium.once('targetdestroyed', target => fulfill(target.page())));
|
||||
await otherPage.close();
|
||||
expect(await closePagePromise).toBe(otherPage);
|
||||
|
||||
allPages = await Promise.all(context.targets().map(target => target.page()));
|
||||
allPages = await Promise.all(browser.chromium.targets().map(target => target.page()));
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).not.toContain(otherPage);
|
||||
});
|
||||
it.skip(FFOX || WEBKIT)('should report when a service worker is created and destroyed', async({page, server, context}) => {
|
||||
it('should report when a service worker is created and destroyed', async({browser, page, server, context}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const createdTarget = new Promise(fulfill => context.once('targetcreated', target => fulfill(target)));
|
||||
const createdTarget = new Promise(fulfill => browser.chromium.once('targetcreated', target => fulfill(target)));
|
||||
|
||||
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');
|
||||
|
||||
expect((await createdTarget).type()).toBe('service_worker');
|
||||
expect((await createdTarget).url()).toBe(server.PREFIX + '/serviceworkers/empty/sw.js');
|
||||
|
||||
const destroyedTarget = new Promise(fulfill => context.once('targetdestroyed', target => fulfill(target)));
|
||||
const destroyedTarget = new Promise(fulfill => browser.chromium.once('targetdestroyed', target => fulfill(target)));
|
||||
await page.evaluate(() => window.registrationPromise.then(registration => registration.unregister()));
|
||||
expect(await destroyedTarget).toBe(await createdTarget);
|
||||
});
|
||||
it.skip(FFOX || WEBKIT)('should create a worker from a service worker', async({browser, page, server, context}) => {
|
||||
it('should create a worker from a service worker', async({browser, page, server, context}) => {
|
||||
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');
|
||||
|
||||
const target = await context.waitForTarget(target => target.type() === 'service_worker');
|
||||
const target = await browser.chromium.waitForTarget(target => target.type() === 'service_worker');
|
||||
const worker = await browser.chromium.serviceWorker(target);
|
||||
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
|
||||
});
|
||||
it.skip(FFOX || WEBKIT)('should create a worker from a shared worker', async({browser, page, server, context}) => {
|
||||
it('should create a worker from a shared worker', async({browser, page, server, context}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.evaluate(() => {
|
||||
new SharedWorker('data:text/javascript,console.log("hi")');
|
||||
});
|
||||
const target = await context.waitForTarget(target => target.type() === 'shared_worker');
|
||||
const target = await browser.chromium.waitForTarget(target => target.type() === 'shared_worker');
|
||||
const worker = await browser.chromium.serviceWorker(target);
|
||||
expect(await worker.evaluate(() => self.toString())).toBe('[object SharedWorkerGlobalScope]');
|
||||
});
|
||||
it.skip(WEBKIT)('should report when a target url changes', async({page, server, context}) => {
|
||||
it('should report when a target url changes', async({browser, page, server, context}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
let changedTarget = new Promise(fulfill => context.once('targetchanged', target => fulfill(target)));
|
||||
let changedTarget = new Promise(fulfill => browser.chromium.once('targetchanged', target => fulfill(target)));
|
||||
await page.goto(server.CROSS_PROCESS_PREFIX + '/');
|
||||
expect((await changedTarget).url()).toBe(server.CROSS_PROCESS_PREFIX + '/');
|
||||
|
||||
changedTarget = new Promise(fulfill => context.once('targetchanged', target => fulfill(target)));
|
||||
changedTarget = new Promise(fulfill => browser.chromium.once('targetchanged', target => fulfill(target)));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect((await changedTarget).url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
it.skip(FFOX || WEBKIT)('should not report uninitialized pages', async({page, server, context}) => {
|
||||
it('should not report uninitialized pages', async({browser, page, server, context}) => {
|
||||
let targetChanged = false;
|
||||
const listener = () => targetChanged = true;
|
||||
context.on('targetchanged', listener);
|
||||
const targetPromise = new Promise(fulfill => context.once('targetcreated', target => fulfill(target)));
|
||||
browser.chromium.on('targetchanged', listener);
|
||||
const targetPromise = new Promise(fulfill => browser.chromium.once('targetcreated', target => fulfill(target)));
|
||||
const newPagePromise = context.newPage();
|
||||
const target = await targetPromise;
|
||||
expect(target.url()).toBe('about:blank');
|
||||
|
||||
const newPage = await newPagePromise;
|
||||
const targetPromise2 = new Promise(fulfill => context.once('targetcreated', target => fulfill(target)));
|
||||
const targetPromise2 = new Promise(fulfill => browser.chromium.once('targetcreated', target => fulfill(target)));
|
||||
const evaluatePromise = newPage.evaluate(() => window.open('about:blank'));
|
||||
const target2 = await targetPromise2;
|
||||
expect(target2.url()).toBe('about:blank');
|
||||
await evaluatePromise;
|
||||
await newPage.close();
|
||||
expect(targetChanged).toBe(false, 'target should not be reported as changed');
|
||||
context.removeListener('targetchanged', listener);
|
||||
browser.chromium.removeListener('targetchanged', listener);
|
||||
});
|
||||
it.skip(WEBKIT)('should not crash while redirecting if original request was missed', async({page, server, context}) => {
|
||||
it('should not crash while redirecting if original request was missed', async({browser, page, server, context}) => {
|
||||
let serverResponse = null;
|
||||
server.setRoute('/one-style.css', (req, res) => serverResponse = res);
|
||||
// Open a new page. Use window.open to connect to the page later.
|
||||
@ -139,7 +151,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
server.waitForRequest('/one-style.css')
|
||||
]);
|
||||
// Connect to the opened page.
|
||||
const target = await context.waitForTarget(target => target.url().includes('one-style.html'));
|
||||
const target = await browser.chromium.waitForTarget(target => target.url().includes('one-style.html'));
|
||||
const newPage = await target.page();
|
||||
// Issue a redirect.
|
||||
serverResponse.writeHead(302, { location: '/injectedstyle.css' });
|
||||
@ -149,22 +161,40 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
// Cleanup.
|
||||
await newPage.close();
|
||||
});
|
||||
it.skip(WEBKIT)('should have an opener', async({page, server, context}) => {
|
||||
it('should have an opener', async({browser, page, server, context}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [createdTarget] = await Promise.all([
|
||||
new Promise(fulfill => context.once('targetcreated', target => fulfill(target))),
|
||||
new Promise(fulfill => browser.chromium.once('targetcreated', target => fulfill(target))),
|
||||
page.goto(server.PREFIX + '/popup/window-open.html')
|
||||
]);
|
||||
expect((await createdTarget.page()).url()).toBe(server.PREFIX + '/popup/popup.html');
|
||||
expect(createdTarget.opener()).toBe(page.target());
|
||||
expect(page.target().opener()).toBe(null);
|
||||
expect(createdTarget.opener()).toBe(browser.chromium.pageTarget(page));
|
||||
expect(browser.chromium.pageTarget(page).opener()).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser.waitForTarget', () => {
|
||||
describe('Chromium.waitForTarget', () => {
|
||||
it('should wait for a target', async function({browser, server}) {
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
let resolved = false;
|
||||
const targetPromise = browser.chromium.waitForTarget(target => target.browserContext() === context && target.url() === server.EMPTY_PAGE);
|
||||
targetPromise.then(() => resolved = true);
|
||||
const page = await context.newPage();
|
||||
expect(resolved).toBe(false);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const target = await targetPromise;
|
||||
expect(await target.page()).toBe(page);
|
||||
await context.close();
|
||||
});
|
||||
it('should timeout waiting for a non-existent target', async function({browser, server}) {
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
const error = await browser.chromium.waitForTarget(target => target.browserContext() === context && target.url() === server.EMPTY_PAGE, {timeout: 1}).catch(e => e);
|
||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
||||
await context.close();
|
||||
});
|
||||
it('should wait for a target', async function({browser, server}) {
|
||||
let resolved = false;
|
||||
const targetPromise = browser.waitForTarget(target => target.url() === server.EMPTY_PAGE);
|
||||
const targetPromise = browser.chromium.waitForTarget(target => target.url() === server.EMPTY_PAGE);
|
||||
targetPromise.then(() => resolved = true);
|
||||
const page = await browser.newPage();
|
||||
expect(resolved).toBe(false);
|
||||
@ -173,9 +203,9 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
expect(await target.page()).toBe(page);
|
||||
await page.close();
|
||||
});
|
||||
it.skip(WEBKIT)('should timeout waiting for a non-existent target', async function({browser, server}) {
|
||||
it('should timeout waiting for a non-existent target', async function({browser, server}) {
|
||||
let error = null;
|
||||
await browser.waitForTarget(target => target.url() === server.EMPTY_PAGE, {
|
||||
await browser.chromium.waitForTarget(target => target.url() === server.EMPTY_PAGE, {
|
||||
timeout: 1
|
||||
}).catch(e => error = e);
|
||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
@ -14,31 +14,33 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { EventEmitter } from 'events';
|
||||
import { assert } from '../../helper';
|
||||
import { Browser } from '../Browser';
|
||||
import { BrowserContext } from '../BrowserContext';
|
||||
import { CDPSession, Connection } from '../Connection';
|
||||
import { Page } from '../Page';
|
||||
import { readProtocolStream } from '../protocolHelper';
|
||||
import { Target } from '../Target';
|
||||
import { Worker } from './workers';
|
||||
|
||||
export class Chromium {
|
||||
export class Chromium extends EventEmitter {
|
||||
private _connection: Connection;
|
||||
private _client: CDPSession;
|
||||
private _recording = false;
|
||||
private _path = '';
|
||||
private _tracingClient: CDPSession | undefined;
|
||||
private _browser: Browser;
|
||||
|
||||
constructor(connection: Connection, client: CDPSession) {
|
||||
this._connection = connection;
|
||||
this._client = client;
|
||||
constructor(browser: Browser) {
|
||||
super();
|
||||
this._connection = browser._connection;
|
||||
this._client = browser._client;
|
||||
this._browser = browser;
|
||||
}
|
||||
|
||||
createBrowserCDPSession(): Promise<CDPSession> {
|
||||
return this._connection.createBrowserSession();
|
||||
}
|
||||
|
||||
createCDPSession(target: Target): Promise<CDPSession> {
|
||||
return target._sessionFactory();
|
||||
browserTarget(): Target {
|
||||
return [...this._browser._targets.values()].find(t => t.type() === 'browser');
|
||||
}
|
||||
|
||||
serviceWorker(target: Target): Promise<Worker | null> {
|
||||
@ -84,6 +86,19 @@ export class Chromium {
|
||||
return contentPromise;
|
||||
}
|
||||
|
||||
targets(context?: BrowserContext): Target[] {
|
||||
const targets = this._browser._allTargets();
|
||||
return context ? targets.filter(t => t.browserContext() === context) : targets;
|
||||
}
|
||||
|
||||
pageTarget(page: Page): Target {
|
||||
return page._target;
|
||||
}
|
||||
|
||||
waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined = {}): Promise<Target> {
|
||||
return this._browser._waitForTarget(predicate, options);
|
||||
}
|
||||
|
||||
wsEndpoint(): string {
|
||||
return this._connection.url();
|
||||
}
|
||||
|
@ -15,9 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const utils = require('../../../test/utils');
|
||||
const {waitEvent} = utils;
|
||||
|
||||
module.exports.addTests = function ({ testRunner, expect }) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
|
@ -105,23 +105,21 @@ export class Browser extends EventEmitter {
|
||||
return this._process;
|
||||
}
|
||||
|
||||
async waitForTarget(predicate: (target: Target) => boolean, options: { timeout?: number; } = {}): Promise<Target> {
|
||||
async _waitForTarget(predicate: (target: Target) => boolean, options: { timeout?: number; } = {}): Promise<Target> {
|
||||
const {
|
||||
timeout = 30000
|
||||
} = options;
|
||||
const existingTarget = this.targets().find(predicate);
|
||||
const existingTarget = this._allTargets().find(predicate);
|
||||
if (existingTarget)
|
||||
return existingTarget;
|
||||
let resolve;
|
||||
const targetPromise = new Promise<Target>(x => resolve = x);
|
||||
this.on(Events.Browser.TargetCreated, check);
|
||||
this.on('targetchanged', check);
|
||||
try {
|
||||
if (!timeout)
|
||||
return await targetPromise;
|
||||
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
|
||||
} finally {
|
||||
this.removeListener(Events.Browser.TargetCreated, check);
|
||||
this.removeListener('targetchanged', check);
|
||||
}
|
||||
|
||||
@ -148,7 +146,7 @@ export class Browser extends EventEmitter {
|
||||
return await Promise.all(pageTargets.map(target => target.page()));
|
||||
}
|
||||
|
||||
targets() {
|
||||
_allTargets() {
|
||||
return Array.from(this._targets.values());
|
||||
}
|
||||
|
||||
@ -163,23 +161,17 @@ export class Browser extends EventEmitter {
|
||||
openerPage.emit(Events.Page.Popup, popupPage);
|
||||
}
|
||||
}
|
||||
this.emit(Events.Browser.TargetCreated, target);
|
||||
context.emit(Events.BrowserContext.TargetCreated, target);
|
||||
}
|
||||
|
||||
_onTargetDestroyed({targetId}) {
|
||||
const target = this._targets.get(targetId);
|
||||
this._targets.delete(targetId);
|
||||
target._closedCallback();
|
||||
this.emit(Events.Browser.TargetDestroyed, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target);
|
||||
}
|
||||
|
||||
_onTargetInfoChanged({targetId, url}) {
|
||||
const target = this._targets.get(targetId);
|
||||
target._url = url;
|
||||
this.emit(Events.Browser.TargetChanged, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetChanged, target);
|
||||
}
|
||||
|
||||
async close() {
|
||||
@ -243,40 +235,32 @@ export class Target {
|
||||
}
|
||||
}
|
||||
|
||||
export class BrowserContext extends EventEmitter {
|
||||
export class BrowserContext {
|
||||
_connection: Connection;
|
||||
_browser: Browser;
|
||||
_browserContextId: string;
|
||||
readonly permissions: Permissions;
|
||||
|
||||
constructor(connection: Connection, browser: Browser, browserContextId: string | null) {
|
||||
super();
|
||||
this._connection = connection;
|
||||
this._browser = browser;
|
||||
this._browserContextId = browserContextId;
|
||||
this.permissions = new Permissions(connection, browserContextId);
|
||||
}
|
||||
|
||||
targets(): Array<Target> {
|
||||
return this._browser.targets().filter(target => target.browserContext() === this);
|
||||
_targets(): Array<Target> {
|
||||
return this._browser._allTargets().filter(target => target.browserContext() === this);
|
||||
}
|
||||
|
||||
|
||||
async pages(): Promise<Array<Page>> {
|
||||
const pages = await Promise.all(
|
||||
this.targets()
|
||||
this._targets()
|
||||
.filter(target => target.type() === 'page')
|
||||
.map(target => target.page())
|
||||
);
|
||||
return pages.filter(page => !!page);
|
||||
}
|
||||
|
||||
|
||||
waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined): Promise<Target> {
|
||||
return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options);
|
||||
}
|
||||
|
||||
|
||||
isIncognito(): boolean {
|
||||
return !!this._browserContextId;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ export class Launcher {
|
||||
const browser = await Browser.create(connection, defaultViewport, firefoxProcess, gracefullyCloseFirefox);
|
||||
if (ignoreHTTPSErrors)
|
||||
await connection.send('Browser.setIgnoreHTTPSErrors', {enabled: true});
|
||||
await browser.waitForTarget(t => t.type() === 'page');
|
||||
await browser._waitForTarget(t => t.type() === 'page');
|
||||
return browser;
|
||||
} catch (e) {
|
||||
killFirefox();
|
||||
|
@ -291,10 +291,6 @@ export class Page extends EventEmitter {
|
||||
return this._target.browser();
|
||||
}
|
||||
|
||||
target() {
|
||||
return this._target;
|
||||
}
|
||||
|
||||
url() {
|
||||
return this._frameManager.mainFrame().url();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
export { TimeoutError } from '../Errors';
|
||||
export { Keyboard, Mouse } from '../input';
|
||||
export { Browser, BrowserContext, Target } from './Browser';
|
||||
export { Browser, BrowserContext } from './Browser';
|
||||
export { BrowserFetcher } from './BrowserFetcher';
|
||||
export { Dialog } from '../dialog';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
|
@ -37,15 +37,6 @@ export const Events = {
|
||||
},
|
||||
|
||||
Browser: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
Disconnected: 'disconnected'
|
||||
},
|
||||
|
||||
BrowserContext: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
}
|
||||
};
|
||||
|
@ -36,17 +36,7 @@ export class Browser extends EventEmitter {
|
||||
private _contexts = new Map<string, BrowserContext>();
|
||||
_targets = new Map<string, Target>();
|
||||
private _eventListeners: RegisteredListener[];
|
||||
_waitForFirstTarget: Promise<void>;
|
||||
private _waitForFirstTargetCallback: () => void;
|
||||
|
||||
static async create(
|
||||
connection: Connection,
|
||||
defaultViewport: Viewport | null,
|
||||
process: childProcess.ChildProcess | null,
|
||||
closeCallback?: (() => Promise<void>)) {
|
||||
const browser = new Browser(connection, defaultViewport, process, closeCallback);
|
||||
return browser;
|
||||
}
|
||||
private _privateEvents = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
connection: Connection,
|
||||
@ -74,7 +64,6 @@ export class Browser extends EventEmitter {
|
||||
|
||||
// Taking multiple screenshots in parallel doesn't work well, so we serialize them.
|
||||
this._screenshotTaskQueue = new TaskQueue();
|
||||
this._waitForFirstTarget = new Promise(f => this._waitForFirstTargetCallback = f);
|
||||
}
|
||||
|
||||
async userAgent(): Promise<string> {
|
||||
@ -128,7 +117,7 @@ export class Browser extends EventEmitter {
|
||||
return Array.from(this._targets.values());
|
||||
}
|
||||
|
||||
async waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined = {}): Promise<Target> {
|
||||
async _waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined = {}): Promise<Target> {
|
||||
const {
|
||||
timeout = 30000
|
||||
} = options;
|
||||
@ -137,15 +126,13 @@ export class Browser extends EventEmitter {
|
||||
return existingTarget;
|
||||
let resolve;
|
||||
const targetPromise = new Promise<Target>(x => resolve = x);
|
||||
this.on(Events.Browser.TargetCreated, check);
|
||||
this.on(Events.Browser.TargetChanged, check);
|
||||
this._privateEvents.on(BrowserEvents.TargetCreated, check);
|
||||
try {
|
||||
if (!timeout)
|
||||
return await targetPromise;
|
||||
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
|
||||
} finally {
|
||||
this.removeListener(Events.Browser.TargetCreated, check);
|
||||
this.removeListener(Events.Browser.TargetChanged, check);
|
||||
this._privateEvents.removeListener(BrowserEvents.TargetCreated, check);
|
||||
}
|
||||
|
||||
function check(target: Target) {
|
||||
@ -175,17 +162,13 @@ export class Browser extends EventEmitter {
|
||||
context = this._defaultContext;
|
||||
const target = new Target(targetInfo, context);
|
||||
this._targets.set(targetInfo.targetId, target);
|
||||
this.emit(Events.Browser.TargetCreated, target);
|
||||
context.emit(Events.BrowserContext.TargetCreated, target);
|
||||
this._waitForFirstTargetCallback();
|
||||
this._privateEvents.emit(BrowserEvents.TargetCreated, target);
|
||||
}
|
||||
|
||||
_onTargetDestroyed({targetId}) {
|
||||
const target = this._targets.get(targetId);
|
||||
this._targets.delete(targetId);
|
||||
target._closedCallback();
|
||||
this.emit(Events.Browser.TargetDestroyed, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target);
|
||||
}
|
||||
|
||||
async _onProvisionalTargetCommitted({oldTargetId, newTargetId}) {
|
||||
@ -199,11 +182,6 @@ export class Browser extends EventEmitter {
|
||||
newTarget._pagePromise = oldTarget._pagePromise;
|
||||
}
|
||||
|
||||
_onTargetChanged(target: Target) {
|
||||
this.emit(Events.BrowserContext.TargetChanged, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetChanged, target);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
throw new Error('Unsupported operation');
|
||||
}
|
||||
@ -218,28 +196,22 @@ export class Browser extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
export class BrowserContext extends EventEmitter {
|
||||
export class BrowserContext {
|
||||
private _browser: Browser;
|
||||
_id: string;
|
||||
|
||||
constructor(browser: Browser, contextId?: string) {
|
||||
super();
|
||||
this._browser = browser;
|
||||
this._id = contextId;
|
||||
}
|
||||
|
||||
targets(): Target[] {
|
||||
_targets(): Target[] {
|
||||
return this._browser.targets().filter(target => target.browserContext() === this);
|
||||
}
|
||||
|
||||
waitForTarget(predicate: (arg0: Target) => boolean, options: { timeout?: number; } | undefined): Promise<Target> {
|
||||
return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options);
|
||||
}
|
||||
|
||||
async pages(): Promise<Page[]> {
|
||||
await this._browser._waitForFirstTarget;
|
||||
const pages = await Promise.all(
|
||||
this.targets()
|
||||
this._targets()
|
||||
.filter(target => target.type() === 'page')
|
||||
.map(target => target.page())
|
||||
);
|
||||
@ -281,3 +253,8 @@ export class BrowserContext extends EventEmitter {
|
||||
await this._browser._connection.send('Browser.deleteAllCookies', { browserContextId: this._id });
|
||||
}
|
||||
}
|
||||
|
||||
const BrowserEvents = {
|
||||
TargetCreated: Symbol('BrowserEvents.TargetCreated'),
|
||||
TargetDestroyed: Symbol('BrowserEvents.TargetDestroyed'),
|
||||
};
|
||||
|
@ -127,6 +127,7 @@ export class Launcher {
|
||||
const transport = new PipeTransport(webkitProcess.stdio[3] as NodeJS.WritableStream, webkitProcess.stdio[4] as NodeJS.ReadableStream);
|
||||
connection = new Connection('', transport, slowMo);
|
||||
const browser = new Browser(connection, defaultViewport, webkitProcess, gracefullyCloseWebkit);
|
||||
await browser._waitForTarget(t => t.type() === 'page');
|
||||
return browser;
|
||||
} catch (e) {
|
||||
killWebKit();
|
||||
|
@ -144,10 +144,6 @@ export class Page extends EventEmitter {
|
||||
await this._initialize().catch(e => debugError('failed to enable agents after swap: ' + e));
|
||||
}
|
||||
|
||||
target(): Target {
|
||||
return this._target;
|
||||
}
|
||||
|
||||
browser(): Browser {
|
||||
return this._target.browser();
|
||||
}
|
||||
@ -255,11 +251,11 @@ export class Page extends EventEmitter {
|
||||
return await this._frameManager.mainFrame().content();
|
||||
}
|
||||
|
||||
async setContent(html: string, options: { timeout?: number; waitUntil?: string | string[]; } | undefined) {
|
||||
async setContent(html: string, options: { timeout?: number; waitUntil?: string | string[]; } = {}) {
|
||||
await this._frameManager.mainFrame().setContent(html, options);
|
||||
}
|
||||
|
||||
async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } | undefined): Promise<network.Response | null> {
|
||||
async goto(url: string, options: { referer?: string; timeout?: number; waitUntil?: string | string[]; } = {}): Promise<network.Response | null> {
|
||||
return await this._frameManager.mainFrame().goto(url, options);
|
||||
}
|
||||
|
||||
@ -494,11 +490,11 @@ export class Page extends EventEmitter {
|
||||
return this.mainFrame().select(selector, ...values);
|
||||
}
|
||||
|
||||
type(selector: string | types.Selector, text: string, options: { delay: (number | undefined); } | undefined) {
|
||||
type(selector: string | types.Selector, text: string, options?: { delay: (number | undefined); }) {
|
||||
return this.mainFrame().type(selector, text, options);
|
||||
}
|
||||
|
||||
waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; } = {}, ...args: any[]): Promise<js.JSHandle> {
|
||||
waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options?: { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string | number; }, ...args: any[]): Promise<js.JSHandle> {
|
||||
return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args);
|
||||
}
|
||||
|
||||
@ -510,7 +506,7 @@ export class Page extends EventEmitter {
|
||||
return this.mainFrame().waitForXPath(xpath, options);
|
||||
}
|
||||
|
||||
waitForFunction(pageFunction: Function | string, options: types.WaitForFunctionOptions, ...args: any[]): Promise<js.JSHandle> {
|
||||
waitForFunction(pageFunction: Function | string, options?: types.WaitForFunctionOptions, ...args: any[]): Promise<js.JSHandle> {
|
||||
return this.mainFrame().waitForFunction(pageFunction, options, ...args);
|
||||
}
|
||||
}
|
||||
|
@ -42,25 +42,6 @@ export class Target {
|
||||
this._pagePromise = null;
|
||||
this._url = url;
|
||||
this._isClosedPromise = new Promise(fulfill => this._closedCallback = fulfill);
|
||||
if (type === 'page') {
|
||||
const session = this._browserContext.browser()._connection.session(this._targetId);
|
||||
this._eventListeners = [
|
||||
// FIXME: we could use Page.frameStartedLoading if it had url info.
|
||||
helper.addEventListener(session, 'Page.frameNavigated', this._onFrameNavigated.bind(this)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
async _onFrameNavigated(params: Protocol.Page.frameNavigatedPayload) {
|
||||
// Check if main frame, get url from the event.
|
||||
// Skip child frames.
|
||||
if (params.frame.parentId)
|
||||
return;
|
||||
const url = params.frame.url;
|
||||
if (this._url !== url) {
|
||||
this._url = url;
|
||||
this.browser()._onTargetChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
async page(): Promise<Page | null> {
|
||||
|
@ -11,6 +11,5 @@ export { Mouse, Keyboard } from '../input';
|
||||
export { Request, Response } from '../network';
|
||||
export { Page } from './Page';
|
||||
export { Playwright } from './Playwright';
|
||||
export { Target } from './Target';
|
||||
export { Dialog } from '../dialog';
|
||||
export { ConsoleMessage } from '../console';
|
||||
|
@ -33,15 +33,6 @@ export const Events = {
|
||||
},
|
||||
|
||||
Browser: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
Disconnected: 'disconnected'
|
||||
},
|
||||
|
||||
BrowserContext: {
|
||||
TargetCreated: 'targetcreated',
|
||||
TargetDestroyed: 'targetdestroyed',
|
||||
TargetChanged: 'targetchanged',
|
||||
},
|
||||
};
|
||||
|
@ -23,7 +23,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
|
||||
describe('Chromium.createCDPSession', function() {
|
||||
it('should work', async function({page, browser, server}) {
|
||||
const client = await browser.chromium.createCDPSession(page.target());
|
||||
const client = await browser.chromium.pageTarget(page).createCDPSession();
|
||||
|
||||
await Promise.all([
|
||||
client.send('Runtime.enable'),
|
||||
@ -33,7 +33,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(foo).toBe('bar');
|
||||
});
|
||||
it('should send events', async function({page, browser, server}) {
|
||||
const client = await browser.chromium.createCDPSession(page.target());
|
||||
const client = await browser.chromium.pageTarget(page).createCDPSession();
|
||||
await client.send('Network.enable');
|
||||
const events = [];
|
||||
client.on('Network.requestWillBeSent', event => events.push(event));
|
||||
@ -41,7 +41,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(events.length).toBe(1);
|
||||
});
|
||||
it('should enable and disable domains independently', async function({page, browser, server}) {
|
||||
const client = await browser.chromium.createCDPSession(page.target());
|
||||
const client = await browser.chromium.pageTarget(page).createCDPSession();
|
||||
await client.send('Runtime.enable');
|
||||
await client.send('Debugger.enable');
|
||||
// JS coverage enables and then disables Debugger domain.
|
||||
@ -56,7 +56,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(event.url).toBe('foo.js');
|
||||
});
|
||||
it('should be able to detach session', async function({page, browser, server}) {
|
||||
const client = await browser.chromium.createCDPSession(page.target());
|
||||
const client = await browser.chromium.pageTarget(page).createCDPSession();
|
||||
await client.send('Runtime.enable');
|
||||
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
||||
expect(evalResponse.result.value).toBe(3);
|
||||
@ -70,7 +70,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(error.message).toContain('Session closed.');
|
||||
});
|
||||
it('should throw nice errors', async function({page, browser}) {
|
||||
const client = await browser.chromium.createCDPSession(page.target());
|
||||
const client = await browser.chromium.pageTarget(page).createCDPSession();
|
||||
const error = await theSourceOfTheProblems().catch(error => error);
|
||||
expect(error.stack).toContain('theSourceOfTheProblems');
|
||||
expect(error.message).toContain('ThisCommand.DoesNotExist');
|
||||
|
@ -56,7 +56,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [popupTarget] = await Promise.all([
|
||||
utils.waitEvent(browser, 'targetcreated'),
|
||||
utils.waitEvent(page, 'popup'),
|
||||
page.evaluate(url => window.open(url), server.EMPTY_PAGE)
|
||||
]);
|
||||
expect(popupTarget.browserContext()).toBe(context);
|
||||
@ -65,9 +65,9 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
it.skip(WEBKIT)('should fire target events', async function({browser, server}) {
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
const events = [];
|
||||
context.on('targetcreated', target => events.push('CREATED: ' + target.url()));
|
||||
context.on('targetchanged', target => events.push('CHANGED: ' + target.url()));
|
||||
context.on('targetdestroyed', target => events.push('DESTROYED: ' + target.url()));
|
||||
browser.chromium.on('targetcreated', target => events.push('CREATED: ' + target.url()));
|
||||
browser.chromium.on('targetchanged', target => events.push('CHANGED: ' + target.url()));
|
||||
browser.chromium.on('targetdestroyed', target => events.push('DESTROYED: ' + target.url()));
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.close();
|
||||
@ -78,30 +78,12 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
]);
|
||||
await context.close();
|
||||
});
|
||||
it('should wait for a target', async function({browser, server}) {
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
let resolved = false;
|
||||
const targetPromise = context.waitForTarget(target => target.url() === server.EMPTY_PAGE);
|
||||
targetPromise.then(() => resolved = true);
|
||||
const page = await context.newPage();
|
||||
expect(resolved).toBe(false);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const target = await targetPromise;
|
||||
expect(await target.page()).toBe(page);
|
||||
await context.close();
|
||||
});
|
||||
it('should timeout waiting for a non-existent target', async function({browser, server}) {
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
const error = await context.waitForTarget(target => target.url() === server.EMPTY_PAGE, {timeout: 1}).catch(e => e);
|
||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
||||
await context.close();
|
||||
});
|
||||
it('should isolate localStorage and cookies', async function({browser, server}) {
|
||||
// Create two incognito contexts.
|
||||
const context1 = await browser.createIncognitoBrowserContext();
|
||||
const context2 = await browser.createIncognitoBrowserContext();
|
||||
expect(context1.targets().length).toBe(0);
|
||||
expect(context2.targets().length).toBe(0);
|
||||
expect(browser.chromium.targets(context1).length).toBe(0);
|
||||
expect(browser.chromium.targets(context2).length).toBe(0);
|
||||
|
||||
// Create a page in first incognito context.
|
||||
const page1 = await context1.newPage();
|
||||
@ -111,8 +93,8 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
document.cookie = 'name=page1';
|
||||
});
|
||||
|
||||
expect(context1.targets().length).toBe(1);
|
||||
expect(context2.targets().length).toBe(0);
|
||||
expect(browser.chromium.targets(context1).length).toBe(1);
|
||||
expect(browser.chromium.targets(context2).length).toBe(0);
|
||||
|
||||
// Create a page in second incognito context.
|
||||
const page2 = await context2.newPage();
|
||||
@ -122,10 +104,10 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
document.cookie = 'name=page2';
|
||||
});
|
||||
|
||||
expect(context1.targets().length).toBe(1);
|
||||
expect(context1.targets()[0]).toBe(page1.target());
|
||||
expect(context2.targets().length).toBe(1);
|
||||
expect(context2.targets()[0]).toBe(page2.target());
|
||||
expect(browser.chromium.targets(context1).length).toBe(1);
|
||||
expect(browser.chromium.targets(context1)[0]).toBe(browser.chromium.pageTarget(page1));
|
||||
expect(browser.chromium.targets(context2).length).toBe(1);
|
||||
expect(browser.chromium.targets(context2)[0]).toBe(browser.chromium.pageTarget(page2));
|
||||
|
||||
// Make sure pages don't share localstorage or cookies.
|
||||
expect(await page1.evaluate(() => localStorage.getItem('name'))).toBe('page1');
|
||||
@ -140,17 +122,5 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
||||
]);
|
||||
expect(browser.browserContexts().length).toBe(1);
|
||||
});
|
||||
it.skip(WEBKIT)('should work across sessions', async function({browser, server}) {
|
||||
expect(browser.browserContexts().length).toBe(1);
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
expect(browser.browserContexts().length).toBe(2);
|
||||
const remoteBrowser = await playwright.connect({
|
||||
browserWSEndpoint: browser.chromium.wsEndpoint()
|
||||
});
|
||||
const contexts = remoteBrowser.browserContexts();
|
||||
expect(contexts.length).toBe(2);
|
||||
remoteBrowser.disconnect();
|
||||
await context.close();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const utils = require('./utils');
|
||||
|
||||
module.exports.addLauncherTests = function({testRunner, expect, defaultBrowserOptions, playwright}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
@ -94,6 +96,57 @@ module.exports.addLauncherTests = function({testRunner, expect, defaultBrowserOp
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser target events', function() {
|
||||
it('should work', async({server}) => {
|
||||
const browser = await playwright.launch(defaultBrowserOptions);
|
||||
const events = [];
|
||||
browser.chromium.on('targetcreated', () => events.push('CREATED'));
|
||||
browser.chromium.on('targetchanged', () => events.push('CHANGED'));
|
||||
browser.chromium.on('targetdestroyed', () => events.push('DESTROYED'));
|
||||
const page = await browser.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.close();
|
||||
expect(events).toEqual(['CREATED', 'CHANGED', 'DESTROYED']);
|
||||
await browser.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser.Events.disconnected', function() {
|
||||
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async() => {
|
||||
const originalBrowser = await playwright.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.chromium.wsEndpoint();
|
||||
const remoteBrowser1 = await playwright.connect({browserWSEndpoint});
|
||||
const remoteBrowser2 = await playwright.connect({browserWSEndpoint});
|
||||
|
||||
let disconnectedOriginal = 0;
|
||||
let disconnectedRemote1 = 0;
|
||||
let disconnectedRemote2 = 0;
|
||||
originalBrowser.on('disconnected', () => ++disconnectedOriginal);
|
||||
remoteBrowser1.on('disconnected', () => ++disconnectedRemote1);
|
||||
remoteBrowser2.on('disconnected', () => ++disconnectedRemote2);
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser2, 'disconnected'),
|
||||
remoteBrowser2.disconnect(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(0);
|
||||
expect(disconnectedRemote1).toBe(0);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser1, 'disconnected'),
|
||||
utils.waitEvent(originalBrowser, 'disconnected'),
|
||||
originalBrowser.close(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(1);
|
||||
expect(disconnectedRemote1).toBe(1);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.exports.addPageTests = function({testRunner, expect}) {
|
||||
|
@ -50,14 +50,14 @@ module.exports.addTests = function({testRunner, expect, playwright, defaultBrows
|
||||
it('background_page target type should be available', async() => {
|
||||
const browserWithExtension = await playwright.launch(extensionOptions);
|
||||
const page = await browserWithExtension.newPage();
|
||||
const backgroundPageTarget = await browserWithExtension.waitForTarget(target => target.type() === 'background_page');
|
||||
const backgroundPageTarget = await browserWithExtension.chromium.waitForTarget(target => target.type() === 'background_page');
|
||||
await page.close();
|
||||
await browserWithExtension.close();
|
||||
expect(backgroundPageTarget).toBeTruthy();
|
||||
});
|
||||
it('target.page() should return a background_page', async({}) => {
|
||||
const browserWithExtension = await playwright.launch(extensionOptions);
|
||||
const backgroundPageTarget = await browserWithExtension.waitForTarget(target => target.type() === 'background_page');
|
||||
const backgroundPageTarget = await browserWithExtension.chromium.waitForTarget(target => target.type() === 'background_page');
|
||||
const page = await backgroundPageTarget.page();
|
||||
expect(await page.evaluate(() => 2 * 3)).toBe(6);
|
||||
expect(await page.evaluate(() => window.MAGIC)).toBe(42);
|
||||
@ -123,7 +123,7 @@ module.exports.addTests = function({testRunner, expect, playwright, defaultBrows
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
await Promise.all([
|
||||
context.newPage(),
|
||||
context.waitForTarget(target => target.url().includes('devtools://')),
|
||||
browser.chromium.waitForTarget(target => target.browserContext() === context && target.url().includes('devtools://')),
|
||||
]);
|
||||
await browser.close();
|
||||
});
|
||||
|
@ -344,7 +344,7 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
|
||||
const browserOne = await playwright.launch(defaultBrowserOptions);
|
||||
const browserTwo = await playwright.connect({ ...defaultBrowserOptions, browserWSEndpoint: browserOne.chromium.wsEndpoint() });
|
||||
const [page1, page2] = await Promise.all([
|
||||
new Promise(x => browserOne.once('targetcreated', target => x(target.page()))),
|
||||
new Promise(x => browserOne.chromium.once('targetcreated', target => x(target.page()))),
|
||||
browserTwo.newPage(),
|
||||
]);
|
||||
expect(await page1.evaluate(() => 7 * 8)).toBe(56);
|
||||
@ -372,55 +372,4 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
|
||||
expect(Devices['iPhone 6']).toBe(playwright.devices['iPhone 6']);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip(WEBKIT)('Browser target events', function() {
|
||||
it('should work', async({server}) => {
|
||||
const browser = await playwright.launch(defaultBrowserOptions);
|
||||
const events = [];
|
||||
browser.on('targetcreated', () => events.push('CREATED'));
|
||||
browser.on('targetchanged', () => events.push('CHANGED'));
|
||||
browser.on('targetdestroyed', () => events.push('DESTROYED'));
|
||||
const page = await browser.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.close();
|
||||
expect(events).toEqual(['CREATED', 'CHANGED', 'DESTROYED']);
|
||||
await browser.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip(WEBKIT || FFOX)('Browser.Events.disconnected', function() {
|
||||
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async() => {
|
||||
const originalBrowser = await playwright.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.chromium.wsEndpoint();
|
||||
const remoteBrowser1 = await playwright.connect({browserWSEndpoint});
|
||||
const remoteBrowser2 = await playwright.connect({browserWSEndpoint});
|
||||
|
||||
let disconnectedOriginal = 0;
|
||||
let disconnectedRemote1 = 0;
|
||||
let disconnectedRemote2 = 0;
|
||||
originalBrowser.on('disconnected', () => ++disconnectedOriginal);
|
||||
remoteBrowser1.on('disconnected', () => ++disconnectedRemote1);
|
||||
remoteBrowser2.on('disconnected', () => ++disconnectedRemote2);
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser2, 'disconnected'),
|
||||
remoteBrowser2.disconnect(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(0);
|
||||
expect(disconnectedRemote1).toBe(0);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser1, 'disconnected'),
|
||||
utils.waitEvent(originalBrowser, 'disconnected'),
|
||||
originalBrowser.close(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(1);
|
||||
expect(disconnectedRemote1).toBe(1);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -57,5 +57,5 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
|
||||
* @param {!Playwright.BrowserContext} context
|
||||
*/
|
||||
function oopifs(context) {
|
||||
return context.targets().filter(target => target._targetInfo.type === 'iframe');
|
||||
return context.browser().chromium.targets().filter(target => target._targetInfo.type === 'iframe');
|
||||
}
|
||||
|
@ -289,9 +289,8 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
// 3. After that, remove the iframe.
|
||||
frame.remove();
|
||||
});
|
||||
const popupTarget = page.browserContext().targets().find(target => target !== page.target());
|
||||
// 4. Connect to the popup and make sure it doesn't throw.
|
||||
await popupTarget.page();
|
||||
await page.browserContext().pages();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1145,8 +1144,8 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
// FIXME: WebKit shouldn't send targetDestroyed on PSON so that we could
|
||||
// convert target destroy events into close.
|
||||
describe('Page.Events.Close', function() {
|
||||
it.skip(WEBKIT)('should work with window.close', async function({ page, context, server }) {
|
||||
const newPagePromise = new Promise(fulfill => context.once('targetcreated', target => fulfill(target.page())));
|
||||
it.skip(WEBKIT)('should work with window.close', async function({ browser, page, context, server }) {
|
||||
const newPagePromise = new Promise(fulfill => browser.chromium.once('targetcreated', target => fulfill(target.page())));
|
||||
await page.evaluate(() => window['newPage'] = window.open('about:blank'));
|
||||
const newPage = await newPagePromise;
|
||||
const closedPromise = new Promise(x => newPage.on('close', x));
|
||||
|
@ -153,7 +153,6 @@ module.exports.addTests = ({testRunner, product, playwrightPath}) => {
|
||||
// FIXME: screenshot tests will fail when running in parallel (maybe)
|
||||
require('./screenshot.spec.js').addTests(testOptions);
|
||||
require('./queryselector.spec.js').addTests(testOptions);
|
||||
require('./target.spec.js').addTests(testOptions);
|
||||
require('./waittask.spec.js').addTests(testOptions);
|
||||
if (CHROME) {
|
||||
require('./CDPSession.spec.js').addTests(testOptions);
|
||||
@ -162,6 +161,7 @@ module.exports.addTests = ({testRunner, product, playwrightPath}) => {
|
||||
require('./chromiumonly.spec.js').addPageTests(testOptions);
|
||||
require('../src/chromium/features/geolocation.spec.js').addTests(testOptions);
|
||||
require('../src/chromium/features/pdf.spec.js').addTests(testOptions);
|
||||
require('../src/chromium/features/chromium.spec.js').addTests(testOptions);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -67,7 +67,7 @@ describe('Playwright-Web', () => {
|
||||
});
|
||||
it('should work over exposed DevTools protocol', async({browser, page, serverConfig}) => {
|
||||
// Expose devtools protocol binding into page.
|
||||
const session = await browser.chromium.createBrowserCDPSession();
|
||||
const session = await browser.chromium.browserTarget().createCDPSession();
|
||||
const pageInfo = (await session.send('Target.getTargets')).targetInfos.find(info => info.attached);
|
||||
await session.send('Target.exposeDevToolsProtocol', {targetId: pageInfo.targetId});
|
||||
await session.detach();
|
||||
|
Loading…
Reference in New Issue
Block a user