fix: detect scheduled script navigations (#2622)

## Summary

- listen for `Page.frameScheduledNavigation` in addition to
`Page.frameStartedNavigating` while waiting for tool-triggered
navigations
- resolve the navigation probe as soon as the main frame schedules a
document navigation, so `evaluate_script` does not miss script-initiated
navigations on slower platforms
- keep the existing wait window, same-document filtering for started
navigations, and response shape unchanged

Fixes #2609

## Validation

- `npm run format`
- `npm run check-format`
- `npm run test tests/tools/script.test.ts`
- `npm run test tests/utils/WaitForHelper.test.ts`
- `npm run test` was also run. It failed in unrelated local
environment/browser cases:
- extension uninstall timeouts in
extension/service-worker/list_pages/evaluate_script extension tests
- `browser_take_screenshot > with full page resulting in a large
screenshot`: `Protocol error (Page.captureScreenshot): Page is too
large`

## Risk

This only changes the early navigation-detection signal used by
`WaitForHelper`. It does not change navigation timeout values, stable
DOM waiting, dialog handling, iframe filtering, or the final
`navigatedToUrl` response construction. `--browserUrl` and browser
launch behavior are untouched.
This commit is contained in:
Elioooon
2026-09-02 07:40:42 +00:00
committed by GitHub
parent 5463101120
commit 1b2c0e5872
+14 -1
View File
@@ -157,7 +157,7 @@ export class WaitForHelper {
// A scoped AbortController used to clean up navigation probe listeners.
// When aborted (either after navigation detection finishes or if this.#abortController
// aborts), it removes the CDP Page.frameStartedNavigating listener and automatically
// aborts), it removes CDP navigation probe listeners and automatically
// detaches the abort listener from this.#abortController.signal.
const navigationAbortController = new AbortController();
const navigationStartedResolvers = Promise.withResolvers<boolean>();
@@ -177,12 +177,25 @@ export class WaitForHelper {
navigationStartedResolvers.resolve(true);
};
const requestedNavigationListener = (
event: Protocol.Page.FrameRequestedNavigationEvent,
) => {
if (event.frameId === this.#page.mainFrame()._id) {
navigationStartedResolvers.resolve(true);
}
};
this.#page._client().on('Page.frameStartedNavigating', navigationListener);
this.#page
._client()
.on('Page.frameRequestedNavigation', requestedNavigationListener);
navigationAbortController.signal.addEventListener('abort', () => {
this.#page
._client()
.off('Page.frameStartedNavigating', navigationListener);
this.#page
._client()
.off('Page.frameRequestedNavigation', requestedNavigationListener);
});
this.#abortController.signal.addEventListener(
'abort',