9
9
type FixtureTestContext ,
10
10
} from '../utils/fixture.js'
11
11
import {
12
+ countOfBlobServerGetsForKey ,
12
13
decodeBlobKey ,
13
14
encodeBlobKey ,
14
15
generateRandomObjectID ,
@@ -64,6 +65,12 @@ describe('page router', () => {
64
65
} ) ,
65
66
)
66
67
68
+ expect (
69
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-automatic' ) ,
70
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
71
+ ) . toBe ( 1 )
72
+ ctx . blobServerGetSpy . mockClear ( )
73
+
67
74
// wait to have page regenerated in the background
68
75
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 1000 ) )
69
76
@@ -82,17 +89,38 @@ describe('page router', () => {
82
89
)
83
90
expect (
84
91
call2Date . localeCompare ( call1Date ) ,
85
- 'the date of regenerated page is newer than initial stale page' ,
92
+ 'the rendered date in regenerated page is newer than initial stale page' ,
93
+ ) . toBeGreaterThan ( 0 )
94
+ expect (
95
+ call2 . headers [ 'date' ] . toString ( ) . localeCompare ( call1 . headers [ 'date' ] . toString ( ) ) ,
96
+ 'the date header of regenerated page is newer than initial stale page' ,
86
97
) . toBeGreaterThan ( 0 )
87
98
99
+ expect (
100
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-automatic' ) ,
101
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
102
+ ) . toBe ( 1 )
103
+ ctx . blobServerGetSpy . mockClear ( )
104
+
88
105
// ping that should serve the stale page for static/revalidate-slow, while revalidating in background
89
106
await invokeFunction ( ctx , { url : 'static/revalidate-slow' } )
90
107
108
+ expect (
109
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-slow' ) ,
110
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
111
+ ) . toBe ( 1 )
112
+ ctx . blobServerGetSpy . mockClear ( )
113
+
91
114
// wait to have a stale page
92
115
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 6_000 ) )
93
116
94
117
// Ping this now so we can wait in parallel
95
118
const callLater = await invokeFunction ( ctx , { url : 'static/revalidate-slow' } )
119
+ expect (
120
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-slow' ) ,
121
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
122
+ ) . toBe ( 1 )
123
+ ctx . blobServerGetSpy . mockClear ( )
96
124
97
125
// over 5 seconds since it was regenerated, so we should get stale response,
98
126
// while fresh is generated in the background
@@ -104,9 +132,19 @@ describe('page router', () => {
104
132
'cache-status' : '"Next.js"; hit; fwd=stale' ,
105
133
} ) ,
106
134
)
107
- expect ( call3Date , 'the date was cached and is matching the initially regenerated one' ) . toBe (
108
- call2Date ,
109
- )
135
+ expect (
136
+ call3Date ,
137
+ 'the rendered date was cached and is matching the initially regenerated one' ,
138
+ ) . toBe ( call2Date )
139
+ expect (
140
+ call3 . headers [ 'date' ] ,
141
+ 'the date header is the same as the initially regenerated one' ,
142
+ ) . toBe ( call2 . headers [ 'date' ] )
143
+ expect (
144
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-automatic' ) ,
145
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
146
+ ) . toBe ( 1 )
147
+ ctx . blobServerGetSpy . mockClear ( )
110
148
111
149
// Slow revalidate should still be a hit, but the maxage should be updated
112
150
const callLater2 = await invokeFunction ( ctx , { url : 'static/revalidate-slow' } )
@@ -119,6 +157,11 @@ describe('page router', () => {
119
157
date : callLater . headers [ 'date' ] ,
120
158
} ) ,
121
159
)
160
+ expect (
161
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-slow' ) ,
162
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
163
+ ) . toBe ( 1 )
164
+ ctx . blobServerGetSpy . mockClear ( )
122
165
123
166
// it does not wait for the cache.set so we have to manually wait here until the blob storage got populated
124
167
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 1000 ) )
@@ -127,6 +170,10 @@ describe('page router', () => {
127
170
const call4 = await invokeFunction ( ctx , { url : 'static/revalidate-automatic' } )
128
171
const call4Date = load ( call4 . body ) ( '[data-testid="date-now"]' ) . text ( )
129
172
expect ( call4Date , 'the date was not cached' ) . not . toBe ( call3Date )
173
+ expect (
174
+ call4 . headers [ 'date' ] . toString ( ) . localeCompare ( call3 . headers [ 'date' ] . toString ( ) ) ,
175
+ 'the date header of regenerated page is newer than initial stale page' ,
176
+ ) . toBeGreaterThan ( 0 )
130
177
expect ( call4 . statusCode ) . toBe ( 200 )
131
178
expect (
132
179
call4 . headers ,
@@ -136,6 +183,11 @@ describe('page router', () => {
136
183
'cache-status' : expect . stringMatching ( / " N e x t .j s " ; h i t / ) ,
137
184
} ) ,
138
185
)
186
+ expect (
187
+ countOfBlobServerGetsForKey ( ctx , '/static/revalidate-automatic' ) ,
188
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
189
+ ) . toBe ( 1 )
190
+ ctx . blobServerGetSpy . mockClear ( )
139
191
} )
140
192
} )
141
193
@@ -168,6 +220,11 @@ describe('app router', () => {
168
220
'netlify-cdn-cache-control' : 's-maxage=5, stale-while-revalidate=31536000' ,
169
221
} ) ,
170
222
)
223
+ expect (
224
+ countOfBlobServerGetsForKey ( ctx , '/posts/1' ) ,
225
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
226
+ ) . toBe ( 1 )
227
+ ctx . blobServerGetSpy . mockClear ( )
171
228
172
229
// test a prerendered page without TTL
173
230
const post2 = await invokeFunction ( ctx , { url : '/' } )
@@ -179,6 +236,11 @@ describe('app router', () => {
179
236
'netlify-cdn-cache-control' : 's-maxage=31536000, stale-while-revalidate=31536000' ,
180
237
} ) ,
181
238
)
239
+ expect (
240
+ countOfBlobServerGetsForKey ( ctx , '/index' ) ,
241
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
242
+ ) . toBe ( 1 )
243
+ ctx . blobServerGetSpy . mockClear ( )
182
244
183
245
expect ( await ctx . blobStore . get ( encodeBlobKey ( '/posts/3' ) ) ) . toBeNull ( )
184
246
// this page is not pre-rendered and should result in a cache miss
@@ -193,7 +255,7 @@ describe('app router', () => {
193
255
194
256
// wait to have a stale page
195
257
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 6_000 ) )
196
- // after the dynamic call of `posts/3` it should be in cache, not this is after the timout as the cache set happens async
258
+ // after the dynamic call of `posts/3` it should be in cache, note this is after the timeout as the cache set happens async
197
259
expect ( await ctx . blobStore . get ( encodeBlobKey ( '/posts/3' ) ) ) . not . toBeNull ( )
198
260
199
261
const stale = await invokeFunction ( ctx , { url : 'posts/1' } )
@@ -204,6 +266,11 @@ describe('app router', () => {
204
266
'cache-status' : '"Next.js"; hit; fwd=stale' ,
205
267
} ) ,
206
268
)
269
+ expect (
270
+ countOfBlobServerGetsForKey ( ctx , '/posts/1' ) ,
271
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
272
+ ) . toBe ( 1 )
273
+ ctx . blobServerGetSpy . mockClear ( )
207
274
// it should've been regenerated in the background after the first call
208
275
// so the date should be different
209
276
expect ( staleDate , 'the date was cached and is matching the initial one' ) . not . toBe ( post1Date )
@@ -216,11 +283,20 @@ describe('app router', () => {
216
283
const cachedDate = load ( cached . body ) ( '[data-testid="date-now"]' ) . text ( )
217
284
expect ( cached . statusCode ) . toBe ( 200 )
218
285
expect ( cachedDate , 'the date is not stale' ) . not . toBe ( staleDate )
286
+ expect (
287
+ cached . headers [ 'date' ] . toString ( ) . localeCompare ( post1 . headers [ 'date' ] . toString ( ) ) ,
288
+ 'the date header of regenerated page is newer than initial stale page' ,
289
+ ) . toBeGreaterThan ( 0 )
219
290
expect ( cached . headers , 'a cache hit after dynamically regenerating the stale page' ) . toEqual (
220
291
expect . objectContaining ( {
221
292
'cache-status' : '"Next.js"; hit' ,
222
293
} ) ,
223
294
)
295
+ expect (
296
+ countOfBlobServerGetsForKey ( ctx , '/posts/1' ) ,
297
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
298
+ ) . toBe ( 1 )
299
+ ctx . blobServerGetSpy . mockClear ( )
224
300
} )
225
301
} )
226
302
@@ -257,10 +333,12 @@ describe('route', () => {
257
333
} )
258
334
expect ( blobEntry ) . not . toBeNull ( )
259
335
336
+ ctx . blobServerGetSpy . mockClear ( )
337
+
260
338
// test the first invocation of the route - we should get stale response while fresh is generated in the background
261
339
const call1 = await invokeFunction ( ctx , { url : '/api/revalidate-handler' } )
262
340
const call1Body = JSON . parse ( call1 . body )
263
- const call1Time = call1Body . time
341
+ const call1Time = call1Body . time as string
264
342
expect ( call1 . statusCode ) . toBe ( 200 )
265
343
expect ( call1Body ) . toMatchObject ( {
266
344
data : expect . objectContaining ( {
@@ -274,12 +352,18 @@ describe('route', () => {
274
352
} ) ,
275
353
)
276
354
355
+ expect (
356
+ countOfBlobServerGetsForKey ( ctx , '/api/revalidate-handler' ) ,
357
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
358
+ ) . toBe ( 1 )
359
+ ctx . blobServerGetSpy . mockClear ( )
360
+
277
361
// it does not wait for the cache.set so we have to manually wait here until the blob storage got populated
278
362
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 1000 ) )
279
363
280
364
const call2 = await invokeFunction ( ctx , { url : '/api/revalidate-handler' } )
281
365
const call2Body = JSON . parse ( call2 . body )
282
- const call2Time = call2Body . time
366
+ const call2Time = call2Body . time as string
283
367
expect ( call2 . statusCode ) . toBe ( 200 )
284
368
expect ( call2Body ) . toMatchObject ( {
285
369
data : expect . objectContaining ( {
@@ -292,7 +376,16 @@ describe('route', () => {
292
376
'cache-status' : '"Next.js"; hit' ,
293
377
} ) ,
294
378
)
295
- expect ( call2Time , 'the date is new' ) . not . toBe ( call1Time )
379
+ expect ( call2Time . localeCompare ( call1Time ) , 'the rendered date is new' ) . toBeGreaterThan ( 0 )
380
+ expect (
381
+ call2 . headers [ 'date' ] . toString ( ) . localeCompare ( call1 . headers [ 'date' ] . toString ( ) ) ,
382
+ 'the date header of regenerated route is newer than initial stale route' ,
383
+ ) . toBeGreaterThan ( 0 )
384
+ expect (
385
+ countOfBlobServerGetsForKey ( ctx , '/api/revalidate-handler' ) ,
386
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
387
+ ) . toBe ( 1 )
388
+ ctx . blobServerGetSpy . mockClear ( )
296
389
297
390
// wait to have a stale route again
298
391
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 8_000 ) )
@@ -308,9 +401,18 @@ describe('route', () => {
308
401
} ) ,
309
402
)
310
403
expect (
311
- call2Time ,
312
- 'the date is the old one on the stale route, while the refresh is happening in the background' ,
313
- ) . toBe ( call3Time )
404
+ call3Time ,
405
+ 'the rendered date is the old one on the stale route, while the refresh is happening in the background' ,
406
+ ) . toBe ( call2Time )
407
+ expect ( call3 . headers [ 'date' ] , 'the date header is the same on stale route' ) . toBe (
408
+ call2 . headers [ 'date' ] ,
409
+ )
410
+
411
+ expect (
412
+ countOfBlobServerGetsForKey ( ctx , '/api/revalidate-handler' ) ,
413
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
414
+ ) . toBe ( 1 )
415
+ ctx . blobServerGetSpy . mockClear ( )
314
416
315
417
// it does not wait for the cache.set so we have to manually wait here until the blob storage got populated
316
418
await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 1000 ) )
@@ -325,6 +427,15 @@ describe('route', () => {
325
427
'cache-status' : '"Next.js"; hit' ,
326
428
} ) ,
327
429
)
328
- expect ( call4Time , 'the date is new' ) . not . toBe ( call3Time )
430
+ expect ( call4Time . localeCompare ( call3Time ) , 'the rendered date is new' ) . toBeGreaterThan ( 0 )
431
+ expect (
432
+ call4 . headers [ 'date' ] . toString ( ) . localeCompare ( call3 . headers [ 'date' ] . toString ( ) ) ,
433
+ 'the date header of regenerated route is newer than previously stale route' ,
434
+ ) . toBeGreaterThan ( 0 )
435
+ expect (
436
+ countOfBlobServerGetsForKey ( ctx , '/api/revalidate-handler' ) ,
437
+ 'should only try to get value once from blob store (date calculation should not trigger additional blobs.get)' ,
438
+ ) . toBe ( 1 )
439
+ ctx . blobServerGetSpy . mockClear ( )
329
440
} )
330
441
} )
0 commit comments