Adds an internal test utility for e2e testing of requests initiated by
the Next.js Router, such as prefetches and navigations. Calls the given
async function then intercepts any router requests that are initiated as
a result. It will then wait for all the requests to complete before
exiting. Inspired by the React `act` API.
I generally dislike early testing abstractions, but getting all the
details right for intercepting the requests with Playwright ended up
being non-trivial enough that I relented and extracted it to a separate
module, in the `e2e/app-dir/segment-cache` folder. I'll hold off moving
it to somewhere even more generic until it's proven to be useful.
Example:
```js
// Asserts that rendering a link results in a prefetch response that
// contains some expected substring
await act(async () => {
await revealLink()
}, {
includes: 'subset of linked page content'
})
```
A few goals here:
- As much as possible, avoid coupling to internal implementation
details. For example, it will check for the presence of the "rsc" header
to determine if a request was initiated by the router, but that's about
it.
- No timers, no race conditions. It works by intercepting the requests
at the Playwright network layer. There should be no long pauses when
running the tests, and if an assertion fails, it should fail quickly.
- Account for Next.js's internal bandwidth throttling. The router does
not initiate more than a fixed number of requests at a time, so every
time a request is fulfilled, it has the potential to unblock more
prefetches. So we must wait a task to check for additional requests.
This is similar to what React's `act` implementation does to account for
asynchronous rendering tasks.
Implements prefetching support for interception routes using the Segment
Cache.
The overall flow is the same as the previous prefetch cache
implementation. If a page varies based on the Next-URL — in other words,
if it might possibly be intercepted — we include the Next-URL as part of
the cache key. However, since most pages do not vary on the Next-URL,
and this is known at build time, for most pages we can omit the Next-URL
from the cache key for all but the first request.
We do this by checking the Vary header of the first response, and if the
Next-URL is not included, we re-key the cache entry to remove the
Next-URL. All subsequent requests for the same page will match this
entry regardless of the Next-URL.
---
One difference from the previous prefetch cache implementation: when an
entry varies by Next-URL, rather than concatenating the Next-URL to the
href to create a combined cache key, we store the entries in a tiered
map structure whose keys are tuples of the href and Next-URL. Then we
compare each key part separately. This might end up being overkill but
it's nice because we don't have to worry about escaping the values, nor
do we have to store an encoded cache key separately from its individual
parts. We will likely use the same approach for storing segment cache
entries, which vary on both the segment path and (in some cases; not yet
implemented) the search params.