test(app-router): cover consumed prefetch cache handoff - #2758
Conversation
Keep the buffered snapshot discoverable while navigation publishes the committed visited response. This prevents a remounted prefetch-enabled Link from observing a false cache miss and starting a duplicate RSC request.
|
@codex review |
commit: |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Performance benchmarksCompared 0 improved · 0 regressed · 6 within ±1.5%
View detailed results and traces 🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head |
# Conflicts: # packages/vinext/src/server/app-browser-entry.ts
|
/bigbonk review for issues |
There was a problem hiding this comment.
Reviewed the test-only change (+59 lines). This is well-constructed, deterministic regression coverage for the consumed-prefetch → committed-cache handoff race.
Verification done:
- Confirmed the final diff is test-only; the source fix (e5e8047) was superseded by #2760, as the PR body states.
- Confirmed the mechanism under test still exists in current
main:consumedPrefetchSnapshotatapp-browser-entry.ts:1974/2007/2285is exactly what lets navigation publish the buffered snapshot without awaiting the delayedcacheBufferPromise(line 2207/2286). The test deliberately stalls that redundant cache tee viareleaseOldNavigationTail, so a regression that reintroduced theawait cacheBufferPromisedependency would hang the poll at line 335 or surface a duplicate request at line 358 — i.e. the test would fail loudly. Good. - The self-restoring global
ReadableStream.prototype.teeoverride (line 308-329) is safe here: no browser-side code runs between install (page.evaluateat 298) andtargetLink.click()(333), so the firsttee()after install is guaranteed to be the navigation'snavBody.tee()atapp-browser-entry.ts:2200. This matches the existing prototype-patch pattern already used at lines 502-514. vp checkpasses (format, lint, types).
Only minor, non-blocking observations below. These mirror patterns already present in this file, so they are consistency notes rather than defects. No changes required.
| const cacheReader = cacheBranch.getReader(); | ||
| const delayedCacheBranch = new ReadableStream({ | ||
| async start(controller) { | ||
| while (true) { |
There was a problem hiding this comment.
Non-blocking: the while (true) drain loop has no error propagation — if cacheReader.read() rejects, start() rejects, releaseOldNavigationTail is never set, and the poll at line 335 times out rather than failing with a clear message. This is acceptable for a test (it fails loudly either way) and is identical to the existing pattern at lines 462-478 / 598-614, so I'd keep it consistent. Just flagging that a rejected read surfaces as a timeout, not a targeted assertion failure.
| "tee", | ||
| ) as typeof ReadableStream.prototype.tee; | ||
| ReadableStream.prototype.tee = function (this: ReadableStream<unknown>) { | ||
| ReadableStream.prototype.tee = originalTee; |
There was a problem hiding this comment.
Non-blocking: the override self-restores on the first tee() call, so exactly one tee() gets delayed. That's the intended contract here (only the navigation's cache tee at app-browser-entry.ts:2200 should be stalled), and the timing guarantees it fires first. Worth a one-line comment noting the "delay exactly the first post-install tee" intent, since the self-restore is load-bearing and easy to accidentally remove in a future refactor.
|
Review posted successfully to PR #2758. SummaryI reviewed this test-only PR (+59 lines to Verdict: LGTM. This is well-constructed, deterministic regression coverage. Key findings:
Non-blocking notes posted:
No changes required. |
Summary
Why
The original production fix on this branch was superseded by the broader cache-publication work merged in #2760. After merging current
main, the conflict was resolved in favor of that newer implementation, leaving this PR as focused regression coverage for the same race.The test remains useful because it deterministically delays the cache branch that previously created the false-miss window. Current
mainpasses by publishing the already-buffered consumed-prefetch snapshot without waiting for that redundant branch to drain.Upstream parity reference:
test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.tsCloses #2756.
Validation
vp check tests/e2e/app-router/nextjs-compat/client-cache.spec.ts