Skip to content

Commit 0ccea28

Browse files
committed
test: refactor app router on-demand revalidation test and add test cases for not prerendered content
1 parent f4eeaa2 commit 0ccea28

File tree

4 files changed

+142
-233
lines changed

4 files changed

+142
-233
lines changed

tests/e2e/on-demand-app.test.ts

+129-230
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,89 @@ import { expect } from '@playwright/test'
22
import { test } from '../utils/playwright-helpers.js'
33

44
test.describe('app router on-demand revalidation', () => {
5-
test('revalidatePath', async ({ page, pollUntilHeadersMatch, serverComponents }) => {
6-
// in case there is retry or some other test did hit that path before
7-
// we want to make sure that cdn cache is not warmed up
8-
const purgeCdnCache = await page.goto(
9-
new URL('/api/purge-cdn?path=/static-fetch/1', serverComponents.url).href,
10-
)
11-
expect(purgeCdnCache?.status()).toBe(200)
12-
13-
// wait a bit until cdn cache purge propagates
14-
await page.waitForTimeout(500)
15-
16-
const response1 = await pollUntilHeadersMatch(
17-
new URL('static-fetch/1', serverComponents.url).href,
18-
{
5+
for (const { label, prerendered, pagePath, revalidateApiPath, expectedH1Content } of [
6+
{
7+
label: 'revalidatePath (prerendered page with static path)',
8+
prerendered: true,
9+
pagePath: '/static-fetch-1',
10+
revalidateApiPath: '/api/on-demand-revalidate/path?path=/static-fetch-1',
11+
expectedH1Content: 'Hello, Static Fetch 1',
12+
},
13+
{
14+
label: 'revalidateTag (prerendered page with static path)',
15+
prerendered: true,
16+
pagePath: '/static-fetch-2',
17+
revalidateApiPath: '/api/on-demand-revalidate/tag?tag=collection',
18+
expectedH1Content: 'Hello, Static Fetch 2',
19+
},
20+
{
21+
label: 'revalidatePath (prerendered page with dynamic path)',
22+
prerendered: true,
23+
pagePath: '/static-fetch/1',
24+
revalidateApiPath: '/api/on-demand-revalidate/path?path=/static-fetch/1',
25+
expectedH1Content: 'Hello, Statically fetched show 1',
26+
},
27+
{
28+
label: 'revalidateTag (prerendered page with dynamic path)',
29+
prerendered: true,
30+
pagePath: '/static-fetch/2',
31+
revalidateApiPath: '/api/on-demand-revalidate/tag?tag=show-2',
32+
expectedH1Content: 'Hello, Statically fetched show 2',
33+
},
34+
{
35+
label: 'revalidatePath (not prerendered page with dynamic path)',
36+
prerendered: false,
37+
pagePath: '/static-fetch/3',
38+
revalidateApiPath: '/api/on-demand-revalidate/path?path=/static-fetch/3',
39+
expectedH1Content: 'Hello, Statically fetched show 3',
40+
},
41+
{
42+
label: 'revalidateTag (not prerendered page with dynamic path)',
43+
prerendered: false,
44+
pagePath: '/static-fetch/4',
45+
revalidateApiPath: '/api/on-demand-revalidate/tag?tag=show-4',
46+
expectedH1Content: 'Hello, Statically fetched show 4',
47+
},
48+
]) {
49+
test(label, async ({ page, pollUntilHeadersMatch, serverComponents }) => {
50+
// in case there is retry or some other test did hit that path before
51+
// we want to make sure that cdn cache is not warmed up
52+
const purgeCdnCache = await page.goto(
53+
new URL(`/api/purge-cdn?path=${pagePath}`, serverComponents.url).href,
54+
)
55+
expect(purgeCdnCache?.status()).toBe(200)
56+
57+
// wait a bit until cdn cache purge propagates
58+
await page.waitForTimeout(500)
59+
60+
const response1 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
1961
headersToMatch: {
2062
// either first time hitting this route or we invalidated
2163
// just CDN node in earlier step
22-
// we will invoke function and see Next cache hit status \
23-
// in the response because it was prerendered at build time
64+
// we will invoke function and see Next cache hit status
65+
// in the response if it was prerendered at build time
2466
// or regenerated in previous attempt to run this test
25-
'cache-status': [/"Netlify Edge"; fwd=(miss|stale)/m, /"Next.js"; hit/m],
67+
'cache-status': [
68+
/"Netlify Edge"; fwd=(miss|stale)/m,
69+
prerendered ? /"Next.js"; hit/m : /"Next.js"; (hit|fwd=miss)/m,
70+
],
2671
},
2772
headersNotMatchedMessage:
2873
'First request to tested page should be a miss or stale on the Edge and hit in Next.js',
29-
},
30-
)
31-
const headers1 = response1?.headers() || {}
32-
expect(response1?.status()).toBe(200)
33-
expect(headers1['x-nextjs-cache']).toBeUndefined()
34-
expect(headers1['netlify-cdn-cache-control']).toBe(
35-
's-maxage=31536000, stale-while-revalidate=31536000',
36-
)
74+
})
75+
const headers1 = response1?.headers() || {}
76+
expect(response1?.status()).toBe(200)
77+
expect(headers1['x-nextjs-cache']).toBeUndefined()
78+
expect(headers1['netlify-cdn-cache-control']).toBe(
79+
's-maxage=31536000, stale-while-revalidate=31536000',
80+
)
3781

38-
const date1 = await page.textContent('[data-testid="date-now"]')
82+
const date1 = await page.textContent('[data-testid="date-now"]')
3983

40-
const h1 = await page.textContent('h1')
41-
expect(h1).toBe('Hello, Statically fetched show 1')
84+
const h1 = await page.textContent('h1')
85+
expect(h1).toBe(expectedH1Content)
4286

43-
const response2 = await pollUntilHeadersMatch(
44-
new URL('static-fetch/1', serverComponents.url).href,
45-
{
87+
const response2 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
4688
headersToMatch: {
4789
// we are hitting the same page again and we most likely will see
4890
// CDN hit (in this case Next reported cache status is omitted
@@ -52,36 +94,31 @@ test.describe('app router on-demand revalidation', () => {
5294
},
5395
headersNotMatchedMessage:
5496
'Second request to tested page should most likely be a hit on the Edge (optionally miss or stale if different CDN node)',
55-
},
56-
)
57-
const headers2 = response2?.headers() || {}
58-
expect(response2?.status()).toBe(200)
59-
expect(headers2['x-nextjs-cache']).toBeUndefined()
60-
if (!headers2['cache-status'].includes('"Netlify Edge"; hit')) {
61-
// if we missed CDN cache, we will see Next cache hit status
62-
// as we reuse cached response
63-
expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m)
64-
}
65-
expect(headers2['netlify-cdn-cache-control']).toBe(
66-
's-maxage=31536000, stale-while-revalidate=31536000',
67-
)
68-
69-
// the page is cached
70-
const date2 = await page.textContent('[data-testid="date-now"]')
71-
expect(date2).toBe(date1)
72-
73-
const revalidate = await page.goto(
74-
new URL('/api/on-demand-revalidate/path', serverComponents.url).href,
75-
)
76-
expect(revalidate?.status()).toBe(200)
77-
78-
// wait a bit until cdn tags and invalidated and cdn is purged
79-
await page.waitForTimeout(500)
80-
81-
// now after the revalidation it should have a different date
82-
const response3 = await pollUntilHeadersMatch(
83-
new URL('static-fetch/1', serverComponents.url).href,
84-
{
97+
})
98+
const headers2 = response2?.headers() || {}
99+
expect(response2?.status()).toBe(200)
100+
expect(headers2['x-nextjs-cache']).toBeUndefined()
101+
if (!headers2['cache-status'].includes('"Netlify Edge"; hit')) {
102+
// if we missed CDN cache, we will see Next cache hit status
103+
// as we reuse cached response
104+
expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m)
105+
}
106+
expect(headers2['netlify-cdn-cache-control']).toBe(
107+
's-maxage=31536000, stale-while-revalidate=31536000',
108+
)
109+
110+
// the page is cached
111+
const date2 = await page.textContent('[data-testid="date-now"]')
112+
expect(date2).toBe(date1)
113+
114+
const revalidate = await page.goto(new URL(revalidateApiPath, serverComponents.url).href)
115+
expect(revalidate?.status()).toBe(200)
116+
117+
// wait a bit until cdn tags and invalidated and cdn is purged
118+
await page.waitForTimeout(500)
119+
120+
// now after the revalidation it should have a different date
121+
const response3 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
85122
headersToMatch: {
86123
// revalidatePath just marks the page(s) as invalid and does NOT
87124
// automatically refreshes the cache. This request will cause
@@ -92,22 +129,19 @@ test.describe('app router on-demand revalidation', () => {
92129
},
93130
headersNotMatchedMessage:
94131
'Third request to tested page should be a miss or stale on the Edge and miss in Next.js after on-demand revalidation',
95-
},
96-
)
97-
const headers3 = response3?.headers() || {}
98-
expect(response3?.status()).toBe(200)
99-
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
100-
expect(headers3['netlify-cdn-cache-control']).toBe(
101-
's-maxage=31536000, stale-while-revalidate=31536000',
102-
)
103-
104-
// the page has now an updated date
105-
const date3 = await page.textContent('[data-testid="date-now"]')
106-
expect(date3).not.toBe(date2)
107-
108-
const response4 = await pollUntilHeadersMatch(
109-
new URL('static-fetch/1', serverComponents.url).href,
110-
{
132+
})
133+
const headers3 = response3?.headers() || {}
134+
expect(response3?.status()).toBe(200)
135+
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
136+
expect(headers3['netlify-cdn-cache-control']).toBe(
137+
's-maxage=31536000, stale-while-revalidate=31536000',
138+
)
139+
140+
// the page has now an updated date
141+
const date3 = await page.textContent('[data-testid="date-now"]')
142+
expect(date3).not.toBe(date2)
143+
144+
const response4 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
111145
headersToMatch: {
112146
// we are hitting the same page again and we most likely will see
113147
// CDN hit (in this case Next reported cache status is omitted
@@ -117,157 +151,22 @@ test.describe('app router on-demand revalidation', () => {
117151
},
118152
headersNotMatchedMessage:
119153
'Fourth request to tested page should most likely be a hit on the Edge (optionally miss or stale if different CDN node)',
120-
},
121-
)
122-
const headers4 = response4?.headers() || {}
123-
expect(response4?.status()).toBe(200)
124-
expect(headers4?.['x-nextjs-cache']).toBeUndefined()
125-
if (!headers4['cache-status'].includes('"Netlify Edge"; hit')) {
126-
// if we missed CDN cache, we will see Next cache hit status
127-
// as we reuse cached response
128-
expect(headers4['cache-status']).toMatch(/"Next.js"; hit/m)
129-
}
130-
expect(headers4['netlify-cdn-cache-control']).toBe(
131-
's-maxage=31536000, stale-while-revalidate=31536000',
132-
)
133-
134-
// the page is cached
135-
const date4 = await page.textContent('[data-testid="date-now"]')
136-
expect(date4).toBe(date3)
137-
})
138-
139-
test('revalidateTag', async ({ page, pollUntilHeadersMatch, serverComponents }) => {
140-
// in case there is retry or some other test did hit that path before
141-
// we want to make sure that cdn cache is not warmed up
142-
const purgeCdnCache = await page.goto(
143-
new URL('/api/purge-cdn?path=/static-fetch-1', serverComponents.url).href,
144-
)
145-
expect(purgeCdnCache?.status()).toBe(200)
146-
147-
// wait a bit until cdn cache purge propagates
148-
await page.waitForTimeout(500)
149-
150-
const response1 = await pollUntilHeadersMatch(
151-
new URL('static-fetch-1', serverComponents.url).href,
152-
{
153-
headersToMatch: {
154-
// either first time hitting this route or we invalidated
155-
// just CDN node in earlier step
156-
// we will invoke function and see Next cache hit status \
157-
// in the response because it was prerendered at build time
158-
// or regenerated in previous attempt to run this test
159-
'cache-status': [/"Netlify Edge"; fwd=(miss|stale)/m, /"Next.js"; hit/m],
160-
},
161-
headersNotMatchedMessage:
162-
'First request to tested page should be a miss or stale on the Edge and hit in Next.js',
163-
},
164-
)
165-
const headers1 = response1?.headers() || {}
166-
expect(response1?.status()).toBe(200)
167-
expect(headers1['x-nextjs-cache']).toBeUndefined()
168-
expect(headers1['netlify-cdn-cache-control']).toBe(
169-
's-maxage=31536000, stale-while-revalidate=31536000',
170-
)
171-
172-
const date1 = await page.textContent('[data-testid="date-now"]')
173-
174-
const h1 = await page.textContent('h1')
175-
expect(h1).toBe('Hello, Static Fetch 1')
176-
177-
const response2 = await pollUntilHeadersMatch(
178-
new URL('static-fetch-1', serverComponents.url).href,
179-
{
180-
headersToMatch: {
181-
// we are hitting the same page again and we most likely will see
182-
// CDN hit (in this case Next reported cache status is omitted
183-
// as it didn't actually take place in handling this request)
184-
// or we will see CDN miss because different CDN node handled request
185-
'cache-status': /"Netlify Edge"; (hit|fwd=miss|fwd=stale)/m,
186-
},
187-
headersNotMatchedMessage:
188-
'Second request to tested page should most likely be a hit on the Edge (optionally miss or stale if different CDN node)',
189-
},
190-
)
191-
const headers2 = response2?.headers() || {}
192-
expect(response2?.status()).toBe(200)
193-
expect(headers2['x-nextjs-cache']).toBeUndefined()
194-
if (!headers2['cache-status'].includes('"Netlify Edge"; hit')) {
195-
// if we missed CDN cache, we will see Next cache hit status
196-
// as we reuse cached response
197-
expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m)
198-
}
199-
expect(headers2['netlify-cdn-cache-control']).toBe(
200-
's-maxage=31536000, stale-while-revalidate=31536000',
201-
)
202-
203-
// the page is cached
204-
const date2 = await page.textContent('[data-testid="date-now"]')
205-
expect(date2).toBe(date1)
206-
207-
const revalidate = await page.goto(
208-
new URL('/api/on-demand-revalidate/tag', serverComponents.url).href,
209-
)
210-
expect(revalidate?.status()).toBe(200)
211-
212-
// wait a bit until cdn tags and invalidated and cdn is purged
213-
await page.waitForTimeout(500)
214-
215-
// now after the revalidation it should have a different date
216-
const response3 = await pollUntilHeadersMatch(
217-
new URL('static-fetch-1', serverComponents.url).href,
218-
{
219-
headersToMatch: {
220-
// revalidateTag just marks the page(s) as invalid and does NOT
221-
// automatically refreshes the cache. This request will cause
222-
// Next.js cache miss and new response will be generated and cached
223-
// Depending if we hit same CDN node as previous request, we might
224-
// get either fwd=miss or fwd=stale
225-
'cache-status': [/"Next.js"; fwd=miss/m, /"Netlify Edge"; fwd=(miss|stale)/m],
226-
},
227-
headersNotMatchedMessage:
228-
'Third request to tested page should be a miss or stale on the Edge and miss in Next.js after on-demand revalidation',
229-
},
230-
)
231-
const headers3 = response3?.headers() || {}
232-
expect(response3?.status()).toBe(200)
233-
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
234-
expect(headers3['netlify-cdn-cache-control']).toBe(
235-
's-maxage=31536000, stale-while-revalidate=31536000',
236-
)
237-
238-
// the page has now an updated date
239-
const date3 = await page.textContent('[data-testid="date-now"]')
240-
expect(date3).not.toBe(date2)
241-
242-
const response4 = await pollUntilHeadersMatch(
243-
new URL('static-fetch-1', serverComponents.url).href,
244-
{
245-
headersToMatch: {
246-
// we are hitting the same page again and we most likely will see
247-
// CDN hit (in this case Next reported cache status is omitted
248-
// as it didn't actually take place in handling this request)
249-
// or we will see CDN miss because different CDN node handled request
250-
'cache-status': /"Netlify Edge"; (hit|fwd=miss|fwd=stale)/m,
251-
},
252-
headersNotMatchedMessage:
253-
'Fourth request to tested page should most likely be a hit on the Edge (optionally miss or stale if different CDN node)',
254-
},
255-
)
256-
const headers4 = response4?.headers() || {}
257-
expect(response4?.status()).toBe(200)
258-
expect(headers4?.['x-nextjs-cache']).toBeUndefined()
259-
260-
if (!headers4['cache-status'].includes('"Netlify Edge"; hit')) {
261-
// if we missed CDN cache, we will see Next cache hit status
262-
// as we reuse cached response
263-
expect(headers4['cache-status']).toMatch(/"Next.js"; hit/m)
264-
}
265-
expect(headers4['netlify-cdn-cache-control']).toBe(
266-
's-maxage=31536000, stale-while-revalidate=31536000',
267-
)
268-
269-
// the page is cached
270-
const date4 = await page.textContent('[data-testid="date-now"]')
271-
expect(date4).toBe(date3)
272-
})
154+
})
155+
const headers4 = response4?.headers() || {}
156+
expect(response4?.status()).toBe(200)
157+
expect(headers4?.['x-nextjs-cache']).toBeUndefined()
158+
if (!headers4['cache-status'].includes('"Netlify Edge"; hit')) {
159+
// if we missed CDN cache, we will see Next cache hit status
160+
// as we reuse cached response
161+
expect(headers4['cache-status']).toMatch(/"Next.js"; hit/m)
162+
}
163+
expect(headers4['netlify-cdn-cache-control']).toBe(
164+
's-maxage=31536000, stale-while-revalidate=31536000',
165+
)
166+
167+
// the page is cached
168+
const date4 = await page.textContent('[data-testid="date-now"]')
169+
expect(date4).toBe(date3)
170+
})
171+
}
273172
})

0 commit comments

Comments
 (0)