chore: wait for frames to be destroyed (#11919)

This commit is contained in:
jrandolf 2024-02-15 09:22:23 +01:00 committed by GitHub
parent bd4d0febf0
commit a02c7a56f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 6 deletions

View File

@ -9,6 +9,9 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {Observable} from '../../third_party/rxjs/rxjs.js'; import type {Observable} from '../../third_party/rxjs/rxjs.js';
import { import {
combineLatest, combineLatest,
defer,
delayWhen,
filter,
first, first,
firstValueFrom, firstValueFrom,
map, map,
@ -258,6 +261,22 @@ export class BidiFrame extends Frame {
}); });
} }
#detached$() {
return defer(() => {
if (this.detached) {
return of(this as Frame);
}
return fromEmitterEvent(
this.page().trustedEmitter,
PageEvent.FrameDetached
).pipe(
filter(detachedFrame => {
return detachedFrame === this;
})
);
});
}
@throwIfDetached @throwIfDetached
override async goto( override async goto(
url: string, url: string,
@ -265,12 +284,12 @@ export class BidiFrame extends Frame {
): Promise<BidiHTTPResponse | null> { ): Promise<BidiHTTPResponse | null> {
const [response] = await Promise.all([ const [response] = await Promise.all([
this.waitForNavigation(options), this.waitForNavigation(options),
// Some implementations currently only report errors when the
// readiness=interactive.
//
// Related: https://bugzilla.mozilla.org/show_bug.cgi?id=1846601
this.browsingContext.navigate( this.browsingContext.navigate(
url, url,
// Some implementations currently only report errors when the
// readiness=interactive. This also ensures that old frames have been
// removed.
// Related: https://bugzilla.mozilla.org/show_bug.cgi?id=1846601
Bidi.BrowsingContext.ReadinessState.Interactive Bidi.BrowsingContext.ReadinessState.Interactive
), ),
]).catch( ]).catch(
@ -304,11 +323,20 @@ export class BidiFrame extends Frame {
): Promise<BidiHTTPResponse | null> { ): Promise<BidiHTTPResponse | null> {
const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options; const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options;
const frames = this.childFrames().map(frame => {
return frame.#detached$();
});
return await firstValueFrom( return await firstValueFrom(
combineLatest([ combineLatest([
fromEmitterEvent(this.browsingContext, 'navigation').pipe( fromEmitterEvent(this.browsingContext, 'navigation').pipe(
switchMap(({navigation}) => { switchMap(({navigation}) => {
return this.#waitForLoad$(options).pipe( return this.#waitForLoad$(options).pipe(
delayWhen(() => {
if (frames.length === 0) {
return of(undefined);
}
return combineLatest(frames);
}),
raceWith( raceWith(
fromEmitterEvent(navigation, 'fragment'), fromEmitterEvent(navigation, 'fragment'),
fromEmitterEvent(navigation, 'failed').pipe( fromEmitterEvent(navigation, 'failed').pipe(
@ -343,7 +371,7 @@ export class BidiFrame extends Frame {
}), }),
raceWith( raceWith(
timeout(ms), timeout(ms),
fromEmitterEvent(this.browsingContext, 'closed').pipe( this.#detached$().pipe(
map(() => { map(() => {
throw new TargetCloseError('Frame detached.'); throw new TargetCloseError('Frame detached.');
}) })
@ -437,7 +465,7 @@ export class BidiFrame extends Frame {
first(), first(),
raceWith( raceWith(
timeout(ms), timeout(ms),
fromEmitterEvent(this.browsingContext, 'closed').pipe( this.#detached$().pipe(
map(() => { map(() => {
throw new Error('Frame detached.'); throw new Error('Frame detached.');
}) })

View File

@ -18,6 +18,7 @@ export {
first, first,
firstValueFrom, firstValueFrom,
forkJoin, forkJoin,
delayWhen,
from, from,
fromEvent, fromEvent,
identity, identity,