Skip to content

Commit 6acc439

Browse files
authored
feat(api): move targets from CRBrowser to CRBrowserContext (#1089)
This makes them work for default context.
1 parent de03f37 commit 6acc439

12 files changed

+171
-143
lines changed

docs/api.md

+63-35
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- [class: BrowserServer](#class-browserserver)
2626
- [class: BrowserType](#class-browsertype)
2727
- [class: ChromiumBrowser](#class-chromiumbrowser)
28+
- [class: ChromiumBrowserContext](#class-chromiumbrowsercontext)
2829
- [class: ChromiumCoverage](#class-chromiumcoverage)
2930
- [class: ChromiumSession](#class-chromiumsession)
3031
- [class: ChromiumTarget](#class-chromiumtarget)
@@ -3532,15 +3533,9 @@ await browser.stopTracing();
35323533
```
35333534

35343535
<!-- GEN:toc -->
3535-
- [event: 'targetchanged'](#event-targetchanged)
3536-
- [event: 'targetcreated'](#event-targetcreated)
3537-
- [event: 'targetdestroyed'](#event-targetdestroyed)
35383536
- [chromiumBrowser.browserTarget()](#chromiumbrowserbrowsertarget)
3539-
- [chromiumBrowser.pageTarget(page)](#chromiumbrowserpagetargetpage)
35403537
- [chromiumBrowser.startTracing(page, [options])](#chromiumbrowserstarttracingpage-options)
35413538
- [chromiumBrowser.stopTracing()](#chromiumbrowserstoptracing)
3542-
- [chromiumBrowser.targets(context)](#chromiumbrowsertargetscontext)
3543-
- [chromiumBrowser.waitForTarget(predicate[, options])](#chromiumbrowserwaitfortargetpredicate-options)
35443539
<!-- GEN:stop -->
35453540
<!-- GEN:toc-extends-Browser -->
35463541
- [event: 'disconnected'](#event-disconnected)
@@ -3551,69 +3546,101 @@ await browser.stopTracing();
35513546
- [browser.newPage([options])](#browsernewpageoptions)
35523547
<!-- GEN:stop -->
35533548

3549+
#### chromiumBrowser.browserTarget()
3550+
- returns: <[ChromiumTarget]>
3551+
3552+
Returns browser target.
3553+
3554+
#### chromiumBrowser.startTracing(page, [options])
3555+
- `page` <[Page]> Optional, if specified, tracing includes screenshots of the given page.
3556+
- `options` <[Object]>
3557+
- `path` <[string]> A path to write the trace file to.
3558+
- `screenshots` <[boolean]> captures screenshots in the trace.
3559+
- `categories` <[Array]<[string]>> specify custom categories to use instead of default.
3560+
- returns: <[Promise]>
3561+
3562+
Only one trace can be active at a time per browser.
3563+
3564+
#### chromiumBrowser.stopTracing()
3565+
- returns: <[Promise]<[Buffer]>> Promise which resolves to buffer with trace data.
3566+
3567+
### class: ChromiumBrowserContext
3568+
3569+
* extends: [BrowserContext]
3570+
3571+
Chromium-specific features including targets, service worker support, etc.
3572+
3573+
```js
3574+
const backroundPageTarget = await context.waitForTarget(target => target.type() === 'background_page');
3575+
const backgroundPage = await backroundPageTarget.page();
3576+
```
3577+
3578+
<!-- GEN:toc -->
3579+
- [event: 'targetchanged'](#event-targetchanged)
3580+
- [event: 'targetcreated'](#event-targetcreated)
3581+
- [event: 'targetdestroyed'](#event-targetdestroyed)
3582+
- [chromiumBrowserContext.pageTarget(page)](#chromiumbrowsercontextpagetargetpage)
3583+
- [chromiumBrowserContext.targets()](#chromiumbrowsercontexttargets)
3584+
- [chromiumBrowserContext.waitForTarget(predicate[, options])](#chromiumbrowsercontextwaitfortargetpredicate-options)
3585+
<!-- GEN:stop -->
3586+
<!-- GEN:toc-extends-BrowserContext -->
3587+
- [event: 'close'](#event-close)
3588+
- [browserContext.clearCookies()](#browsercontextclearcookies)
3589+
- [browserContext.clearPermissions()](#browsercontextclearpermissions)
3590+
- [browserContext.close()](#browsercontextclose)
3591+
- [browserContext.cookies([...urls])](#browsercontextcookiesurls)
3592+
- [browserContext.newPage()](#browsercontextnewpage)
3593+
- [browserContext.pages()](#browsercontextpages)
3594+
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
3595+
- [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout)
3596+
- [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout)
3597+
- [browserContext.setGeolocation(geolocation)](#browsercontextsetgeolocationgeolocation)
3598+
- [browserContext.setPermissions(origin, permissions[])](#browsercontextsetpermissionsorigin-permissions)
3599+
<!-- GEN:stop -->
3600+
35543601
#### event: 'targetchanged'
35553602
- <[ChromiumTarget]>
35563603

35573604
Emitted when the url of a target changes.
35583605

3559-
> **NOTE** This includes target changes in incognito browser contexts.
3606+
> **NOTE** Only includes targets from this browser context.
35603607
35613608

35623609
#### event: 'targetcreated'
35633610
- <[ChromiumTarget]>
35643611

35653612
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).
35663613

3567-
> **NOTE** This includes target creations in incognito browser contexts.
3614+
> **NOTE** Only includes targets from this browser context.
35683615
35693616
#### event: 'targetdestroyed'
35703617
- <[ChromiumTarget]>
35713618

35723619
Emitted when a target is destroyed, for example when a page is closed.
35733620

3574-
> **NOTE** This includes target destructions in incognito browser contexts.
3575-
3576-
#### chromiumBrowser.browserTarget()
3577-
- returns: <[ChromiumTarget]>
3578-
3579-
Returns browser target.
3621+
> **NOTE** Only includes targets from this browser context.
35803622
3581-
#### chromiumBrowser.pageTarget(page)
3623+
#### chromiumBrowserContext.pageTarget(page)
35823624
- `page` <[Page]> Page to return target for.
35833625
- returns: <[ChromiumTarget]> a target given page was created from.
35843626

3585-
#### chromiumBrowser.startTracing(page, [options])
3586-
- `page` <[Page]> Optional, if specified, tracing includes screenshots of the given page.
3587-
- `options` <[Object]>
3588-
- `path` <[string]> A path to write the trace file to.
3589-
- `screenshots` <[boolean]> captures screenshots in the trace.
3590-
- `categories` <[Array]<[string]>> specify custom categories to use instead of default.
3591-
- returns: <[Promise]>
3592-
3593-
Only one trace can be active at a time per browser.
3594-
3595-
#### chromiumBrowser.stopTracing()
3596-
- returns: <[Promise]<[Buffer]>> Promise which resolves to buffer with trace data.
3597-
3598-
#### chromiumBrowser.targets(context)
3599-
- `context` <[BrowserContext]> Optional, if specified, only targets from this context are returned.
3627+
#### chromiumBrowserContext.targets()
36003628
- returns: <[Array]<[ChromiumTarget]>>
36013629

3602-
An array of all active targets inside the Browser. In case of multiple browser contexts,
3603-
the method will return an array with all the targets in all browser contexts.
3630+
An array of all active targets inside the browser context.
36043631

3605-
#### chromiumBrowser.waitForTarget(predicate[, options])
3632+
#### chromiumBrowserContext.waitForTarget(predicate[, options])
36063633
- `predicate` <[function]\([ChromiumTarget]\):[boolean]> A function to be run for every target
36073634
- `options` <[Object]>
36083635
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
36093636
- returns: <[Promise]<[ChromiumTarget]>> Promise which resolves to the first target found that matches the `predicate` function.
36103637

3611-
This searches for a target in all browser contexts.
3638+
This searches for a target in the browser context.
36123639

36133640
An example of finding a target for a page opened via `window.open`:
36143641
```js
36153642
await page.evaluate(() => window.open('https://www.example.com/'));
3616-
const newWindowTarget = await browser.chromium.waitForTarget(target => target.url() === 'https://www.example.com/');
3643+
const newWindowTarget = await page.context().waitForTarget(target => target.url() === 'https://www.example.com/');
36173644
```
36183645

36193646
### class: ChromiumCoverage
@@ -3875,6 +3902,7 @@ const { chromium } = require('playwright');
38753902
[Buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer "Buffer"
38763903
[ChildProcess]: https://nodejs.org/api/child_process.html "ChildProcess"
38773904
[ChromiumBrowser]: #class-chromiumbrowser "ChromiumBrowser"
3905+
[ChromiumBrowserContext]: #class-chromiumbrowsercontext "ChromiumBrowserContext"
38783906
[ChromiumSession]: #class-chromiumsession "ChromiumSession"
38793907
[ChromiumTarget]: #class-chromiumtarget "ChromiumTarget"
38803908
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"

src/api.ts

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export { FileChooser, Page, Worker } from './page';
2929
export { Selectors } from './selectors';
3030

3131
export { CRBrowser as ChromiumBrowser } from './chromium/crBrowser';
32+
export { CRBrowserContext as ChromiumBrowserContext } from './chromium/crBrowser';
3233
export { CRCoverage as ChromiumCoverage } from './chromium/crCoverage';
3334
export { CRSession as ChromiumSession } from './chromium/crConnection';
3435
export { CRTarget as ChromiumTarget } from './chromium/crTarget';

src/chromium/crBrowser.ts

+36-39
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { TimeoutSettings } from '../timeoutSettings';
3535
export class CRBrowser extends platform.EventEmitter implements Browser {
3636
_connection: CRConnection;
3737
_client: CRSession;
38-
readonly _defaultContext: BrowserContext;
38+
readonly _defaultContext: CRBrowserContext;
3939
readonly _contexts = new Map<string, CRBrowserContext>();
4040
_targets = new Map<string, CRTarget>();
4141

@@ -93,7 +93,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
9393
this._targets.set(event.targetInfo.targetId, target);
9494

9595
if (target._isInitialized || await target._initializedPromise)
96-
this.emit(Events.CRBrowser.TargetCreated, target);
96+
context.emit(Events.CRBrowserContext.TargetCreated, target);
9797
}
9898

9999
async _targetDestroyed(event: { targetId: string; }) {
@@ -102,7 +102,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
102102
this._targets.delete(event.targetId);
103103
target._didClose();
104104
if (await target._initializedPromise)
105-
this.emit(Events.CRBrowser.TargetDestroyed, target);
105+
target.context().emit(Events.CRBrowserContext.TargetDestroyed, target);
106106
}
107107

108108
_targetInfoChanged(event: Protocol.Target.targetInfoChangedPayload) {
@@ -112,7 +112,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
112112
const wasInitialized = target._isInitialized;
113113
target._targetInfoChanged(event.targetInfo);
114114
if (wasInitialized && previousURL !== target.url())
115-
this.emit(Events.CRBrowser.TargetChanged, target);
115+
target.context().emit(Events.CRBrowserContext.TargetChanged, target);
116116
}
117117

118118
async _closePage(page: Page) {
@@ -123,32 +123,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
123123
return Array.from(this._targets.values()).filter(target => target._isInitialized);
124124
}
125125

126-
async waitForTarget(predicate: (arg0: CRTarget) => boolean, options: { timeout?: number; } | undefined = {}): Promise<CRTarget> {
127-
const {
128-
timeout = 30000
129-
} = options;
130-
const existingTarget = this._allTargets().find(predicate);
131-
if (existingTarget)
132-
return existingTarget;
133-
let resolve: (target: CRTarget) => void;
134-
const targetPromise = new Promise<CRTarget>(x => resolve = x);
135-
this.on(Events.CRBrowser.TargetCreated, check);
136-
this.on(Events.CRBrowser.TargetChanged, check);
137-
try {
138-
if (!timeout)
139-
return await targetPromise;
140-
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
141-
} finally {
142-
this.removeListener(Events.CRBrowser.TargetCreated, check);
143-
this.removeListener(Events.CRBrowser.TargetChanged, check);
144-
}
145-
146-
function check(target: CRTarget) {
147-
if (predicate(target))
148-
resolve(target);
149-
}
150-
}
151-
152126
async close() {
153127
const disconnected = new Promise(f => this._connection.once(ConnectionEvents.Disconnected, f));
154128
await Promise.all(this.contexts().map(context => context.close()));
@@ -199,15 +173,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
199173
return contentPromise;
200174
}
201175

202-
targets(context?: BrowserContext): CRTarget[] {
203-
const targets = this._allTargets();
204-
return context ? targets.filter(t => t.context() === context) : targets;
205-
}
206-
207-
pageTarget(page: Page): CRTarget {
208-
return CRTarget.fromPage(page);
209-
}
210-
211176
isConnected(): boolean {
212177
return !this._connection._closed;
213178
}
@@ -339,6 +304,38 @@ export class CRBrowserContext extends platform.EventEmitter implements BrowserCo
339304
this.emit(CommonEvents.BrowserContext.Close);
340305
}
341306

307+
pageTarget(page: Page): CRTarget {
308+
return CRTarget.fromPage(page);
309+
}
310+
311+
targets(): CRTarget[] {
312+
return this._browser._allTargets().filter(t => t.context() === this);
313+
}
314+
315+
async waitForTarget(predicate: (arg0: CRTarget) => boolean, options: { timeout?: number; } = {}): Promise<CRTarget> {
316+
const { timeout = 30000 } = options;
317+
const existingTarget = this._browser._allTargets().find(predicate);
318+
if (existingTarget)
319+
return existingTarget;
320+
let resolve: (target: CRTarget) => void;
321+
const targetPromise = new Promise<CRTarget>(x => resolve = x);
322+
this.on(Events.CRBrowserContext.TargetCreated, check);
323+
this.on(Events.CRBrowserContext.TargetChanged, check);
324+
try {
325+
if (!timeout)
326+
return await targetPromise;
327+
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
328+
} finally {
329+
this.removeListener(Events.CRBrowserContext.TargetCreated, check);
330+
this.removeListener(Events.CRBrowserContext.TargetChanged, check);
331+
}
332+
333+
function check(target: CRTarget) {
334+
if (predicate(target))
335+
resolve(target);
336+
}
337+
}
338+
342339
_browserClosed() {
343340
this._closed = true;
344341
for (const page of this._existingPages())

src/chromium/crTarget.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { CRBrowser } from './crBrowser';
19-
import { BrowserContext } from '../browserContext';
18+
import { CRBrowser, CRBrowserContext } from './crBrowser';
2019
import { CRSession, CRSessionEvents } from './crConnection';
2120
import { Events } from '../events';
2221
import { Page, Worker } from '../page';
@@ -30,7 +29,7 @@ const targetSymbol = Symbol('target');
3029
export class CRTarget {
3130
private _targetInfo: Protocol.Target.TargetInfo;
3231
private readonly _browser: CRBrowser;
33-
private readonly _browserContext: BrowserContext;
32+
private readonly _browserContext: CRBrowserContext;
3433
readonly _targetId: string;
3534
private _sessionFactory: () => Promise<CRSession>;
3635
private _pagePromise: Promise<Page> | null = null;
@@ -47,7 +46,7 @@ export class CRTarget {
4746
constructor(
4847
browser: CRBrowser,
4948
targetInfo: Protocol.Target.TargetInfo,
50-
browserContext: BrowserContext,
49+
browserContext: CRBrowserContext,
5150
sessionFactory: () => Promise<CRSession>) {
5251
this._targetInfo = targetInfo;
5352
this._browser = browser;
@@ -120,7 +119,7 @@ export class CRTarget {
120119
return 'other';
121120
}
122121

123-
context(): BrowserContext {
122+
context(): CRBrowserContext {
124123
return this._browserContext;
125124
}
126125

src/chromium/events.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
export const Events = {
19-
CRBrowser: {
19+
CRBrowserContext: {
2020
TargetCreated: 'targetcreated',
2121
TargetDestroyed: 'targetdestroyed',
2222
TargetChanged: 'targetchanged',

src/server/chromium.ts

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

test/browsercontext.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
3838
const context = await browser.newContext();
3939
const page = await context.newPage();
4040
await page.goto(server.EMPTY_PAGE);
41-
const [popupTarget] = await Promise.all([
41+
const [popup] = await Promise.all([
4242
utils.waitEvent(page, 'popup'),
4343
page.evaluate(url => window.open(url), server.EMPTY_PAGE)
4444
]);
45-
expect(popupTarget.context()).toBe(context);
45+
expect(popup.context()).toBe(context);
4646
await context.close();
4747
});
4848
it('should isolate localStorage and cookies', async function({browser, server}) {

0 commit comments

Comments
 (0)