-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathrevalidate-path.test.ts
148 lines (126 loc) · 5.35 KB
/
revalidate-path.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { load } from 'cheerio'
import { getLogger } from 'lambda-local'
import { v4 } from 'uuid'
import { beforeEach, expect, test, vi } from 'vitest'
import { type FixtureTestContext } from '../utils/contexts.js'
import { createFixture, invokeFunction, runPlugin } from '../utils/fixture.js'
import {
encodeBlobKey,
generateRandomObjectID,
getBlobServerGets,
startMockBlobStore,
} from '../utils/helpers.js'
import { nextVersionSatisfies } from '../utils/next-version-helpers.mjs'
function isTagManifest(key: string) {
return key.startsWith('_N_T_')
}
expect.extend({
toBeDistinct(received: string[]) {
const { isNot } = this
const pass = new Set(received).size === received.length
return {
pass,
message: () => `${received} is${isNot ? ' not' : ''} array with distinct values`,
}
},
})
interface CustomMatchers<R = unknown> {
toBeDistinct(): R
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
}
// Disable the verbose logging of the lambda-local runtime
getLogger().level = 'alert'
beforeEach<FixtureTestContext>(async (ctx) => {
// set for each test a new deployID and siteID
ctx.deployID = generateRandomObjectID()
ctx.siteID = v4()
vi.stubEnv('SITE_ID', ctx.siteID)
vi.stubEnv('DEPLOY_ID', ctx.deployID)
vi.stubEnv('NETLIFY_PURGE_API_TOKEN', 'fake-token')
// hide debug logs in tests
// vi.spyOn(console, 'debug').mockImplementation(() => {})
await startMockBlobStore(ctx)
})
test<FixtureTestContext>('should revalidate a route by path', async (ctx) => {
await createFixture('server-components', ctx)
await runPlugin(ctx)
expect(await ctx.blobStore.get(encodeBlobKey('/static-fetch/1'))).not.toBeNull()
expect(await ctx.blobStore.get(encodeBlobKey('_N_T_/static-fetch/[id]/page'))).toBeNull()
ctx.blobServerGetSpy.mockClear()
// test the function call
const post1 = await invokeFunction(ctx, { url: '/static-fetch/1' })
const post1Date = load(post1.body)('[data-testid="date-now"]').text()
expect(post1.statusCode).toBe(200)
expect(load(post1.body)('h1').text()).toBe('Hello, Statically fetched show 1')
expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
expect.objectContaining({
'cache-status': expect.stringMatching(/"Next.js"; hit/),
'netlify-cdn-cache-control': nextVersionSatisfies('>=15.0.0-canary.187')
? 's-maxage=31536000, durable'
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
}),
)
expect(
getBlobServerGets(ctx, isTagManifest),
`expected tag manifests to be retrieved at most once per tag`,
).toBeDistinct()
ctx.blobServerGetSpy.mockClear()
const post1Route2 = await invokeFunction(ctx, { url: '/static-fetch/2' })
expect(post1Route2.statusCode).toBe(200)
expect(post1Route2.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
expect.objectContaining({
'cache-status': expect.stringMatching(/"Next.js"; hit/),
'netlify-cdn-cache-control': nextVersionSatisfies('>=15.0.0-canary.187')
? 's-maxage=31536000, durable'
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
}),
)
expect(
getBlobServerGets(ctx, isTagManifest),
`expected tag manifests to be retrieved at most once per tag`,
).toBeDistinct()
ctx.blobServerGetSpy.mockClear()
const revalidate = await invokeFunction(ctx, { url: '/api/on-demand-revalidate/path' })
expect(revalidate.statusCode).toBe(200)
expect(JSON.parse(revalidate.body)).toEqual({ revalidated: true, now: expect.any(String) })
// expect(calledPurge).toBe(1)
// it does not wait for the cache.set so we have to manually wait here until the blob storage got populated
await new Promise<void>((resolve) => setTimeout(resolve, 1000))
expect(await ctx.blobStore.get(encodeBlobKey('_N_T_/static-fetch/[id]/page'))).not.toBeNull()
ctx.blobServerGetSpy.mockClear()
const post2 = await invokeFunction(ctx, { url: '/static-fetch/1' })
const post2Date = load(post2.body)('[data-testid="date-now"]').text()
expect(post2.statusCode).toBe(200)
expect(load(post2.body)('h1').text()).toBe('Hello, Statically fetched show 1')
expect(post2.headers, 'a cache miss on the on demand revalidated path /1').toEqual(
expect.objectContaining({
'cache-status': '"Next.js"; fwd=miss',
'netlify-cdn-cache-control': nextVersionSatisfies('>=15.0.0-canary.187')
? 's-maxage=31536000, durable'
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
}),
)
expect(post2Date).not.toBe(post1Date)
expect(
getBlobServerGets(ctx, isTagManifest),
`expected tag manifests to be retrieved at most once per tag`,
).toBeDistinct()
ctx.blobServerGetSpy.mockClear()
const post2Route2 = await invokeFunction(ctx, { url: '/static-fetch/2' })
expect(post2Route2.statusCode).toBe(200)
expect(post2Route2.headers, 'a cache miss on the on demand revalidated path /2').toEqual(
expect.objectContaining({
'cache-status': '"Next.js"; fwd=miss',
'netlify-cdn-cache-control': nextVersionSatisfies('>=15.0.0-canary.187')
? 's-maxage=31536000, durable'
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
}),
)
expect(
getBlobServerGets(ctx, isTagManifest),
`expected tag manifests to be retrieved at most once per tag`,
).toBeDistinct()
ctx.blobServerGetSpy.mockClear()
})