feat(api): move targets from CRBrowser to CRBrowserContext (#1089)

This makes them work for default context.
This commit is contained in:
Dmitry Gozman 2020-02-24 14:35:51 -08:00 committed by GitHub
parent de03f37a99
commit 6acc439450
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 174 additions and 146 deletions

View File

@ -25,6 +25,7 @@
- [class: BrowserServer](#class-browserserver)
- [class: BrowserType](#class-browsertype)
- [class: ChromiumBrowser](#class-chromiumbrowser)
- [class: ChromiumBrowserContext](#class-chromiumbrowsercontext)
- [class: ChromiumCoverage](#class-chromiumcoverage)
- [class: ChromiumSession](#class-chromiumsession)
- [class: ChromiumTarget](#class-chromiumtarget)
@ -3532,15 +3533,9 @@ await browser.stopTracing();
```
<!-- GEN:toc -->
- [event: 'targetchanged'](#event-targetchanged)
- [event: 'targetcreated'](#event-targetcreated)
- [event: 'targetdestroyed'](#event-targetdestroyed)
- [chromiumBrowser.browserTarget()](#chromiumbrowserbrowsertarget)
- [chromiumBrowser.pageTarget(page)](#chromiumbrowserpagetargetpage)
- [chromiumBrowser.startTracing(page, [options])](#chromiumbrowserstarttracingpage-options)
- [chromiumBrowser.stopTracing()](#chromiumbrowserstoptracing)
- [chromiumBrowser.targets(context)](#chromiumbrowsertargetscontext)
- [chromiumBrowser.waitForTarget(predicate[, options])](#chromiumbrowserwaitfortargetpredicate-options)
<!-- GEN:stop -->
<!-- GEN:toc-extends-Browser -->
- [event: 'disconnected'](#event-disconnected)
@ -3551,37 +3546,11 @@ await browser.stopTracing();
- [browser.newPage([options])](#browsernewpageoptions)
<!-- GEN:stop -->
#### event: 'targetchanged'
- <[ChromiumTarget]>
Emitted when the url of a target changes.
> **NOTE** This includes target changes in incognito browser contexts.
#### event: 'targetcreated'
- <[ChromiumTarget]>
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 [`browserContext.newPage`](#browsercontextnewpage).
> **NOTE** This includes target creations in incognito browser contexts.
#### event: 'targetdestroyed'
- <[ChromiumTarget]>
Emitted when a target is destroyed, for example when a page is closed.
> **NOTE** This includes target destructions in incognito browser contexts.
#### chromiumBrowser.browserTarget()
- returns: <[ChromiumTarget]>
Returns browser target.
#### chromiumBrowser.pageTarget(page)
- `page` <[Page]> Page to return target for.
- returns: <[ChromiumTarget]> a target given page was created from.
#### chromiumBrowser.startTracing(page, [options])
- `page` <[Page]> Optional, if specified, tracing includes screenshots of the given page.
- `options` <[Object]>
@ -3595,25 +3564,83 @@ Only one trace can be active at a time per browser.
#### chromiumBrowser.stopTracing()
- returns: <[Promise]<[Buffer]>> Promise which resolves to buffer with trace data.
#### chromiumBrowser.targets(context)
- `context` <[BrowserContext]> Optional, if specified, only targets from this context are returned.
### class: ChromiumBrowserContext
* extends: [BrowserContext]
Chromium-specific features including targets, service worker support, etc.
```js
const backroundPageTarget = await context.waitForTarget(target => target.type() === 'background_page');
const backgroundPage = await backroundPageTarget.page();
```
<!-- GEN:toc -->
- [event: 'targetchanged'](#event-targetchanged)
- [event: 'targetcreated'](#event-targetcreated)
- [event: 'targetdestroyed'](#event-targetdestroyed)
- [chromiumBrowserContext.pageTarget(page)](#chromiumbrowsercontextpagetargetpage)
- [chromiumBrowserContext.targets()](#chromiumbrowsercontexttargets)
- [chromiumBrowserContext.waitForTarget(predicate[, options])](#chromiumbrowsercontextwaitfortargetpredicate-options)
<!-- GEN:stop -->
<!-- GEN:toc-extends-BrowserContext -->
- [event: 'close'](#event-close)
- [browserContext.clearCookies()](#browsercontextclearcookies)
- [browserContext.clearPermissions()](#browsercontextclearpermissions)
- [browserContext.close()](#browsercontextclose)
- [browserContext.cookies([...urls])](#browsercontextcookiesurls)
- [browserContext.newPage()](#browsercontextnewpage)
- [browserContext.pages()](#browsercontextpages)
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
- [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout)
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
- [browserContext.setGeolocation(geolocation)](#browsercontextsetgeolocationgeolocation)
- [browserContext.setPermissions(origin, permissions[])](#browsercontextsetpermissionsorigin-permissions)
<!-- GEN:stop -->
#### event: 'targetchanged'
- <[ChromiumTarget]>
Emitted when the url of a target changes.
> **NOTE** Only includes targets from this browser context.
#### event: 'targetcreated'
- <[ChromiumTarget]>
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 [`browserContext.newPage`](#browsercontextnewpage).
> **NOTE** Only includes targets from this browser context.
#### event: 'targetdestroyed'
- <[ChromiumTarget]>
Emitted when a target is destroyed, for example when a page is closed.
> **NOTE** Only includes targets from this browser context.
#### chromiumBrowserContext.pageTarget(page)
- `page` <[Page]> Page to return target for.
- returns: <[ChromiumTarget]> a target given page was created from.
#### chromiumBrowserContext.targets()
- returns: <[Array]<[ChromiumTarget]>>
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.
An array of all active targets inside the browser context.
#### chromiumBrowser.waitForTarget(predicate[, options])
#### chromiumBrowserContext.waitForTarget(predicate[, options])
- `predicate` <[function]\([ChromiumTarget]\):[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]<[ChromiumTarget]>> Promise which resolves to the first target found that matches the `predicate` function.
This searches for a target in all browser contexts.
This searches for a target in the 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 browser.chromium.waitForTarget(target => target.url() === 'https://www.example.com/');
const newWindowTarget = await page.context().waitForTarget(target => target.url() === 'https://www.example.com/');
```
### class: ChromiumCoverage
@ -3875,6 +3902,7 @@ const { chromium } = require('playwright');
[Buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer "Buffer"
[ChildProcess]: https://nodejs.org/api/child_process.html "ChildProcess"
[ChromiumBrowser]: #class-chromiumbrowser "ChromiumBrowser"
[ChromiumBrowserContext]: #class-chromiumbrowsercontext "ChromiumBrowserContext"
[ChromiumSession]: #class-chromiumsession "ChromiumSession"
[ChromiumTarget]: #class-chromiumtarget "ChromiumTarget"
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"

View File

@ -29,6 +29,7 @@ export { FileChooser, Page, Worker } from './page';
export { Selectors } from './selectors';
export { CRBrowser as ChromiumBrowser } from './chromium/crBrowser';
export { CRBrowserContext as ChromiumBrowserContext } from './chromium/crBrowser';
export { CRCoverage as ChromiumCoverage } from './chromium/crCoverage';
export { CRSession as ChromiumSession } from './chromium/crConnection';
export { CRTarget as ChromiumTarget } from './chromium/crTarget';

View File

@ -35,7 +35,7 @@ import { TimeoutSettings } from '../timeoutSettings';
export class CRBrowser extends platform.EventEmitter implements Browser {
_connection: CRConnection;
_client: CRSession;
readonly _defaultContext: BrowserContext;
readonly _defaultContext: CRBrowserContext;
readonly _contexts = new Map<string, CRBrowserContext>();
_targets = new Map<string, CRTarget>();
@ -93,7 +93,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
this._targets.set(event.targetInfo.targetId, target);
if (target._isInitialized || await target._initializedPromise)
this.emit(Events.CRBrowser.TargetCreated, target);
context.emit(Events.CRBrowserContext.TargetCreated, target);
}
async _targetDestroyed(event: { targetId: string; }) {
@ -102,7 +102,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
this._targets.delete(event.targetId);
target._didClose();
if (await target._initializedPromise)
this.emit(Events.CRBrowser.TargetDestroyed, target);
target.context().emit(Events.CRBrowserContext.TargetDestroyed, target);
}
_targetInfoChanged(event: Protocol.Target.targetInfoChangedPayload) {
@ -112,7 +112,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
const wasInitialized = target._isInitialized;
target._targetInfoChanged(event.targetInfo);
if (wasInitialized && previousURL !== target.url())
this.emit(Events.CRBrowser.TargetChanged, target);
target.context().emit(Events.CRBrowserContext.TargetChanged, target);
}
async _closePage(page: Page) {
@ -123,32 +123,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
return Array.from(this._targets.values()).filter(target => target._isInitialized);
}
async waitForTarget(predicate: (arg0: CRTarget) => boolean, options: { timeout?: number; } | undefined = {}): Promise<CRTarget> {
const {
timeout = 30000
} = options;
const existingTarget = this._allTargets().find(predicate);
if (existingTarget)
return existingTarget;
let resolve: (target: CRTarget) => void;
const targetPromise = new Promise<CRTarget>(x => resolve = x);
this.on(Events.CRBrowser.TargetCreated, check);
this.on(Events.CRBrowser.TargetChanged, check);
try {
if (!timeout)
return await targetPromise;
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
} finally {
this.removeListener(Events.CRBrowser.TargetCreated, check);
this.removeListener(Events.CRBrowser.TargetChanged, check);
}
function check(target: CRTarget) {
if (predicate(target))
resolve(target);
}
}
async close() {
const disconnected = new Promise(f => this._connection.once(ConnectionEvents.Disconnected, f));
await Promise.all(this.contexts().map(context => context.close()));
@ -199,15 +173,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
return contentPromise;
}
targets(context?: BrowserContext): CRTarget[] {
const targets = this._allTargets();
return context ? targets.filter(t => t.context() === context) : targets;
}
pageTarget(page: Page): CRTarget {
return CRTarget.fromPage(page);
}
isConnected(): boolean {
return !this._connection._closed;
}
@ -339,6 +304,38 @@ export class CRBrowserContext extends platform.EventEmitter implements BrowserCo
this.emit(CommonEvents.BrowserContext.Close);
}
pageTarget(page: Page): CRTarget {
return CRTarget.fromPage(page);
}
targets(): CRTarget[] {
return this._browser._allTargets().filter(t => t.context() === this);
}
async waitForTarget(predicate: (arg0: CRTarget) => boolean, options: { timeout?: number; } = {}): Promise<CRTarget> {
const { timeout = 30000 } = options;
const existingTarget = this._browser._allTargets().find(predicate);
if (existingTarget)
return existingTarget;
let resolve: (target: CRTarget) => void;
const targetPromise = new Promise<CRTarget>(x => resolve = x);
this.on(Events.CRBrowserContext.TargetCreated, check);
this.on(Events.CRBrowserContext.TargetChanged, check);
try {
if (!timeout)
return await targetPromise;
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
} finally {
this.removeListener(Events.CRBrowserContext.TargetCreated, check);
this.removeListener(Events.CRBrowserContext.TargetChanged, check);
}
function check(target: CRTarget) {
if (predicate(target))
resolve(target);
}
}
_browserClosed() {
this._closed = true;
for (const page of this._existingPages())

View File

@ -15,8 +15,7 @@
* limitations under the License.
*/
import { CRBrowser } from './crBrowser';
import { BrowserContext } from '../browserContext';
import { CRBrowser, CRBrowserContext } from './crBrowser';
import { CRSession, CRSessionEvents } from './crConnection';
import { Events } from '../events';
import { Page, Worker } from '../page';
@ -30,7 +29,7 @@ const targetSymbol = Symbol('target');
export class CRTarget {
private _targetInfo: Protocol.Target.TargetInfo;
private readonly _browser: CRBrowser;
private readonly _browserContext: BrowserContext;
private readonly _browserContext: CRBrowserContext;
readonly _targetId: string;
private _sessionFactory: () => Promise<CRSession>;
private _pagePromise: Promise<Page> | null = null;
@ -47,7 +46,7 @@ export class CRTarget {
constructor(
browser: CRBrowser,
targetInfo: Protocol.Target.TargetInfo,
browserContext: BrowserContext,
browserContext: CRBrowserContext,
sessionFactory: () => Promise<CRSession>) {
this._targetInfo = targetInfo;
this._browser = browser;
@ -120,7 +119,7 @@ export class CRTarget {
return 'other';
}
context(): BrowserContext {
context(): CRBrowserContext {
return this._browserContext;
}

View File

@ -16,7 +16,7 @@
*/
export const Events = {
CRBrowser: {
CRBrowserContext: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',

View File

@ -68,7 +68,7 @@ export class Chromium implements BrowserType {
const { timeout = 30000 } = options || {};
const { browserServer, transport } = await this._launchServer(options, 'persistent', userDataDir);
const browser = await CRBrowser.connect(transport!);
await helper.waitWithTimeout(browser.waitForTarget(t => t.type() === 'page'), 'first page', timeout);
await helper.waitWithTimeout(browser._defaultContext.waitForTarget(t => t.type() === 'page'), 'first page', timeout);
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
const browserContext = browser._defaultContext;
browserContext.close = () => browserServer.close();

View File

@ -38,11 +38,11 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
const [popupTarget] = await Promise.all([
const [popup] = await Promise.all([
utils.waitEvent(page, 'popup'),
page.evaluate(url => window.open(url), server.EMPTY_PAGE)
]);
expect(popupTarget.context()).toBe(context);
expect(popup.context()).toBe(context);
await context.close();
});
it('should isolate localStorage and cookies', async function({browser, server}) {

View File

@ -25,28 +25,31 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
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();
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');
it('ChromiumBrowserContext.targets should return all of the targets', async({page, server, browser}) => {
const second = await page.context().newPage();
await second.goto(server.EMPTY_PAGE);
const targets = page.context().targets();
// The pages will be the testing page from the harness and the one created here.
expect(targets.length).toBe(2);
expect(targets.some(target => target.type() !== 'page')).toBe(false);
expect(targets.some(target => target.url() === 'about:blank')).toBeTruthy('Missing blank page');
expect(targets.some(target => target.url() === server.EMPTY_PAGE)).toBeTruthy('Missing new page');
await second.close();
});
it('Browser.pages should return all of the pages', async({page, server, context}) => {
// The pages will be the testing page
it('BrowserContext.pages should return all of the pages', async({page, server, context}) => {
const second = await page.context().newPage();
const allPages = await context.pages();
expect(allPages.length).toBe(1);
expect(allPages.length).toBe(2);
expect(allPages).toContain(page);
expect(allPages[0]).not.toBe(allPages[1]);
expect(allPages).toContain(second);
await second.close();
});
it('should contain browser target', async({browser}) => {
const targets = browser.targets();
const browserTarget = targets.find(target => target.type() === 'browser');
expect(browserTarget).toBe(browser.browserTarget());
it('should report browser target', async({browser}) => {
expect(browser.browserTarget()).toBeTruthy();
});
it('should report when a new page is created and closed', async({browser, page, server, context}) => {
const [otherPage] = await Promise.all([
browser.waitForTarget(target => target.url() === server.CROSS_PROCESS_PREFIX + '/empty.html').then(target => target.page()),
page.context().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);
@ -57,31 +60,31 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
expect(allPages).toContain(page);
expect(allPages).toContain(otherPage);
const closePagePromise = new Promise(fulfill => browser.once('targetdestroyed', target => fulfill(target.page())));
const closePagePromise = new Promise(fulfill => page.context().once('targetdestroyed', target => fulfill(target.page())));
await otherPage.close();
expect(await closePagePromise).toBe(otherPage);
allPages = await Promise.all(browser.targets().map(target => target.page()));
allPages = await Promise.all(page.context().targets().map(target => target.page()));
expect(allPages).toContain(page);
expect(allPages).not.toContain(otherPage);
});
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 => browser.once('targetcreated', target => fulfill(target)));
const createdTarget = new Promise(fulfill => page.context().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 => browser.once('targetdestroyed', target => fulfill(target)));
const destroyedTarget = new Promise(fulfill => page.context().once('targetdestroyed', target => fulfill(target)));
await page.evaluate(() => window.registrationPromise.then(registration => registration.unregister()));
expect(await destroyedTarget).toBe(await createdTarget);
});
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 browser.waitForTarget(target => target.type() === 'service_worker');
const target = await page.context().waitForTarget(target => target.type() === 'service_worker');
const worker = await target.serviceWorker();
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
});
@ -90,17 +93,17 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
await page.evaluate(() => {
new SharedWorker('data:text/javascript,console.log("hi")');
});
const target = await browser.waitForTarget(target => target.type() === 'shared_worker');
const target = await page.context().waitForTarget(target => target.type() === 'shared_worker');
const worker = await target.serviceWorker();
expect(worker).toBe(null);
});
it('should report when a target url changes', async({browser, page, server, context}) => {
await page.goto(server.EMPTY_PAGE);
let changedTarget = new Promise(fulfill => browser.once('targetchanged', target => fulfill(target)));
let changedTarget = new Promise(fulfill => page.context().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 => browser.once('targetchanged', target => fulfill(target)));
changedTarget = new Promise(fulfill => page.context().once('targetchanged', target => fulfill(target)));
await page.goto(server.EMPTY_PAGE);
expect((await changedTarget).url()).toBe(server.EMPTY_PAGE);
});
@ -108,13 +111,13 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
let targetChanged = false;
const listener = () => targetChanged = true;
browser.on('targetchanged', listener);
const targetPromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target)));
const targetPromise = new Promise(fulfill => context.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 => browser.once('targetcreated', target => fulfill(target)));
const targetPromise2 = new Promise(fulfill => context.once('targetcreated', target => fulfill(target)));
const evaluatePromise = newPage.evaluate(() => window.open('about:blank'));
const target2 = await targetPromise2;
expect(target2.url()).toBe('about:blank');
@ -132,7 +135,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
server.waitForRequest('/one-style.css')
]);
// Connect to the opened page.
const target = await browser.waitForTarget(target => target.url().includes('one-style.html'));
const target = await page.context().waitForTarget(target => target.url().includes('one-style.html'));
const newPage = await target.page();
// Issue a redirect.
serverResponse.writeHead(302, { location: '/injectedstyle.css' });
@ -145,23 +148,21 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
it('should have an opener', async({browser, page, server, context}) => {
await page.goto(server.EMPTY_PAGE);
const [createdTarget] = await Promise.all([
new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))),
new Promise(fulfill => page.context().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(browser.pageTarget(page));
expect(browser.pageTarget(page).opener()).toBe(null);
expect(createdTarget.opener()).toBe(page.context().pageTarget(page));
expect(page.context().pageTarget(page).opener()).toBe(null);
});
it('should close all belonging targets once closing context', async function({browser}) {
const targets = async (context) => (await browser.targets()).filter(t => t.type() === 'page' && t.context() === context);
const context = await browser.newContext();
await context.newPage();
expect((await targets(context)).length).toBe(1);
expect((await context.targets()).length).toBe(1);
expect((await context.pages()).length).toBe(1);
await context.close();
expect((await targets(context)).length).toBe(0);
expect((await context.targets()).length).toBe(0);
});
});
@ -169,7 +170,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
it('should wait for a target', async function({server, browser}) {
const context = await browser.newContext();
let resolved = false;
const targetPromise = browser.waitForTarget(target => target.context() === context && target.url() === server.EMPTY_PAGE);
const targetPromise = context.waitForTarget(target => target.url() === server.EMPTY_PAGE);
targetPromise.then(() => resolved = true);
const page = await context.newPage();
expect(resolved).toBe(false);
@ -179,26 +180,27 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
await context.close();
});
it('should timeout waiting for a non-existent target', async function({browser, context, server}) {
const error = await browser.waitForTarget(target => target.context() === context && target.url() === server.EMPTY_PAGE, {timeout: 1}).catch(e => e);
const error = await context.waitForTarget(target => target.url() === server.EMPTY_PAGE, {timeout: 1}).catch(e => e);
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
});
it('should wait for a target', async function({browser, server}) {
const context = await browser.newContext();
let resolved = false;
const targetPromise = browser.waitForTarget(target => target.url() === server.EMPTY_PAGE);
const targetPromise = context.waitForTarget(target => target.url() === server.EMPTY_PAGE);
targetPromise.then(() => resolved = true);
const page = await browser.newPage();
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 page.context().close();
await context.close();
});
it('should fire target events', async function({browser, server}) {
const context = await browser.newContext();
const events = [];
browser.on('targetcreated', target => events.push('CREATED: ' + target.url()));
browser.on('targetchanged', target => events.push('CHANGED: ' + target.url()));
browser.on('targetdestroyed', target => events.push('DESTROYED: ' + target.url()));
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()));
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
await page.close();

View File

@ -51,17 +51,18 @@ module.exports.describe = 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 page.context().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 page = await backgroundPageTarget.page();
expect(await page.evaluate(() => 2 * 3)).toBe(6);
expect(await page.evaluate(() => window.MAGIC)).toBe(42);
const page = await browserWithExtension.newPage();
const backgroundPageTarget = await page.context().waitForTarget(target => target.type() === 'background_page');
const backgroundPage = await backgroundPageTarget.page();
expect(await backgroundPage.evaluate(() => 2 * 3)).toBe(6);
expect(await backgroundPage.evaluate(() => window.MAGIC)).toBe(42);
await browserWithExtension.close();
});
// TODO: Support OOOPIF. @see https://github.com/GoogleChrome/puppeteer/issues/2548
@ -91,7 +92,7 @@ module.exports.describe = function({testRunner, expect, playwright, defaultBrows
const context = await browser.newContext();
await Promise.all([
context.newPage(),
browser.waitForTarget(target => target.context() === context && target.url().includes('devtools://')),
context.waitForTarget(target => target.url().includes('devtools://')),
]);
await browser.close();
});

View File

@ -59,9 +59,9 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
const browser = await playwright.launch(defaultBrowserOptions);
const context = await browser.newContext();
const events = [];
browser.on('targetcreated', target => target.context() === context && events.push('CREATED'));
browser.on('targetchanged', target => target.context() === context && events.push('CHANGED'));
browser.on('targetdestroyed', target => target.context() === context && events.push('DESTROYED'));
context.on('targetcreated', target => events.push('CREATED'));
context.on('targetchanged', target => events.push('CHANGED'));
context.on('targetdestroyed', target => events.push('DESTROYED'));
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
await page.close();

View File

@ -43,18 +43,18 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
});
xit('should report oopif frames', async function({browser, page, server, context}) {
await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(oopifs(browser).length).toBe(1);
expect(oopifs(page.context()).length).toBe(1);
expect(page.frames().length).toBe(2);
});
it('should load oopif iframes with subresources and request interception', async function({browser, page, server, context}) {
await page.route('*', request => request.continue());
await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(oopifs(browser).length).toBe(1);
expect(oopifs(page.context()).length).toBe(1);
});
});
};
function oopifs(browser) {
return browser.targets().filter(target => target._targetInfo.type === 'iframe');
function oopifs(context) {
return context.targets().filter(target => target._targetInfo.type === 'iframe');
}

View File

@ -26,7 +26,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
describe('Chromium.createCDPSession', function() {
it('should work', async function({page, browser, server}) {
const client = await browser.pageTarget(page).createCDPSession();
const client = await page.context().pageTarget(page).createCDPSession();
await Promise.all([
client.send('Runtime.enable'),
@ -36,7 +36,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(foo).toBe('bar');
});
it('should send events', async function({page, browser, server}) {
const client = await browser.pageTarget(page).createCDPSession();
const client = await page.context().pageTarget(page).createCDPSession();
await client.send('Network.enable');
const events = [];
client.on('Network.requestWillBeSent', event => events.push(event));
@ -44,7 +44,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(events.length).toBe(1);
});
it('should enable and disable domains independently', async function({page, browser, server}) {
const client = await browser.pageTarget(page).createCDPSession();
const client = await page.context().pageTarget(page).createCDPSession();
await client.send('Runtime.enable');
await client.send('Debugger.enable');
// JS coverage enables and then disables Debugger domain.
@ -59,7 +59,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(event.url).toBe('foo.js');
});
it('should be able to detach session', async function({page, browser, server}) {
const client = await browser.pageTarget(page).createCDPSession();
const client = await page.context().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);
@ -73,7 +73,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(error.message).toContain('Session closed.');
});
it('should throw nice errors', async function({page, browser}) {
const client = await browser.pageTarget(page).createCDPSession();
const client = await page.context().pageTarget(page).createCDPSession();
const error = await theSourceOfTheProblems().catch(error => error);
expect(error.stack).toContain('theSourceOfTheProblems');
expect(error.message).toContain('ThisCommand.DoesNotExist');