Add `prefetch: 'app-shell'` option to the instant() navigation testing helper
By default, instant() simulates a fully warm cache: navigations render
everything the link would have prefetched, including per-link and
runtime-prefetched data. This adds a way to assert on just the route's
App Shell:
await instant(page, fn, { prefetch: 'app-shell' })
The option is carried on the instant cookie's pending value and preserved
on captured values, so it survives MPA page loads within a scope. While
active:
- every prefetch task stops before the Speculative phase — the locked
navigation's own prefetch as well as incidental link prefetches (e.g.
the hover-intent reschedule triggered by clicking a link) — so no
per-link concrete-param or runtime-prefetch data is fetched during the
scope, and
- navigation reads are restricted to shell entries regardless of the
link's own fetch strategy (e.g. prefetch={true}).
Cookie parsers now discriminate pending vs. captured values by the first
element instead of array length, since pending values can carry options.
The e2e coverage uses a fixture modeled on the standard App Shell example
from the Runtime Prefetching guide (cacheComponents + partialPrefetching,
a /courses route mixing static, 'use cache', session-cookie, searchParams,
and uncached-per-request content behind an allow-runtime + prefetch={true}
link). The tests assert each content kind lands in its documented bucket:
the session-personalized App Shell renders instantly (including the
cookie-derived badge), per-link searchParams data shows its fallback and
is deferred, and the scope's network traffic contains the App Shell
prefetch ('3') but no per-link runtime prefetch ('2').