mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: use internal method for networkidle with BiDi (#11167)
This commit is contained in:
parent
f0af79a1d6
commit
5278de9276
@ -84,7 +84,6 @@ import type {Viewport} from '../common/Viewport.js';
|
|||||||
import type {ScreenRecorder} from '../node/ScreenRecorder.js';
|
import type {ScreenRecorder} from '../node/ScreenRecorder.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {guarded} from '../util/decorators.js';
|
import {guarded} from '../util/decorators.js';
|
||||||
import type {Deferred} from '../util/Deferred.js';
|
|
||||||
import {
|
import {
|
||||||
AsyncDisposableStack,
|
AsyncDisposableStack,
|
||||||
asyncDisposeSymbol,
|
asyncDisposeSymbol,
|
||||||
@ -1741,36 +1740,32 @@ export abstract class Page extends EventEmitter<PageEvents> {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
protected async _waitForNetworkIdle(
|
_waitForNetworkIdle(
|
||||||
networkManager: BidiNetworkManager | CdpNetworkManager,
|
networkManager: BidiNetworkManager | CdpNetworkManager,
|
||||||
idleTime: number,
|
idleTime: number,
|
||||||
ms: number,
|
requestsInFlight = 0
|
||||||
closedDeferred: Deferred<TargetCloseError>
|
): Observable<void> {
|
||||||
): Promise<void> {
|
return merge(
|
||||||
await firstValueFrom(
|
fromEvent(
|
||||||
merge(
|
networkManager,
|
||||||
fromEvent(
|
NetworkManagerEvent.Request as unknown as string
|
||||||
networkManager,
|
) as Observable<void>,
|
||||||
NetworkManagerEvent.Request as unknown as string
|
fromEvent(
|
||||||
),
|
networkManager,
|
||||||
fromEvent(
|
NetworkManagerEvent.Response as unknown as string
|
||||||
networkManager,
|
) as Observable<void>,
|
||||||
NetworkManagerEvent.Response as unknown as string
|
fromEvent(
|
||||||
),
|
networkManager,
|
||||||
fromEvent(
|
NetworkManagerEvent.RequestFailed as unknown as string
|
||||||
networkManager,
|
) as Observable<void>
|
||||||
NetworkManagerEvent.RequestFailed as unknown as string
|
).pipe(
|
||||||
)
|
startWith(undefined),
|
||||||
).pipe(
|
filter(() => {
|
||||||
startWith(null),
|
return networkManager.inFlightRequestsCount() <= requestsInFlight;
|
||||||
filter(() => {
|
}),
|
||||||
return networkManager.inFlightRequestsCount() === 0;
|
switchMap(v => {
|
||||||
}),
|
return of(v).pipe(delay(idleTime));
|
||||||
switchMap(v => {
|
})
|
||||||
return of(v).pipe(delay(idleTime));
|
|
||||||
}),
|
|
||||||
raceWith(timeout(ms), from(closedDeferred.valueOrThrow()))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,27 +3,14 @@ import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
|
|||||||
|
|
||||||
import {CDPSession} from '../api/CDPSession.js';
|
import {CDPSession} from '../api/CDPSession.js';
|
||||||
import type {Connection as CdpConnection} from '../cdp/Connection.js';
|
import type {Connection as CdpConnection} from '../cdp/Connection.js';
|
||||||
import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js';
|
|
||||||
import {TargetCloseError} from '../common/Errors.js';
|
import {TargetCloseError} from '../common/Errors.js';
|
||||||
import type {EventType} from '../common/EventEmitter.js';
|
import type {EventType} from '../common/EventEmitter.js';
|
||||||
import {debugError} from '../common/util.js';
|
import {debugError} from '../common/util.js';
|
||||||
import {assert} from '../util/assert.js';
|
|
||||||
import {Deferred} from '../util/Deferred.js';
|
import {Deferred} from '../util/Deferred.js';
|
||||||
|
|
||||||
import type {BidiConnection} from './Connection.js';
|
import type {BidiConnection} from './Connection.js';
|
||||||
import {BidiRealm} from './Realm.js';
|
import {BidiRealm} from './Realm.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const lifeCycleToSubscribedEvent = new Map<
|
|
||||||
PuppeteerLifeCycleEvent,
|
|
||||||
string
|
|
||||||
>([
|
|
||||||
['load', 'browsingContext.load'],
|
|
||||||
['domcontentloaded', 'browsingContext.domContentLoaded'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -198,30 +185,3 @@ export class BrowsingContext extends BidiRealm {
|
|||||||
void this.#cdpSession.detach().catch(debugError);
|
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;
|
|
||||||
}
|
|
||||||
|
@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
|
import type {ObservableInput} from '../../third_party/rxjs/rxjs.js';
|
||||||
import {
|
import {
|
||||||
type Observable,
|
type Observable,
|
||||||
firstValueFrom,
|
|
||||||
from,
|
from,
|
||||||
fromEvent,
|
fromEvent,
|
||||||
merge,
|
merge,
|
||||||
raceWith,
|
map,
|
||||||
switchMap,
|
|
||||||
forkJoin,
|
forkJoin,
|
||||||
first,
|
first,
|
||||||
|
firstValueFrom,
|
||||||
|
raceWith,
|
||||||
} from '../../third_party/rxjs/rxjs.js';
|
} from '../../third_party/rxjs/rxjs.js';
|
||||||
import type {CDPSession} from '../api/CDPSession.js';
|
import type {CDPSession} from '../api/CDPSession.js';
|
||||||
import {
|
import {
|
||||||
@ -34,26 +35,26 @@ import {
|
|||||||
type WaitForOptions,
|
type WaitForOptions,
|
||||||
throwIfDetached,
|
throwIfDetached,
|
||||||
} from '../api/Frame.js';
|
} 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 {TimeoutSettings} from '../common/TimeoutSettings.js';
|
||||||
import type {Awaitable} from '../common/types.js';
|
import type {Awaitable} from '../common/types.js';
|
||||||
import {
|
import {
|
||||||
|
NETWORK_IDLE_TIME,
|
||||||
UTILITY_WORLD_NAME,
|
UTILITY_WORLD_NAME,
|
||||||
setPageContent,
|
setPageContent,
|
||||||
waitWithTimeout,
|
timeout,
|
||||||
} from '../common/util.js';
|
} from '../common/util.js';
|
||||||
import {timeout} from '../common/util.js';
|
|
||||||
import {Deferred} from '../util/Deferred.js';
|
import {Deferred} from '../util/Deferred.js';
|
||||||
import {disposeSymbol} from '../util/disposable.js';
|
import {disposeSymbol} from '../util/disposable.js';
|
||||||
|
|
||||||
import {
|
import type {BrowsingContext} from './BrowsingContext.js';
|
||||||
getWaitUntilSingle,
|
|
||||||
lifeCycleToSubscribedEvent,
|
|
||||||
type BrowsingContext,
|
|
||||||
} from './BrowsingContext.js';
|
|
||||||
import {ExposeableFunction} from './ExposedFunction.js';
|
import {ExposeableFunction} from './ExposedFunction.js';
|
||||||
import type {BidiHTTPResponse} from './HTTPResponse.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 type {BidiPage} from './Page.js';
|
||||||
import {
|
import {
|
||||||
MAIN_SANDBOX,
|
MAIN_SANDBOX,
|
||||||
@ -62,17 +63,6 @@ import {
|
|||||||
type SandboxChart,
|
type SandboxChart,
|
||||||
} from './Sandbox.js';
|
} 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
|
* Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation
|
||||||
* @internal
|
* @internal
|
||||||
@ -145,33 +135,25 @@ export class BidiFrame extends Frame {
|
|||||||
): Promise<BidiHTTPResponse | null> {
|
): Promise<BidiHTTPResponse | null> {
|
||||||
const {
|
const {
|
||||||
waitUntil = 'load',
|
waitUntil = 'load',
|
||||||
timeout = this.#timeoutSettings.navigationTimeout(),
|
timeout: ms = this.#timeoutSettings.navigationTimeout(),
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const readinessState = lifeCycleToReadinessState.get(
|
const [readiness, networkIdle] = getBiDiReadinessState(waitUntil);
|
||||||
getWaitUntilSingle(waitUntil)
|
|
||||||
) as Bidi.BrowsingContext.ReadinessState;
|
|
||||||
|
|
||||||
try {
|
const response = await firstValueFrom(
|
||||||
const {result} = await waitWithTimeout(
|
this._waitWithNetworkIdle(
|
||||||
this.#context.connection.send('browsingContext.navigate', {
|
this.#context.connection.send('browsingContext.navigate', {
|
||||||
url: url,
|
context: this.#context.id,
|
||||||
context: this._id,
|
url,
|
||||||
wait: readinessState,
|
wait: readiness,
|
||||||
}),
|
}),
|
||||||
'Navigation',
|
networkIdle
|
||||||
timeout
|
)
|
||||||
);
|
.pipe(raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())))
|
||||||
|
.pipe(rewriteNavigationError(url, ms))
|
||||||
|
);
|
||||||
|
|
||||||
return this.#page.getNavigationResponse(result.navigation);
|
return this.#page.getNavigationResponse(response?.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDetached
|
@throwIfDetached
|
||||||
@ -184,15 +166,22 @@ export class BidiFrame extends Frame {
|
|||||||
timeout: ms = this.#timeoutSettings.navigationTimeout(),
|
timeout: ms = this.#timeoutSettings.navigationTimeout(),
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const waitUntilEvent = lifeCycleToSubscribedEvent.get(
|
const [waitEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil);
|
||||||
getWaitUntilSingle(waitUntil)
|
|
||||||
) as string;
|
|
||||||
|
|
||||||
await firstValueFrom(
|
await firstValueFrom(
|
||||||
forkJoin([
|
this._waitWithNetworkIdle(
|
||||||
fromEvent(this.#context, waitUntilEvent).pipe(first()),
|
forkJoin([
|
||||||
from(setPageContent(this, html)),
|
fromEvent(this.#context, waitEvent).pipe(first()),
|
||||||
]).pipe(raceWith(timeout(ms)))
|
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(),
|
timeout: ms = this.#timeoutSettings.navigationTimeout(),
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const waitUntilEvent = lifeCycleToSubscribedEvent.get(
|
const [waitUntilEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil);
|
||||||
getWaitUntilSingle(waitUntil)
|
|
||||||
) as string;
|
|
||||||
|
|
||||||
const info = await firstValueFrom(
|
const navigatedObservable = merge(
|
||||||
merge(
|
forkJoin([
|
||||||
fromEvent(
|
fromEvent(
|
||||||
this.#context,
|
this.#context,
|
||||||
Bidi.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted
|
Bidi.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted
|
||||||
).pipe(
|
).pipe(first()),
|
||||||
switchMap(() => {
|
fromEvent(this.#context, waitUntilEvent).pipe(
|
||||||
return fromEvent(
|
first()
|
||||||
this.#context,
|
) as Observable<Bidi.BrowsingContext.NavigationInfo>,
|
||||||
waitUntilEvent
|
]),
|
||||||
) as Observable<Bidi.BrowsingContext.NavigationInfo>;
|
fromEvent(
|
||||||
})
|
this.#context,
|
||||||
),
|
Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated
|
||||||
fromEvent(
|
) as Observable<Bidi.BrowsingContext.NavigationInfo>
|
||||||
this.#context,
|
).pipe(
|
||||||
Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated
|
map(result => {
|
||||||
) as Observable<Bidi.BrowsingContext.NavigationInfo>
|
if (Array.isArray(result)) {
|
||||||
).pipe(raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())))
|
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 {
|
override get detached(): boolean {
|
||||||
@ -270,4 +266,31 @@ export class BidiFrame extends Frame {
|
|||||||
throw error;
|
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;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ export class BidiNetworkManager extends EventEmitter<NetworkManagerEvents> {
|
|||||||
this.#requestMap.delete(event.request.request);
|
this.#requestMap.delete(event.request.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
getNavigationResponse(navigationId: string | null): BidiHTTPResponse | null {
|
getNavigationResponse(navigationId?: string | null): BidiHTTPResponse | null {
|
||||||
if (!navigationId) {
|
if (!navigationId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,7 @@ import {
|
|||||||
ConsoleMessage,
|
ConsoleMessage,
|
||||||
type ConsoleMessageLocation,
|
type ConsoleMessageLocation,
|
||||||
} from '../common/ConsoleMessage.js';
|
} from '../common/ConsoleMessage.js';
|
||||||
import {
|
import {TargetCloseError} from '../common/Errors.js';
|
||||||
ProtocolError,
|
|
||||||
TargetCloseError,
|
|
||||||
TimeoutError,
|
|
||||||
} from '../common/Errors.js';
|
|
||||||
import type {Handler} from '../common/EventEmitter.js';
|
import type {Handler} from '../common/EventEmitter.js';
|
||||||
import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js';
|
import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js';
|
||||||
import type {PDFOptions} from '../common/PDFOptions.js';
|
import type {PDFOptions} from '../common/PDFOptions.js';
|
||||||
@ -51,10 +47,10 @@ import type {Awaitable} from '../common/types.js';
|
|||||||
import {
|
import {
|
||||||
debugError,
|
debugError,
|
||||||
evaluationString,
|
evaluationString,
|
||||||
|
NETWORK_IDLE_TIME,
|
||||||
timeout,
|
timeout,
|
||||||
validateDialogType,
|
validateDialogType,
|
||||||
waitForHTTP,
|
waitForHTTP,
|
||||||
waitWithTimeout,
|
|
||||||
} from '../common/util.js';
|
} from '../common/util.js';
|
||||||
import type {Viewport} from '../common/Viewport.js';
|
import type {Viewport} from '../common/Viewport.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
@ -66,7 +62,6 @@ import type {BidiBrowserContext} from './BrowserContext.js';
|
|||||||
import {
|
import {
|
||||||
BrowsingContextEvent,
|
BrowsingContextEvent,
|
||||||
CdpSessionWrapper,
|
CdpSessionWrapper,
|
||||||
getWaitUntilSingle,
|
|
||||||
type BrowsingContext,
|
type BrowsingContext,
|
||||||
} from './BrowsingContext.js';
|
} from './BrowsingContext.js';
|
||||||
import type {BidiConnection} from './Connection.js';
|
import type {BidiConnection} from './Connection.js';
|
||||||
@ -74,11 +69,12 @@ import {BidiDeserializer} from './Deserializer.js';
|
|||||||
import {BidiDialog} from './Dialog.js';
|
import {BidiDialog} from './Dialog.js';
|
||||||
import {BidiElementHandle} from './ElementHandle.js';
|
import {BidiElementHandle} from './ElementHandle.js';
|
||||||
import {EmulationManager} from './EmulationManager.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 {BidiHTTPRequest} from './HTTPRequest.js';
|
||||||
import type {BidiHTTPResponse} from './HTTPResponse.js';
|
import type {BidiHTTPResponse} from './HTTPResponse.js';
|
||||||
import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js';
|
import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js';
|
||||||
import type {BidiJSHandle} from './JSHandle.js';
|
import type {BidiJSHandle} from './JSHandle.js';
|
||||||
|
import {getBiDiReadinessState, rewriteNavigationError} from './lifecycle.js';
|
||||||
import {BidiNetworkManager} from './NetworkManager.js';
|
import {BidiNetworkManager} from './NetworkManager.js';
|
||||||
import {createBidiHandle} from './Realm.js';
|
import {createBidiHandle} from './Realm.js';
|
||||||
|
|
||||||
@ -89,7 +85,7 @@ export class BidiPage extends Page {
|
|||||||
#accessibility: Accessibility;
|
#accessibility: Accessibility;
|
||||||
#connection: BidiConnection;
|
#connection: BidiConnection;
|
||||||
#frameTree = new FrameTree<BidiFrame>();
|
#frameTree = new FrameTree<BidiFrame>();
|
||||||
#networkManager: BidiNetworkManager;
|
_networkManager: BidiNetworkManager;
|
||||||
#viewport: Viewport | null = null;
|
#viewport: Viewport | null = null;
|
||||||
#closedDeferred = Deferred.create<never, TargetCloseError>();
|
#closedDeferred = Deferred.create<never, TargetCloseError>();
|
||||||
#subscribedEvents = new Map<Bidi.Event['method'], Handler<any>>([
|
#subscribedEvents = new Map<Bidi.Event['method'], Handler<any>>([
|
||||||
@ -169,7 +165,7 @@ export class BidiPage extends Page {
|
|||||||
this.#browsingContext.on(event, subscriber);
|
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) {
|
for (const [event, subscriber] of this.#subscribedEvents) {
|
||||||
this.#connection.on(event, subscriber);
|
this.#connection.on(event, subscriber);
|
||||||
@ -177,7 +173,7 @@ export class BidiPage extends Page {
|
|||||||
|
|
||||||
for (const [event, subscriber] of this.#networkManagerEvents) {
|
for (const [event, subscriber] of this.#networkManagerEvents) {
|
||||||
// TODO: remove any
|
// TODO: remove any
|
||||||
this.#networkManager.on(event, subscriber as any);
|
this._networkManager.on(event, subscriber as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
const frame = new BidiFrame(
|
const frame = new BidiFrame(
|
||||||
@ -381,7 +377,7 @@ export class BidiPage extends Page {
|
|||||||
this.#removeFramesRecursively(child);
|
this.#removeFramesRecursively(child);
|
||||||
}
|
}
|
||||||
frame[disposeSymbol]();
|
frame[disposeSymbol]();
|
||||||
this.#networkManager.clearMapAfterFrameDispose(frame);
|
this._networkManager.clearMapAfterFrameDispose(frame);
|
||||||
this.#frameTree.removeFrame(frame);
|
this.#frameTree.removeFrame(frame);
|
||||||
this.emit(PageEvent.FrameDetached, frame);
|
this.emit(PageEvent.FrameDetached, frame);
|
||||||
}
|
}
|
||||||
@ -460,8 +456,8 @@ export class BidiPage extends Page {
|
|||||||
this.emit(PageEvent.Dialog, dialog);
|
this.emit(PageEvent.Dialog, dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
getNavigationResponse(id: string | null): BidiHTTPResponse | null {
|
getNavigationResponse(id?: string | null): BidiHTTPResponse | null {
|
||||||
return this.#networkManager.getNavigationResponse(id);
|
return this._networkManager.getNavigationResponse(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
override isClosed(): boolean {
|
override isClosed(): boolean {
|
||||||
@ -474,7 +470,7 @@ export class BidiPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.#closedDeferred.reject(new TargetCloseError('Page closed!'));
|
this.#closedDeferred.reject(new TargetCloseError('Page closed!'));
|
||||||
this.#networkManager.dispose();
|
this._networkManager.dispose();
|
||||||
|
|
||||||
await this.#connection.send('browsingContext.close', {
|
await this.#connection.send('browsingContext.close', {
|
||||||
context: this.mainFrame()._id,
|
context: this.mainFrame()._id,
|
||||||
@ -489,32 +485,25 @@ export class BidiPage extends Page {
|
|||||||
): Promise<BidiHTTPResponse | null> {
|
): Promise<BidiHTTPResponse | null> {
|
||||||
const {
|
const {
|
||||||
waitUntil = 'load',
|
waitUntil = 'load',
|
||||||
timeout = this._timeoutSettings.navigationTimeout(),
|
timeout: ms = this._timeoutSettings.navigationTimeout(),
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const readinessState = lifeCycleToReadinessState.get(
|
const [readiness, networkIdle] = getBiDiReadinessState(waitUntil);
|
||||||
getWaitUntilSingle(waitUntil)
|
|
||||||
) as Bidi.BrowsingContext.ReadinessState;
|
|
||||||
|
|
||||||
try {
|
const response = await firstValueFrom(
|
||||||
const {result} = await waitWithTimeout(
|
this.mainFrame()
|
||||||
this.#connection.send('browsingContext.reload', {
|
._waitWithNetworkIdle(
|
||||||
context: this.mainFrame()._id,
|
this.#connection.send('browsingContext.reload', {
|
||||||
wait: readinessState,
|
context: this.mainFrame()._id,
|
||||||
}),
|
wait: readiness,
|
||||||
'Navigation',
|
}),
|
||||||
timeout
|
networkIdle
|
||||||
);
|
)
|
||||||
|
.pipe(raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow())))
|
||||||
|
.pipe(rewriteNavigationError(this.url(), ms))
|
||||||
|
);
|
||||||
|
|
||||||
return this.getNavigationResponse(result.navigation);
|
return this.getNavigationResponse(response?.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override setDefaultNavigationTimeout(timeout: number): void {
|
override setDefaultNavigationTimeout(timeout: number): void {
|
||||||
@ -692,7 +681,7 @@ export class BidiPage extends Page {
|
|||||||
): Promise<BidiHTTPRequest> {
|
): Promise<BidiHTTPRequest> {
|
||||||
const {timeout = this._timeoutSettings.timeout()} = options;
|
const {timeout = this._timeoutSettings.timeout()} = options;
|
||||||
return await waitForHTTP(
|
return await waitForHTTP(
|
||||||
this.#networkManager,
|
this._networkManager,
|
||||||
NetworkManagerEvent.Request,
|
NetworkManagerEvent.Request,
|
||||||
urlOrPredicate,
|
urlOrPredicate,
|
||||||
timeout,
|
timeout,
|
||||||
@ -708,7 +697,7 @@ export class BidiPage extends Page {
|
|||||||
): Promise<BidiHTTPResponse> {
|
): Promise<BidiHTTPResponse> {
|
||||||
const {timeout = this._timeoutSettings.timeout()} = options;
|
const {timeout = this._timeoutSettings.timeout()} = options;
|
||||||
return await waitForHTTP(
|
return await waitForHTTP(
|
||||||
this.#networkManager,
|
this._networkManager,
|
||||||
NetworkManagerEvent.Response,
|
NetworkManagerEvent.Response,
|
||||||
urlOrPredicate,
|
urlOrPredicate,
|
||||||
timeout,
|
timeout,
|
||||||
@ -719,13 +708,15 @@ export class BidiPage extends Page {
|
|||||||
override async waitForNetworkIdle(
|
override async waitForNetworkIdle(
|
||||||
options: {idleTime?: number; timeout?: number} = {}
|
options: {idleTime?: number; timeout?: number} = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {idleTime = 500, timeout = this._timeoutSettings.timeout()} = options;
|
const {
|
||||||
|
idleTime = NETWORK_IDLE_TIME,
|
||||||
|
timeout: ms = this._timeoutSettings.timeout(),
|
||||||
|
} = options;
|
||||||
|
|
||||||
await this._waitForNetworkIdle(
|
await firstValueFrom(
|
||||||
this.#networkManager,
|
this._waitForNetworkIdle(this._networkManager, idleTime).pipe(
|
||||||
idleTime,
|
raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow()))
|
||||||
timeout,
|
)
|
||||||
this.#closedDeferred
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
120
packages/puppeteer-core/src/bidi/lifecycle.ts
Normal file
120
packages/puppeteer-core/src/bidi/lifecycle.ts
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
@ -53,6 +53,7 @@ import {
|
|||||||
evaluationString,
|
evaluationString,
|
||||||
getReadableAsBuffer,
|
getReadableAsBuffer,
|
||||||
getReadableFromProtocolStream,
|
getReadableFromProtocolStream,
|
||||||
|
NETWORK_IDLE_TIME,
|
||||||
pageBindingInitString,
|
pageBindingInitString,
|
||||||
timeout,
|
timeout,
|
||||||
validateDialogType,
|
validateDialogType,
|
||||||
@ -936,13 +937,18 @@ export class CdpPage extends Page {
|
|||||||
override async waitForNetworkIdle(
|
override async waitForNetworkIdle(
|
||||||
options: {idleTime?: number; timeout?: number} = {}
|
options: {idleTime?: number; timeout?: number} = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {idleTime = 500, timeout = this._timeoutSettings.timeout()} = options;
|
const {
|
||||||
|
idleTime = NETWORK_IDLE_TIME,
|
||||||
|
timeout: ms = this._timeoutSettings.timeout(),
|
||||||
|
} = options;
|
||||||
|
|
||||||
await this._waitForNetworkIdle(
|
await firstValueFrom(
|
||||||
this.#frameManager.networkManager,
|
this._waitForNetworkIdle(
|
||||||
idleTime,
|
this.#frameManager.networkManager,
|
||||||
timeout,
|
idleTime
|
||||||
this.#sessionCloseDeferred
|
).pipe(
|
||||||
|
raceWith(timeout(ms), from(this.#sessionCloseDeferred.valueOrThrow()))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import type {CDPSession} from '../api/CDPSession.js';
|
|||||||
import type {Page} from '../api/Page.js';
|
import type {Page} from '../api/Page.js';
|
||||||
import {isNode} from '../environment.js';
|
import {isNode} from '../environment.js';
|
||||||
import {assert} from '../util/assert.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 {isErrorLike} from '../util/ErrorLike.js';
|
||||||
|
|
||||||
import {debug} from './Debug.js';
|
import {debug} from './Debug.js';
|
||||||
@ -409,22 +409,6 @@ export function pageBindingInitString(type: string, name: string): string {
|
|||||||
return evaluationString(addPageBinding, type, name);
|
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
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -633,3 +617,8 @@ export async function waitForHTTP<T extends {url(): string}>(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const NETWORK_IDLE_TIME = 500;
|
||||||
|
@ -24,6 +24,7 @@ export {
|
|||||||
filter,
|
filter,
|
||||||
first,
|
first,
|
||||||
firstValueFrom,
|
firstValueFrom,
|
||||||
|
forkJoin,
|
||||||
from,
|
from,
|
||||||
fromEvent,
|
fromEvent,
|
||||||
identity,
|
identity,
|
||||||
@ -34,9 +35,7 @@ export {
|
|||||||
mergeMap,
|
mergeMap,
|
||||||
NEVER,
|
NEVER,
|
||||||
noop,
|
noop,
|
||||||
Observable,
|
|
||||||
of,
|
of,
|
||||||
OperatorFunction,
|
|
||||||
pipe,
|
pipe,
|
||||||
race,
|
race,
|
||||||
raceWith,
|
raceWith,
|
||||||
@ -47,9 +46,10 @@ export {
|
|||||||
tap,
|
tap,
|
||||||
throwIfEmpty,
|
throwIfEmpty,
|
||||||
timer,
|
timer,
|
||||||
forkJoin,
|
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
|
|
||||||
|
export type * from 'rxjs';
|
||||||
|
|
||||||
import {filter, from, map, mergeMap, type Observable} from 'rxjs';
|
import {filter, from, map, mergeMap, type Observable} from 'rxjs';
|
||||||
|
|
||||||
export function filterAsync<T>(
|
export function filterAsync<T>(
|
||||||
|
@ -155,18 +155,6 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"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 *",
|
"testIdPattern": "[navigation.spec] navigation Page.goBack *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -195,7 +183,7 @@
|
|||||||
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
||||||
@ -792,10 +780,10 @@
|
|||||||
"expectations": ["FAIL"]
|
"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"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
|
"testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
|
||||||
@ -803,42 +791,12 @@
|
|||||||
"parameters": ["firefox"],
|
"parameters": ["firefox"],
|
||||||
"expectations": ["FAIL"]
|
"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",
|
"testIdPattern": "[navigation.spec] navigation Page.goto should send referer",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"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",
|
"testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -897,7 +855,7 @@
|
|||||||
"testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker",
|
"testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network Response.timing returns timing information",
|
"testIdPattern": "[network.spec] network Response.timing returns timing information",
|
||||||
@ -2336,8 +2294,8 @@
|
|||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes",
|
"testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",
|
"testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",
|
||||||
|
@ -817,6 +817,7 @@ describe('navigation', function () {
|
|||||||
const error = await navigationPromise;
|
const error = await navigationPromise;
|
||||||
expect(error.message).atLeastOneToContain([
|
expect(error.message).atLeastOneToContain([
|
||||||
'Navigating frame was detached',
|
'Navigating frame was detached',
|
||||||
|
'Frame detached',
|
||||||
'Error: NS_BINDING_ABORTED',
|
'Error: NS_BINDING_ABORTED',
|
||||||
'net::ERR_ABORTED',
|
'net::ERR_ABORTED',
|
||||||
]);
|
]);
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
"output": [
|
"output": [
|
||||||
"bin/**",
|
"bin/**",
|
||||||
"tsconfig.tsbuildinfo"
|
"tsconfig.tsbuildinfo"
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
"../../packages/puppeteer-core:build"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
|
Loading…
Reference in New Issue
Block a user