mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat(bidi): implement UserContexts (#11784)
This commit is contained in:
parent
9ff6bd3805
commit
2930a70c88
@ -119,7 +119,9 @@ export class BidiBrowser extends Browser {
|
||||
this.#browserCore = browserCore;
|
||||
this.#defaultViewport = opts.defaultViewport;
|
||||
this.#browserTarget = new BiDiBrowserTarget(this);
|
||||
this.#createBrowserContext(this.#browserCore.defaultUserContext);
|
||||
for (const context of this.#browserCore.userContexts) {
|
||||
this.#createBrowserContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
#initialize() {
|
||||
@ -159,6 +161,7 @@ export class BidiBrowser extends Browser {
|
||||
const target = this.#targets.get(event.context);
|
||||
if (target) {
|
||||
this.emit(BrowserEvent.TargetChanged, target);
|
||||
target.browserContext().emit(BrowserContextEvent.TargetChanged, target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,10 +180,12 @@ export class BidiBrowser extends Browser {
|
||||
this.#browserName
|
||||
);
|
||||
this.connection.registerBrowsingContexts(context);
|
||||
// TODO: once more browsing context types are supported, this should be
|
||||
// updated to support those. Currently, all top-level contexts are treated
|
||||
// as pages.
|
||||
const browserContext = this.browserContexts().at(-1);
|
||||
const browserContext =
|
||||
event.userContext === 'default'
|
||||
? this.defaultBrowserContext()
|
||||
: this.browserContexts().find(browserContext => {
|
||||
return browserContext.id === event.userContext;
|
||||
});
|
||||
if (!browserContext) {
|
||||
throw new Error('Missing browser contexts');
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ export class BidiBrowserContext extends BrowserContext {
|
||||
override async newPage(): Promise<Page> {
|
||||
const {result} = await this.#connection.send('browsingContext.create', {
|
||||
type: Bidi.BrowsingContext.CreateType.Tab,
|
||||
userContext: this.#userContext.id,
|
||||
});
|
||||
const target = this.#browser._getTargetById(result.context);
|
||||
|
||||
@ -99,16 +100,6 @@ export class BidiBrowserContext extends BrowserContext {
|
||||
throw new Error('Default context cannot be closed!');
|
||||
}
|
||||
|
||||
// TODO: Remove once we have adopted the new browsing contexts.
|
||||
for (const target of this.targets()) {
|
||||
const page = await target?.page();
|
||||
try {
|
||||
await page?.close();
|
||||
} catch (error) {
|
||||
debugError(error);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.#userContext.remove();
|
||||
} catch (error) {
|
||||
@ -142,4 +133,11 @@ export class BidiBrowserContext extends BrowserContext {
|
||||
override clearPermissionOverrides(): never {
|
||||
throw new UnsupportedOperation();
|
||||
}
|
||||
|
||||
override get id(): string | undefined {
|
||||
if (this.#userContext.id === 'default') {
|
||||
return undefined;
|
||||
}
|
||||
return this.#userContext.id;
|
||||
}
|
||||
}
|
||||
|
@ -85,9 +85,26 @@ export class Browser extends EventEmitter<{
|
||||
}
|
||||
});
|
||||
|
||||
await this.#syncUserContexts();
|
||||
await this.#syncBrowsingContexts();
|
||||
}
|
||||
|
||||
async #syncUserContexts() {
|
||||
const {
|
||||
result: {userContexts},
|
||||
} = await this.session.send('browser.getUserContexts', {});
|
||||
|
||||
for (const context of userContexts) {
|
||||
if (context.userContext === UserContext.DEFAULT) {
|
||||
continue;
|
||||
}
|
||||
this.#userContexts.set(
|
||||
context.userContext,
|
||||
UserContext.create(this, context.userContext)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async #syncBrowsingContexts() {
|
||||
// In case contexts are created or destroyed during `getTree`, we use this
|
||||
// set to detect them.
|
||||
@ -185,16 +202,14 @@ export class Browser extends EventEmitter<{
|
||||
});
|
||||
}
|
||||
|
||||
static userContextId = 0;
|
||||
@throwIfDisposed<Browser>(browser => {
|
||||
// SAFETY: By definition of `disposed`, `#reason` is defined.
|
||||
return browser.#reason!;
|
||||
})
|
||||
async createUserContext(): Promise<UserContext> {
|
||||
// TODO: implement incognito context https://github.com/w3c/webdriver-bidi/issues/289.
|
||||
// TODO: Call `createUserContext` once available.
|
||||
// Generating a monotonically increasing context id.
|
||||
const context = `${++Browser.userContextId}`;
|
||||
const {
|
||||
result: {userContext: context},
|
||||
} = await this.session.send('browser.createUserContext', {});
|
||||
|
||||
const userContext = UserContext.create(this, context);
|
||||
this.#userContexts.set(userContext.id, userContext);
|
||||
|
@ -38,6 +38,21 @@ export interface Commands {
|
||||
returnType: Bidi.EmptyResult;
|
||||
};
|
||||
|
||||
'browser.createUserContext': {
|
||||
params: Bidi.EmptyParams;
|
||||
returnType: Bidi.Browser.CreateUserContextResult;
|
||||
};
|
||||
'browser.getUserContexts': {
|
||||
params: Bidi.EmptyParams;
|
||||
returnType: Bidi.Browser.GetUserContextsResult;
|
||||
};
|
||||
'browser.removeUserContext': {
|
||||
params: {
|
||||
userContext: Bidi.Browser.UserContext;
|
||||
};
|
||||
returnType: Bidi.Browser.RemoveUserContext;
|
||||
};
|
||||
|
||||
'browsingContext.activate': {
|
||||
params: Bidi.BrowsingContext.ActivateParameters;
|
||||
returnType: Bidi.EmptyResult;
|
||||
|
@ -84,6 +84,10 @@ export class UserContext extends EventEmitter<{
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.userContext !== this.#id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const browsingContext = BrowsingContext.from(
|
||||
this,
|
||||
undefined,
|
||||
@ -143,6 +147,7 @@ export class UserContext extends EventEmitter<{
|
||||
type,
|
||||
...options,
|
||||
referenceContext: options.referenceContext?.id,
|
||||
userContext: this.#id,
|
||||
});
|
||||
|
||||
const browsingContext = this.#browsingContexts.get(contextId);
|
||||
@ -161,7 +166,9 @@ export class UserContext extends EventEmitter<{
|
||||
})
|
||||
async remove(): Promise<void> {
|
||||
try {
|
||||
// TODO: Call `removeUserContext` once available.
|
||||
await this.#session.send('browser.removeUserContext', {
|
||||
userContext: this.#id,
|
||||
});
|
||||
} finally {
|
||||
this.dispose('User context already closed.');
|
||||
}
|
||||
|
@ -353,6 +353,18 @@
|
||||
"parameters": ["webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should be prompt by default",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -629,12 +641,6 @@
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["SKIP"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["webDriverBiDi"],
|
||||
"expectations": ["FAIL", "TIMEOUT"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -1363,6 +1369,20 @@
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should create new incognito context",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should fire target events",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "In BiDi currently more events than needed are fired (because target is updated more often). We probably need to adjust the test as the behavior is not broken per se"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should fire target events",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -1370,10 +1390,11 @@
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should provide a context id",
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should have default context",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["cdp", "firefox"],
|
||||
"expectations": ["FAIL"]
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext should timeout waiting for a non-existent target",
|
||||
@ -1405,6 +1426,13 @@
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browsercontext.spec] BrowserContext window.open should use parent tab context",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -2894,6 +2922,20 @@
|
||||
"parameters": ["cdp", "firefox"],
|
||||
"expectations": ["SKIP"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Close should work with window.close",
|
||||
"platforms": ["linux"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["TIMEOUT"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Close should work with window.close",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["PASS", "TIMEOUT"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -2924,6 +2966,20 @@
|
||||
"parameters": ["cdp", "firefox"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Console should not throw when there are console messages in detached iframes",
|
||||
"platforms": ["linux"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Console should not throw when there are console messages in detached iframes",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL", "PASS"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -3404,6 +3460,13 @@
|
||||
"parameters": ["chrome", "webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should be able to use async waitForTarget",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should contain browser target",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -3428,6 +3491,13 @@
|
||||
"parameters": ["cdp", "firefox"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -3446,6 +3516,13 @@
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should report when a new page is created and closed",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Re-test after user contexts land"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[target.spec] Target should report when a new page is created and closed",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
|
@ -52,7 +52,9 @@ describe('Browser specs', function () {
|
||||
expect(process!.pid).toBeGreaterThan(0);
|
||||
});
|
||||
it('should not return child_process for remote browser', async () => {
|
||||
const {browser, puppeteer} = await getTestState();
|
||||
const {browser, puppeteer} = await getTestState({
|
||||
skipContextCreation: true,
|
||||
});
|
||||
|
||||
const browserWSEndpoint = browser.wsEndpoint();
|
||||
const remoteBrowser = await puppeteer.connect({
|
||||
@ -66,7 +68,9 @@ describe('Browser specs', function () {
|
||||
|
||||
describe('Browser.isConnected', () => {
|
||||
it('should set the browser connected state', async () => {
|
||||
const {browser, puppeteer} = await getTestState();
|
||||
const {browser, puppeteer} = await getTestState({
|
||||
skipContextCreation: true,
|
||||
});
|
||||
|
||||
const browserWSEndpoint = browser.wsEndpoint();
|
||||
const newBrowser = await puppeteer.connect({
|
||||
|
@ -214,15 +214,18 @@ describe('BrowserContext', function () {
|
||||
|
||||
expect(browser.browserContexts()).toHaveLength(1);
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
expect(browser.browserContexts()).toHaveLength(2);
|
||||
const remoteBrowser = await puppeteer.connect({
|
||||
browserWSEndpoint: browser.wsEndpoint(),
|
||||
protocol: browser.protocol,
|
||||
});
|
||||
const contexts = remoteBrowser.browserContexts();
|
||||
expect(contexts).toHaveLength(2);
|
||||
await remoteBrowser.disconnect();
|
||||
await context.close();
|
||||
try {
|
||||
expect(browser.browserContexts()).toHaveLength(2);
|
||||
const remoteBrowser = await puppeteer.connect({
|
||||
browserWSEndpoint: browser.wsEndpoint(),
|
||||
protocol: browser.protocol,
|
||||
});
|
||||
const contexts = remoteBrowser.browserContexts();
|
||||
expect(contexts).toHaveLength(2);
|
||||
await remoteBrowser.disconnect();
|
||||
} finally {
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
|
||||
it('should provide a context id', async () => {
|
||||
|
@ -48,7 +48,10 @@ describe('Launcher specs', function () {
|
||||
[
|
||||
'Navigating frame was detached',
|
||||
'Protocol error (Page.navigate): Target closed.',
|
||||
].includes(error.message)
|
||||
'Protocol error (browsingContext.navigate): Target closed',
|
||||
].some(message => {
|
||||
return error.message.startsWith(message);
|
||||
})
|
||||
).toBeTruthy();
|
||||
} finally {
|
||||
await close();
|
||||
|
Loading…
Reference in New Issue
Block a user