chore: use internal method for networkidle with BiDi (#11167)

This commit is contained in:
Nikolay Vitkov 2023-10-24 10:07:35 +02:00 committed by GitHub
parent f0af79a1d6
commit 5278de9276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 305 additions and 259 deletions

View File

@ -84,7 +84,6 @@ import type {Viewport} from '../common/Viewport.js';
import type {ScreenRecorder} from '../node/ScreenRecorder.js';
import {assert} from '../util/assert.js';
import {guarded} from '../util/decorators.js';
import type {Deferred} from '../util/Deferred.js';
import {
AsyncDisposableStack,
asyncDisposeSymbol,
@ -1741,36 +1740,32 @@ export abstract class Page extends EventEmitter<PageEvents> {
/**
* @internal
*/
protected async _waitForNetworkIdle(
_waitForNetworkIdle(
networkManager: BidiNetworkManager | CdpNetworkManager,
idleTime: number,
ms: number,
closedDeferred: Deferred<TargetCloseError>
): Promise<void> {
await firstValueFrom(
merge(
fromEvent(
networkManager,
NetworkManagerEvent.Request as unknown as string
),
fromEvent(
networkManager,
NetworkManagerEvent.Response as unknown as string
),
fromEvent(
networkManager,
NetworkManagerEvent.RequestFailed as unknown as string
)
).pipe(
startWith(null),
filter(() => {
return networkManager.inFlightRequestsCount() === 0;
}),
switchMap(v => {
return of(v).pipe(delay(idleTime));
}),
raceWith(timeout(ms), from(closedDeferred.valueOrThrow()))
)
requestsInFlight = 0
): Observable<void> {
return merge(
fromEvent(
networkManager,
NetworkManagerEvent.Request as unknown as string
) as Observable<void>,
fromEvent(
networkManager,
NetworkManagerEvent.Response as unknown as string
) as Observable<void>,
fromEvent(
networkManager,
NetworkManagerEvent.RequestFailed as unknown as string
) as Observable<void>
).pipe(
startWith(undefined),
filter(() => {
return networkManager.inFlightRequestsCount() <= requestsInFlight;
}),
switchMap(v => {
return of(v).pipe(delay(idleTime));
})
);
}

View File

@ -3,27 +3,14 @@ import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
import {CDPSession} from '../api/CDPSession.js';
import type {Connection as CdpConnection} from '../cdp/Connection.js';
import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js';
import {TargetCloseError} from '../common/Errors.js';
import type {EventType} from '../common/EventEmitter.js';
import {debugError} from '../common/util.js';
import {assert} from '../util/assert.js';
import {Deferred} from '../util/Deferred.js';
import type {BidiConnection} from './Connection.js';
import {BidiRealm} from './Realm.js';
/**
* @internal
*/
export const lifeCycleToSubscribedEvent = new Map<
PuppeteerLifeCycleEvent,
string
>([
['load', 'browsingContext.load'],
['domcontentloaded', 'browsingContext.domContentLoaded'],
]);
/**
* @internal
*/
@ -198,30 +185,3 @@ export class BrowsingContext extends BidiRealm {
void this.#cdpSession.detach().catch(debugError);
}
}
/**
* @internal
*/
export function getWaitUntilSingle(
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
): Extract<PuppeteerLifeCycleEvent, 'load' | 'domcontentloaded'> {
if (Array.isArray(event) && event.length > 1) {
throw new Error('BiDi support only single `waitUntil` argument');
}
const waitUntilSingle = Array.isArray(event)
? (event.find(lifecycle => {
return lifecycle === 'domcontentloaded' || lifecycle === 'load';
}) as PuppeteerLifeCycleEvent)
: event;
if (
waitUntilSingle === 'networkidle0' ||
waitUntilSingle === 'networkidle2'
) {
throw new Error(`BiDi does not support 'waitUntil' ${waitUntilSingle}`);
}
assert(waitUntilSingle, `Invalid waitUntil option ${waitUntilSingle}`);
return waitUntilSingle;
}

View File

@ -16,16 +16,17 @@
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {ObservableInput} from '../../third_party/rxjs/rxjs.js';
import {
type Observable,
firstValueFrom,
from,
fromEvent,
merge,
raceWith,
switchMap,
map,
forkJoin,
first,
firstValueFrom,
raceWith,
} from '../../third_party/rxjs/rxjs.js';
import type {CDPSession} from '../api/CDPSession.js';
import {
@ -34,26 +35,26 @@ import {
type WaitForOptions,
throwIfDetached,
} from '../api/Frame.js';
import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js';
import {ProtocolError, TimeoutError} from '../common/Errors.js';
import type {TimeoutSettings} from '../common/TimeoutSettings.js';
import type {Awaitable} from '../common/types.js';
import {
NETWORK_IDLE_TIME,
UTILITY_WORLD_NAME,
setPageContent,
waitWithTimeout,
timeout,
} from '../common/util.js';
import {timeout} from '../common/util.js';
import {Deferred} from '../util/Deferred.js';
import {disposeSymbol} from '../util/disposable.js';
import {
getWaitUntilSingle,
lifeCycleToSubscribedEvent,
type BrowsingContext,
} from './BrowsingContext.js';
import type {BrowsingContext} from './BrowsingContext.js';
import {ExposeableFunction} from './ExposedFunction.js';
import type {BidiHTTPResponse} from './HTTPResponse.js';
import type {BiDiNetworkIdle} from './lifecycle.js';
import {
getBiDiLifecycleEvent,
getBiDiReadinessState,
rewriteNavigationError,
} from './lifecycle.js';
import type {BidiPage} from './Page.js';
import {
MAIN_SANDBOX,
@ -62,17 +63,6 @@ import {
type SandboxChart,
} from './Sandbox.js';
/**
* @internal
*/
export const lifeCycleToReadinessState = new Map<
PuppeteerLifeCycleEvent,
Bidi.BrowsingContext.ReadinessState
>([
['load', Bidi.BrowsingContext.ReadinessState.Complete],
['domcontentloaded', Bidi.BrowsingContext.ReadinessState.Interactive],
]);
/**
* Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation
* @internal
@ -145,33 +135,25 @@ export class BidiFrame extends Frame {
): Promise<BidiHTTPResponse | null> {
const {
waitUntil = 'load',
timeout = this.#timeoutSettings.navigationTimeout(),
timeout: ms = this.#timeoutSettings.navigationTimeout(),
} = options;
const readinessState = lifeCycleToReadinessState.get(
getWaitUntilSingle(waitUntil)
) as Bidi.BrowsingContext.ReadinessState;
const [readiness, networkIdle] = getBiDiReadinessState(waitUntil);
try {
const {result} = await waitWithTimeout(
const response = await firstValueFrom(
this._waitWithNetworkIdle(
this.#context.connection.send('browsingContext.navigate', {
url: url,
context: this._id,
wait: readinessState,
context: this.#context.id,
url,
wait: readiness,
}),
'Navigation',
timeout
);
networkIdle
)
.pipe(raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())))
.pipe(rewriteNavigationError(url, ms))
);
return this.#page.getNavigationResponse(result.navigation);
} catch (error) {
if (error instanceof ProtocolError) {
error.message += ` at ${url}`;
} else if (error instanceof TimeoutError) {
error.message = 'Navigation timeout of ' + timeout + ' ms exceeded';
}
throw error;
}
return this.#page.getNavigationResponse(response?.result.navigation);
}
@throwIfDetached
@ -184,15 +166,22 @@ export class BidiFrame extends Frame {
timeout: ms = this.#timeoutSettings.navigationTimeout(),
} = options;
const waitUntilEvent = lifeCycleToSubscribedEvent.get(
getWaitUntilSingle(waitUntil)
) as string;
const [waitEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil);
await firstValueFrom(
forkJoin([
fromEvent(this.#context, waitUntilEvent).pipe(first()),
from(setPageContent(this, html)),
]).pipe(raceWith(timeout(ms)))
this._waitWithNetworkIdle(
forkJoin([
fromEvent(this.#context, waitEvent).pipe(first()),
from(setPageContent(this, html)),
]).pipe(
map(() => {
return null;
})
),
networkIdle
)
.pipe(raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())))
.pipe(rewriteNavigationError('setContent', ms))
);
}
@ -209,31 +198,38 @@ export class BidiFrame extends Frame {
timeout: ms = this.#timeoutSettings.navigationTimeout(),
} = options;
const waitUntilEvent = lifeCycleToSubscribedEvent.get(
getWaitUntilSingle(waitUntil)
) as string;
const [waitUntilEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil);
const info = await firstValueFrom(
merge(
const navigatedObservable = merge(
forkJoin([
fromEvent(
this.#context,
Bidi.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted
).pipe(
switchMap(() => {
return fromEvent(
this.#context,
waitUntilEvent
) as Observable<Bidi.BrowsingContext.NavigationInfo>;
})
),
fromEvent(
this.#context,
Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated
) as Observable<Bidi.BrowsingContext.NavigationInfo>
).pipe(raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())))
).pipe(first()),
fromEvent(this.#context, waitUntilEvent).pipe(
first()
) as Observable<Bidi.BrowsingContext.NavigationInfo>,
]),
fromEvent(
this.#context,
Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated
) as Observable<Bidi.BrowsingContext.NavigationInfo>
).pipe(
map(result => {
if (Array.isArray(result)) {
return {result: result[1]};
}
return {result};
})
);
return this.#page.getNavigationResponse(info.navigation);
const response = await firstValueFrom(
this._waitWithNetworkIdle(navigatedObservable, networkIdle).pipe(
raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow()))
)
);
return this.#page.getNavigationResponse(response?.result.navigation);
}
override get detached(): boolean {
@ -270,4 +266,31 @@ export class BidiFrame extends Frame {
throw error;
}
}
/** @internal */
_waitWithNetworkIdle(
observableInput: ObservableInput<{
result: Bidi.BrowsingContext.NavigateResult;
} | null>,
networkIdle: BiDiNetworkIdle
): Observable<{
result: Bidi.BrowsingContext.NavigateResult;
} | null> {
const delay = networkIdle
? this.#page._waitForNetworkIdle(
this.#page._networkManager,
NETWORK_IDLE_TIME,
networkIdle === 'networkidle0' ? 0 : 2
)
: from(Promise.resolve());
return forkJoin([
from(observableInput).pipe(first()),
delay.pipe(first()),
]).pipe(
map(([response]) => {
return response;
})
);
}
}

View File

@ -122,7 +122,7 @@ export class BidiNetworkManager extends EventEmitter<NetworkManagerEvents> {
this.#requestMap.delete(event.request.request);
}
getNavigationResponse(navigationId: string | null): BidiHTTPResponse | null {
getNavigationResponse(navigationId?: string | null): BidiHTTPResponse | null {
if (!navigationId) {
return null;
}

View File

@ -39,11 +39,7 @@ import {
ConsoleMessage,
type ConsoleMessageLocation,
} from '../common/ConsoleMessage.js';
import {
ProtocolError,
TargetCloseError,
TimeoutError,
} from '../common/Errors.js';
import {TargetCloseError} from '../common/Errors.js';
import type {Handler} from '../common/EventEmitter.js';
import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js';
import type {PDFOptions} from '../common/PDFOptions.js';
@ -51,10 +47,10 @@ import type {Awaitable} from '../common/types.js';
import {
debugError,
evaluationString,
NETWORK_IDLE_TIME,
timeout,
validateDialogType,
waitForHTTP,
waitWithTimeout,
} from '../common/util.js';
import type {Viewport} from '../common/Viewport.js';
import {assert} from '../util/assert.js';
@ -66,7 +62,6 @@ import type {BidiBrowserContext} from './BrowserContext.js';
import {
BrowsingContextEvent,
CdpSessionWrapper,
getWaitUntilSingle,
type BrowsingContext,
} from './BrowsingContext.js';
import type {BidiConnection} from './Connection.js';
@ -74,11 +69,12 @@ import {BidiDeserializer} from './Deserializer.js';
import {BidiDialog} from './Dialog.js';
import {BidiElementHandle} from './ElementHandle.js';
import {EmulationManager} from './EmulationManager.js';
import {BidiFrame, lifeCycleToReadinessState} from './Frame.js';
import {BidiFrame} from './Frame.js';
import type {BidiHTTPRequest} from './HTTPRequest.js';
import type {BidiHTTPResponse} from './HTTPResponse.js';
import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js';
import type {BidiJSHandle} from './JSHandle.js';
import {getBiDiReadinessState, rewriteNavigationError} from './lifecycle.js';
import {BidiNetworkManager} from './NetworkManager.js';
import {createBidiHandle} from './Realm.js';
@ -89,7 +85,7 @@ export class BidiPage extends Page {
#accessibility: Accessibility;
#connection: BidiConnection;
#frameTree = new FrameTree<BidiFrame>();
#networkManager: BidiNetworkManager;
_networkManager: BidiNetworkManager;
#viewport: Viewport | null = null;
#closedDeferred = Deferred.create<never, TargetCloseError>();
#subscribedEvents = new Map<Bidi.Event['method'], Handler<any>>([
@ -169,7 +165,7 @@ export class BidiPage extends Page {
this.#browsingContext.on(event, subscriber);
}
this.#networkManager = new BidiNetworkManager(this.#connection, this);
this._networkManager = new BidiNetworkManager(this.#connection, this);
for (const [event, subscriber] of this.#subscribedEvents) {
this.#connection.on(event, subscriber);
@ -177,7 +173,7 @@ export class BidiPage extends Page {
for (const [event, subscriber] of this.#networkManagerEvents) {
// TODO: remove any
this.#networkManager.on(event, subscriber as any);
this._networkManager.on(event, subscriber as any);
}
const frame = new BidiFrame(
@ -381,7 +377,7 @@ export class BidiPage extends Page {
this.#removeFramesRecursively(child);
}
frame[disposeSymbol]();
this.#networkManager.clearMapAfterFrameDispose(frame);
this._networkManager.clearMapAfterFrameDispose(frame);
this.#frameTree.removeFrame(frame);
this.emit(PageEvent.FrameDetached, frame);
}
@ -460,8 +456,8 @@ export class BidiPage extends Page {
this.emit(PageEvent.Dialog, dialog);
}
getNavigationResponse(id: string | null): BidiHTTPResponse | null {
return this.#networkManager.getNavigationResponse(id);
getNavigationResponse(id?: string | null): BidiHTTPResponse | null {
return this._networkManager.getNavigationResponse(id);
}
override isClosed(): boolean {
@ -474,7 +470,7 @@ export class BidiPage extends Page {
}
this.#closedDeferred.reject(new TargetCloseError('Page closed!'));
this.#networkManager.dispose();
this._networkManager.dispose();
await this.#connection.send('browsingContext.close', {
context: this.mainFrame()._id,
@ -489,32 +485,25 @@ export class BidiPage extends Page {
): Promise<BidiHTTPResponse | null> {
const {
waitUntil = 'load',
timeout = this._timeoutSettings.navigationTimeout(),
timeout: ms = this._timeoutSettings.navigationTimeout(),
} = options;
const readinessState = lifeCycleToReadinessState.get(
getWaitUntilSingle(waitUntil)
) as Bidi.BrowsingContext.ReadinessState;
const [readiness, networkIdle] = getBiDiReadinessState(waitUntil);
try {
const {result} = await waitWithTimeout(
this.#connection.send('browsingContext.reload', {
context: this.mainFrame()._id,
wait: readinessState,
}),
'Navigation',
timeout
);
const response = await firstValueFrom(
this.mainFrame()
._waitWithNetworkIdle(
this.#connection.send('browsingContext.reload', {
context: this.mainFrame()._id,
wait: readiness,
}),
networkIdle
)
.pipe(raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow())))
.pipe(rewriteNavigationError(this.url(), ms))
);
return this.getNavigationResponse(result.navigation);
} catch (error) {
if (error instanceof ProtocolError) {
error.message += ` at ${this.url}`;
} else if (error instanceof TimeoutError) {
error.message = 'Navigation timeout of ' + timeout + ' ms exceeded';
}
throw error;
}
return this.getNavigationResponse(response?.result.navigation);
}
override setDefaultNavigationTimeout(timeout: number): void {
@ -692,7 +681,7 @@ export class BidiPage extends Page {
): Promise<BidiHTTPRequest> {
const {timeout = this._timeoutSettings.timeout()} = options;
return await waitForHTTP(
this.#networkManager,
this._networkManager,
NetworkManagerEvent.Request,
urlOrPredicate,
timeout,
@ -708,7 +697,7 @@ export class BidiPage extends Page {
): Promise<BidiHTTPResponse> {
const {timeout = this._timeoutSettings.timeout()} = options;
return await waitForHTTP(
this.#networkManager,
this._networkManager,
NetworkManagerEvent.Response,
urlOrPredicate,
timeout,
@ -719,13 +708,15 @@ export class BidiPage extends Page {
override async waitForNetworkIdle(
options: {idleTime?: number; timeout?: number} = {}
): Promise<void> {
const {idleTime = 500, timeout = this._timeoutSettings.timeout()} = options;
const {
idleTime = NETWORK_IDLE_TIME,
timeout: ms = this._timeoutSettings.timeout(),
} = options;
await this._waitForNetworkIdle(
this.#networkManager,
idleTime,
timeout,
this.#closedDeferred
await firstValueFrom(
this._waitForNetworkIdle(this._networkManager, idleTime).pipe(
raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow()))
)
);
}

View File

@ -0,0 +1,120 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {
ObservableInput,
ObservedValueOf,
OperatorFunction,
} from '../../third_party/rxjs/rxjs';
import {catchError} from '../../third_party/rxjs/rxjs';
import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher';
import {ProtocolError, TimeoutError} from '../common/Errors';
export type BiDiNetworkIdle = Extract<
PuppeteerLifeCycleEvent,
'networkidle0' | 'networkidle2'
> | null;
/**
* @internal
*/
export function getBiDiLifeCycles(
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
): [
Extract<PuppeteerLifeCycleEvent, 'load' | 'domcontentloaded'>,
BiDiNetworkIdle,
] {
if (Array.isArray(event)) {
const pageLifeCycle = event.some(lifeCycle => {
return lifeCycle !== 'domcontentloaded';
})
? 'load'
: 'domcontentloaded';
const networkLifeCycle = event.reduce((acc, lifeCycle) => {
if (lifeCycle === 'networkidle0') {
return lifeCycle;
} else if (acc !== 'networkidle0' && lifeCycle === 'networkidle2') {
return lifeCycle;
}
return acc;
}, null as BiDiNetworkIdle);
return [pageLifeCycle, networkLifeCycle];
}
if (event === 'networkidle0' || event === 'networkidle2') {
return ['load', event];
}
return [event, null];
}
/**
* @internal
*/
export const lifeCycleToReadinessState = new Map<
PuppeteerLifeCycleEvent,
Bidi.BrowsingContext.ReadinessState
>([
['load', Bidi.BrowsingContext.ReadinessState.Complete],
['domcontentloaded', Bidi.BrowsingContext.ReadinessState.Interactive],
]);
export function getBiDiReadinessState(
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
): [Bidi.BrowsingContext.ReadinessState, BiDiNetworkIdle] {
const lifeCycles = getBiDiLifeCycles(event);
const readiness = lifeCycleToReadinessState.get(lifeCycles[0])!;
return [readiness, lifeCycles[1]];
}
/**
* @internal
*/
export const lifeCycleToSubscribedEvent = new Map<
PuppeteerLifeCycleEvent,
'browsingContext.load' | 'browsingContext.domContentLoaded'
>([
['load', 'browsingContext.load'],
['domcontentloaded', 'browsingContext.domContentLoaded'],
]);
export function getBiDiLifecycleEvent(
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
): [
'browsingContext.load' | 'browsingContext.domContentLoaded',
BiDiNetworkIdle,
] {
const lifeCycles = getBiDiLifeCycles(event);
const bidiEvent = lifeCycleToSubscribedEvent.get(lifeCycles[0])!;
return [bidiEvent, lifeCycles[1]];
}
export function rewriteNavigationError<T, R extends ObservableInput<T>>(
message: string,
ms: number
): OperatorFunction<T, T | ObservedValueOf<R>> {
return catchError<T, R>(error => {
if (error instanceof ProtocolError) {
error.message += ` at ${message}`;
} else if (error instanceof TimeoutError) {
error.message = `Navigation timeout of ${ms} ms exceeded`;
}
throw error;
});
}

View File

@ -53,6 +53,7 @@ import {
evaluationString,
getReadableAsBuffer,
getReadableFromProtocolStream,
NETWORK_IDLE_TIME,
pageBindingInitString,
timeout,
validateDialogType,
@ -936,13 +937,18 @@ export class CdpPage extends Page {
override async waitForNetworkIdle(
options: {idleTime?: number; timeout?: number} = {}
): Promise<void> {
const {idleTime = 500, timeout = this._timeoutSettings.timeout()} = options;
const {
idleTime = NETWORK_IDLE_TIME,
timeout: ms = this._timeoutSettings.timeout(),
} = options;
await this._waitForNetworkIdle(
this.#frameManager.networkManager,
idleTime,
timeout,
this.#sessionCloseDeferred
await firstValueFrom(
this._waitForNetworkIdle(
this.#frameManager.networkManager,
idleTime
).pipe(
raceWith(timeout(ms), from(this.#sessionCloseDeferred.valueOrThrow()))
)
);
}

View File

@ -34,7 +34,7 @@ import type {CDPSession} from '../api/CDPSession.js';
import type {Page} from '../api/Page.js';
import {isNode} from '../environment.js';
import {assert} from '../util/assert.js';
import {Deferred} from '../util/Deferred.js';
import type {Deferred} from '../util/Deferred.js';
import {isErrorLike} from '../util/ErrorLike.js';
import {debug} from './Debug.js';
@ -409,22 +409,6 @@ export function pageBindingInitString(type: string, name: string): string {
return evaluationString(addPageBinding, type, name);
}
/**
* @internal
*/
export async function waitWithTimeout<T>(
promise: Promise<T>,
taskName: string,
timeout: number
): Promise<T> {
const deferred = Deferred.create<never>({
message: `waiting for ${taskName} failed: timeout ${timeout}ms exceeded`,
timeout,
});
return await Deferred.race([promise, deferred]);
}
/**
* @internal
*/
@ -633,3 +617,8 @@ export async function waitForHTTP<T extends {url(): string}>(
)
);
}
/**
* @internal
*/
export const NETWORK_IDLE_TIME = 500;

View File

@ -24,6 +24,7 @@ export {
filter,
first,
firstValueFrom,
forkJoin,
from,
fromEvent,
identity,
@ -34,9 +35,7 @@ export {
mergeMap,
NEVER,
noop,
Observable,
of,
OperatorFunction,
pipe,
race,
raceWith,
@ -47,9 +46,10 @@ export {
tap,
throwIfEmpty,
timer,
forkJoin,
} from 'rxjs';
export type * from 'rxjs';
import {filter, from, map, mergeMap, type Observable} from 'rxjs';
export function filterAsync<T>(

View File

@ -155,18 +155,6 @@
"parameters": ["webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[navigation.spec] navigation Frame.goto *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goBack *",
"platforms": ["darwin", "linux", "win32"],
@ -195,7 +183,7 @@
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
"expectations": ["FAIL", "TIMEOUT"]
},
{
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
@ -792,10 +780,10 @@
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",
"testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["PASS"]
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
@ -803,42 +791,12 @@
"parameters": ["firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle0",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle2",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should navigate to page with iframe and networkidle0",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should send referer",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.goto should wait for network idle to succeed navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished",
"platforms": ["darwin", "linux", "win32"],
@ -897,7 +855,7 @@
"testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
"expectations": ["FAIL", "TIMEOUT"]
},
{
"testIdPattern": "[network.spec] network Response.timing returns timing information",
@ -2336,8 +2294,8 @@
{
"testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"]
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",

View File

@ -817,6 +817,7 @@ describe('navigation', function () {
const error = await navigationPromise;
expect(error.message).atLeastOneToContain([
'Navigating frame was detached',
'Frame detached',
'Error: NS_BINDING_ABORTED',
'net::ERR_ABORTED',
]);

View File

@ -21,6 +21,9 @@
"output": [
"bin/**",
"tsconfig.tsbuildinfo"
],
"dependencies": [
"../../packages/puppeteer-core:build"
]
},
"test": {