test: de-flake client-cache deployment tests (#87412)

These tests aren't resilient to changes in router behavior after
extensive refactors. What looks to be happening is a race between the
prefetch being issued and the click firing:
1. Cache expires -> refetch prefetch is triggered
2. Click happens while prefetch is in-flight -> route entry is Pending
3. Since no fulfilled cache entry exists, `navigate()` falls through to
`navigateDynamicallyWithNoPrefetch()`
4. This issues a full dynamic request
5. The full dynamic response is favored and skips the loading state

This ensures that we are waiting for network activity to finish before
navigating.
This commit is contained in:
Zack Tanner
2025-12-19 11:08:10 -08:00
committed by GitHub
parent 71f9a8c65c
commit c95eb899fa
3 changed files with 38 additions and 2 deletions
@@ -268,6 +268,9 @@ describe('app dir client cache semantics (default semantics)', () => {
})
it('should refetch the full page after 5 mins', async () => {
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
const randomLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
@@ -285,6 +288,10 @@ describe('app dir client cache semantics (default semantics)', () => {
.click()
.waitForElementByCss('[href="/1?timeout=1000"]')
// Wait for prefetch requests to complete before clicking, otherwise
// clicking during an in-flight prefetch aborts it and skips loading state
await browser.waitForIdleNetwork()
const newLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
@@ -20,6 +20,9 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
it('should trigger a loading state before fetching the page, followed by fresh data on every subsequent navigation', async () => {
const browser = await next.browser('/', browserConfigWithFixedTime)
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
// this test introduces an artificial delay in rendering the requested page, so we verify a loading state is rendered
await browser
.elementByCss('[href="/1?timeout=1000"]')
@@ -124,6 +127,9 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
it('should trigger a loading state before fetching the page, followed by fresh data on every subsequent navigation', async () => {
const browser = await next.browser('/', browserConfigWithFixedTime)
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
// this test introduces an artificial delay in rendering the requested page, so we verify a loading state is rendered
await browser
.elementByCss('[href="/2?timeout=1000"]')
@@ -176,6 +182,9 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
it('should trigger a loading state before fetching the page, followed by fresh data on every subsequent navigation', async () => {
const browser = await next.browser('/', browserConfigWithFixedTime)
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
// this test introduces an artificial delay in rendering the requested page, so we verify a loading state is rendered
await browser
.elementByCss('[href="/1?timeout=1000"]')
@@ -317,15 +326,21 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
it('should re-use the loading boundary for the custom static override time (3 minutes)', async () => {
const browser = await next.browser('/', browserConfigWithFixedTime)
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
const loadingRandomNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
.waitForElementByCss('#loading')
.text()
await browser.eval(fastForwardTo, 2 * 60 * 1000) // fast forward 2 minutes
await browser.elementByCss('[href="/"]').click()
await browser.eval(fastForwardTo, 2 * 60 * 1000) // fast forward 2 minutes
await browser.waitForElementByCss('[href="/1?timeout=1000"]')
await browser.waitForIdleNetwork()
let newLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
@@ -335,9 +350,13 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
expect(loadingRandomNumber).toBe(newLoadingNumber)
await browser.eval(fastForwardTo, 2 * 60 * 1000) // fast forward 2 minutes
await browser.elementByCss('[href="/"]').click()
await browser.eval(fastForwardTo, 2 * 60 * 1000) // fast forward 2 minutes
// Wait for link to be visible (triggers prefetch), then wait for prefetch to complete
await browser.waitForElementByCss('[href="/1?timeout=1000"]')
await browser.waitForIdleNetwork()
newLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
@@ -384,6 +403,9 @@ describe('app dir client cache semantics (experimental staleTimes)', () => {
it('should trigger a loading state before fetching the page, followed by fresh data on every subsequent navigation', async () => {
const browser = await next.browser('/', browserConfigWithFixedTime)
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
// this test introduces an artificial delay in rendering the requested page, so we verify a loading state is rendered
await browser
.elementByCss('[href="/1?timeout=1000"]')
@@ -360,6 +360,9 @@ describe('app dir client cache semantics (30s/5min)', () => {
expect(newNumber).not.toBe(randomNumber)
})
it('should refetch the full page after 5 mins', async () => {
// Wait for initial prefetch to complete before clicking
await browser.waitForIdleNetwork()
const randomLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
@@ -377,6 +380,10 @@ describe('app dir client cache semantics (30s/5min)', () => {
.click()
.waitForElementByCss('[href="/1?timeout=1000"]')
// Wait for prefetch requests to complete before clicking, otherwise
// clicking during an in-flight prefetch aborts it and skips loading state
await browser.waitForIdleNetwork()
const newLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()