fix(extension): pass frame loaderId when waiting for navigation commit

handleNavigate's `Page.frameNavigated` handler called
`acceptLifecycleEvent("commit", frameId)` without the frame's loaderId.
Once `Page.navigate` resolves, the loader guard always carries the new
loaderId, so `eventLoaderIsRelevant(undefined, guard)` rejected the
commit event outright.

The navigation still completed in the common case only because the
readyState probe short-circuited first. On cross-origin navigations the
probe returns null (the old execution context has been destroyed), so
the wait fell back to `frameNavigated` — which was then rejected — and
`wait_until="commit"` timed out for the full `timeout_ms` instead of
resolving on commit.

Pass `p.frame?.loaderId` through, matching the sibling `lifecycleEvent`
branches. Adds a regression test that makes the readyState probe fail
and asserts commit is reached from the `frameNavigated` event; it fails
(reached "timeout") on the previous code.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Qiaochu Hu
2026-07-22 15:56:35 +08:00
co-authored by Claude
parent ccf3c32140
commit 063b0bbc91
2 changed files with 43 additions and 5 deletions
+2 -2
View File
@@ -325,14 +325,14 @@ function startLifecycleWait(
if (source.tabId !== expectedTabId) return;
if (targetName === "commit" && method === "Page.frameNavigated") {
const p = params as { frame?: { id?: string; parentId?: string } };
const p = params as { frame?: { id?: string; parentId?: string; loaderId?: string } };
const expectedFrameId = currentFrameId();
if (expectedFrameId.length > 0) {
if (p.frame?.id !== expectedFrameId) return;
} else if (p.frame?.parentId) {
return;
}
if (!acceptLifecycleEvent("commit", p.frame?.id)) return;
if (!acceptLifecycleEvent("commit", p.frame?.id, p.frame?.loaderId)) return;
finish({ reached: "match", lastLifecycle: "commit" });
return;
}