fix: custom sessions should not emit targetcreated events (#8788)

Closes #8787
This commit is contained in:
Alex Rudenko 2022-08-16 12:56:13 +02:00 committed by GitHub
parent 65a5ce8464
commit 3fad05d333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 19 deletions

View File

@ -492,8 +492,11 @@ export class Browser extends EventEmitter {
session, session,
context, context,
this.#targetManager, this.#targetManager,
() => { (isAutoAttachEmulated: boolean) => {
return this.#connection.createSession(targetInfo); return this.#connection._createSession(
targetInfo,
isAutoAttachEmulated
);
}, },
this.#ignoreHTTPSErrors, this.#ignoreHTTPSErrors,
this.#defaultViewport ?? null, this.#defaultViewport ?? null,

View File

@ -236,7 +236,7 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
// Special case (https://crbug.com/1338156): currently, shared_workers // Special case (https://crbug.com/1338156): currently, shared_workers
// don't get auto-attached. This should be removed once the auto-attach // don't get auto-attached. This should be removed once the auto-attach
// works. // works.
await this.#connection.createSession(event.targetInfo); await this.#connection._createSession(event.targetInfo, true);
} }
}; };
@ -300,6 +300,10 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
.catch(debugError); .catch(debugError);
}; };
if (!this.#connection.isAutoAttached(targetInfo.targetId)) {
return;
}
// Special case for service workers: being attached to service workers will // Special case for service workers: being attached to service workers will
// prevent them from ever being destroyed. Therefore, we silently detach // prevent them from ever being destroyed. Therefore, we silently detach
// from service workers unless the connection was manually created via // from service workers unless the connection was manually created via
@ -364,7 +368,9 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
} }
this.#targetsIdsForInit.delete(target._targetId); this.#targetsIdsForInit.delete(target._targetId);
this.emit(TargetManagerEmittedEvents.TargetAvailable, target); if (!existingTarget) {
this.emit(TargetManagerEmittedEvents.TargetAvailable, target);
}
this.#finishInitializationIfReady(); this.#finishInitializationIfReady();
// TODO: the browser might be shutting down here. What do we do with the // TODO: the browser might be shutting down here. What do we do with the

View File

@ -228,6 +228,28 @@ export class Connection extends EventEmitter {
return !this.#manuallyAttached.has(targetId); return !this.#manuallyAttached.has(targetId);
} }
/**
* @internal
*/
async _createSession(
targetInfo: Protocol.Target.TargetInfo,
isAutoAttachEmulated = true
): Promise<CDPSession> {
if (!isAutoAttachEmulated) {
this.#manuallyAttached.add(targetInfo.targetId);
}
const {sessionId} = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId,
flatten: true,
});
this.#manuallyAttached.delete(targetInfo.targetId);
const session = this.#sessions.get(sessionId);
if (!session) {
throw new Error('CDPSession creation failed.');
}
return session;
}
/** /**
* @param targetInfo - The target info * @param targetInfo - The target info
* @returns The CDP session that is created * @returns The CDP session that is created
@ -235,16 +257,7 @@ export class Connection extends EventEmitter {
async createSession( async createSession(
targetInfo: Protocol.Target.TargetInfo targetInfo: Protocol.Target.TargetInfo
): Promise<CDPSession> { ): Promise<CDPSession> {
this.#manuallyAttached.add(targetInfo.targetId); return await this._createSession(targetInfo, false);
const {sessionId} = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId,
flatten: true,
});
const session = this.#sessions.get(sessionId);
if (!session) {
throw new Error('CDPSession creation failed.');
}
return session;
} }
} }

View File

@ -30,7 +30,7 @@ export class Target {
#browserContext: BrowserContext; #browserContext: BrowserContext;
#session?: CDPSession; #session?: CDPSession;
#targetInfo: Protocol.Target.TargetInfo; #targetInfo: Protocol.Target.TargetInfo;
#sessionFactory: () => Promise<CDPSession>; #sessionFactory: (isAutoAttachEmulated: boolean) => Promise<CDPSession>;
#ignoreHTTPSErrors: boolean; #ignoreHTTPSErrors: boolean;
#defaultViewport?: Viewport; #defaultViewport?: Viewport;
#pagePromise?: Promise<Page>; #pagePromise?: Promise<Page>;
@ -76,7 +76,7 @@ export class Target {
session: CDPSession | undefined, session: CDPSession | undefined,
browserContext: BrowserContext, browserContext: BrowserContext,
targetManager: TargetManager, targetManager: TargetManager,
sessionFactory: () => Promise<CDPSession>, sessionFactory: (isAutoAttachEmulated: boolean) => Promise<CDPSession>,
ignoreHTTPSErrors: boolean, ignoreHTTPSErrors: boolean,
defaultViewport: Viewport | null, defaultViewport: Viewport | null,
screenshotTaskQueue: TaskQueue, screenshotTaskQueue: TaskQueue,
@ -132,7 +132,7 @@ export class Target {
* Creates a Chrome Devtools Protocol session attached to the target. * Creates a Chrome Devtools Protocol session attached to the target.
*/ */
createCDPSession(): Promise<CDPSession> { createCDPSession(): Promise<CDPSession> {
return this.#sessionFactory(); return this.#sessionFactory(false);
} }
/** /**
@ -155,7 +155,9 @@ export class Target {
async page(): Promise<Page | null> { async page(): Promise<Page | null> {
if (this._isPageTargetCallback(this.#targetInfo) && !this.#pagePromise) { if (this._isPageTargetCallback(this.#targetInfo) && !this.#pagePromise) {
this.#pagePromise = ( this.#pagePromise = (
this.#session ? Promise.resolve(this.#session) : this.#sessionFactory() this.#session
? Promise.resolve(this.#session)
: this.#sessionFactory(true)
).then(client => { ).then(client => {
return Page._create( return Page._create(
client, client,
@ -182,7 +184,9 @@ export class Target {
if (!this.#workerPromise) { if (!this.#workerPromise) {
// TODO(einbinder): Make workers send their console logs. // TODO(einbinder): Make workers send their console logs.
this.#workerPromise = ( this.#workerPromise = (
this.#session ? Promise.resolve(this.#session) : this.#sessionFactory() this.#session
? Promise.resolve(this.#session)
: this.#sessionFactory(false)
).then(client => { ).then(client => {
return new WebWorker( return new WebWorker(
client, client,

View File

@ -42,6 +42,20 @@ describeChromeOnly('Target.createCDPSession', function () {
}); });
expect(foo).toBe('bar'); expect(foo).toBe('bar');
}); });
it('should not report created targets for custom CDP sessions', async () => {
const {browser} = getTestState();
let called = 0;
browser.browserContexts()[0]!.on('targetcreated', async target => {
called++;
if (called > 1) {
throw new Error('Too many targets created');
}
await target.createCDPSession();
});
await browser.newPage();
});
it('should send events', async () => { it('should send events', async () => {
const {page, server} = getTestState(); const {page, server} = getTestState();