11import { test } from "@playwright/test"
22import { assert } from "chai"
3- import { clearAllCaches , getCacheStatus , registerServiceWorker , unregisterServiceWorker , testFetch , waitForServiceWorkerToControl , getCachedResponse , setNetworkDelay } from "../helpers/offline"
3+ import { clearAllCaches , registerServiceWorker , unregisterServiceWorker , testFetch , waitForServiceWorkerToControl , getCachedResponse , setNetworkDelay } from "../helpers/offline"
44
55test . beforeEach ( async ( { page } ) => {
66 await page . goto ( "/src/tests/fixtures/bare.html" )
@@ -21,22 +21,14 @@ test("registers service worker and intercepts and caches requests with cache-fir
2121
2222 const dynamicTxtUrl = "/__turbo/dynamic.txt"
2323
24- const firstTxtResponse = await testFetch ( page , dynamicTxtUrl )
25- assert . equal ( firstTxtResponse . ok , true )
26- const firstContent = firstTxtResponse . text . trim ( )
24+ const firstContent = await fetchContent ( page , dynamicTxtUrl )
2725
2826 // Wait a bit for the response to be cached
2927 await page . waitForTimeout ( 200 )
3028
31- // Check the cached content
32- const fullUrl = "http://localhost:9000" + dynamicTxtUrl
33- const cachedResponse = await getCachedResponse ( page , "test-cache-first" , fullUrl )
34- assert . isTrue ( cachedResponse . found )
35- assert . equal ( cachedResponse . text . trim ( ) , firstContent , "Cached content should match first response" )
29+ await assertCachedContent ( page , "test-cache-first" , dynamicTxtUrl , firstContent )
3630
37- const secondTxtResponse = await testFetch ( page , dynamicTxtUrl )
38- assert . equal ( secondTxtResponse . ok , true )
39- const secondContent = secondTxtResponse . text . trim ( )
31+ const secondContent = await fetchContent ( page , dynamicTxtUrl )
4032
4133 assert . equal ( secondContent , firstContent , "Second request should return identical content from cache" )
4234} )
@@ -48,27 +40,20 @@ test("registers service worker and intercepts and caches requests with network-f
4840 const dynamicTxtUrl = "/__turbo/dynamic.txt"
4941
5042 // First request to dynamic text file - should hit network and cache unique content
51- const firstTxtResponse = await testFetch ( page , dynamicTxtUrl )
52- assert . equal ( firstTxtResponse . ok , true )
53- const firstContent = firstTxtResponse . text . trim ( )
43+ const firstContent = await fetchContent ( page , dynamicTxtUrl )
5444
55- // Check the cached content
56- const fullUrl = "http://localhost:9000" + dynamicTxtUrl
57- const cachedResponse = await getCachedResponse ( page , "test-network-first" , fullUrl )
58- assert . isTrue ( cachedResponse . found )
59- assert . equal ( cachedResponse . text . trim ( ) , firstContent , "Cached content should match first response" )
45+ // Wait a bit for the response to be cached
46+ await page . waitForTimeout ( 200 )
47+ await assertCachedContent ( page , "test-network-first" , dynamicTxtUrl , firstContent )
6048
6149 // Second request - should hit the network again
62- const secondTxtResponse = await testFetch ( page , dynamicTxtUrl )
63- assert . equal ( secondTxtResponse . ok , true )
64- const secondContent = secondTxtResponse . text . trim ( )
50+ const secondContent = await fetchContent ( page , dynamicTxtUrl )
6551
6652 assert . notEqual ( secondContent , firstContent , "Second request should return different content from network" )
6753
6854 // The cached content should have been refreshed as well
69- const cachedResponseAfterSecondRequest = await getCachedResponse ( page , "test-network-first" , fullUrl )
70- assert . isTrue ( cachedResponseAfterSecondRequest . found )
71- assert . notEqual ( cachedResponseAfterSecondRequest . text . trim ( ) , cachedResponse . text . trim ( ) , "Cached content should have changed" )
55+ const cachedContentAfterSecondRequest = await getCachedContent ( page , "test-network-first" , dynamicTxtUrl )
56+ assert . notEqual ( cachedContentAfterSecondRequest , firstContent , "Cached content should have changed" )
7257} )
7358
7459test ( "registers service worker and intercepts and caches requests with stale-while-revalidate strategy" , async ( { page } ) => {
@@ -78,28 +63,20 @@ test("registers service worker and intercepts and caches requests with stale-whi
7863 const dynamicTxtUrl = "/__turbo/dynamic.txt"
7964
8065 // First request to dynamic text file - should hit network and cache unique content
81- const firstTxtResponse = await testFetch ( page , dynamicTxtUrl )
82- assert . equal ( firstTxtResponse . ok , true )
83- const firstContent = firstTxtResponse . text . trim ( )
66+ const firstContent = await fetchContent ( page , dynamicTxtUrl )
8467
85- // Check the cached content
86- const fullUrl = "http://localhost:9000" + dynamicTxtUrl
87- const cachedResponse = await getCachedResponse ( page , "test-stale-while-revalidate" , fullUrl )
88- assert . isTrue ( cachedResponse . found )
89- assert . equal ( cachedResponse . text . trim ( ) , firstContent , "Cached content should match first response" )
68+ // Wait a bit for the response to be cached
69+ await page . waitForTimeout ( 200 )
70+ await assertCachedContent ( page , "test-stale-while-revalidate" , dynamicTxtUrl , firstContent )
9071
9172 // Second request - should return the cached response but refresh it in the background
92- const secondTxtResponse = await testFetch ( page , dynamicTxtUrl )
93- assert . equal ( secondTxtResponse . ok , true )
94- const secondContent = secondTxtResponse . text . trim ( )
95-
73+ const secondContent = await fetchContent ( page , dynamicTxtUrl )
9674 assert . equal ( secondContent , firstContent , "Second request should return identical content from cache" )
9775
9876 // Now check that the cached content was refreshed
9977 await page . waitForTimeout ( 200 )
100- const cachedResponseAfterSecondRequest = await getCachedResponse ( page , "test-stale-while-revalidate" , fullUrl )
101- assert . isTrue ( cachedResponseAfterSecondRequest . found )
102- assert . notEqual ( cachedResponseAfterSecondRequest . text . trim ( ) , cachedResponse . text . trim ( ) , "Cached content should have changed" )
78+ const cachedContentAfterSecondRequest = await getCachedContent ( page , "test-stale-while-revalidate" , dynamicTxtUrl )
79+ assert . notEqual ( cachedContentAfterSecondRequest , firstContent , "Cached content should have changed" )
10380} )
10481
10582test ( "doesn't intercept non-matching requests" , async ( { page } ) => {
@@ -123,10 +100,7 @@ test("doesn't intercept non-matching requests", async ({ page }) => {
123100 assert . notEqual ( secondJsonData . timestamp , firstJsonData . timestamp , "Timestamps should have changed" )
124101 assert . notEqual ( secondJsonData . requestId , firstJsonData . requestId , "Request IDs should be different" )
125102
126- const cacheStatus = await getCacheStatus ( page )
127-
128- // Should not have our test cache since no matching requests were made
129- assert . isFalse ( Object . keys ( cacheStatus ) . includes ( "test-cache-first" ) , "Test cache should not exist for non-matching requests" )
103+ await assertNotCached ( page , "test-cache-first" , dynamicJsonUrl )
130104} )
131105
132106test ( "registers service worker as a module and intercepts and caches requests" , async ( { page, browserName } ) => {
@@ -138,13 +112,8 @@ test("registers service worker as a module and intercepts and caches requests",
138112
139113 const dynamicTxtUrl = "/__turbo/dynamic.txt"
140114
141- const firstTxtResponse = await testFetch ( page , dynamicTxtUrl )
142- assert . equal ( firstTxtResponse . ok , true )
143- const firstContent = firstTxtResponse . text . trim ( )
144-
145- const secondTxtResponse = await testFetch ( page , dynamicTxtUrl )
146- assert . equal ( secondTxtResponse . ok , true )
147- const secondContent = secondTxtResponse . text . trim ( )
115+ const firstContent = await fetchContent ( page , dynamicTxtUrl )
116+ const secondContent = await fetchContent ( page , dynamicTxtUrl )
148117
149118 assert . equal ( secondContent , firstContent , "Second request should return identical content from cache" )
150119} )
@@ -158,38 +127,22 @@ test("applies different handlers to different requests based on different rules"
158127 const dynamicJsonUrl = "/__turbo/dynamic.json"
159128
160129 // Request cached with network-first
161- const jsonResponse = await testFetch ( page , dynamicJsonUrl )
162- assert . equal ( jsonResponse . ok , true )
163-
164- let fullUrl = "http://localhost:9000" + dynamicJsonUrl
165- let cachedResponse = await getCachedResponse ( page , "test-network-first" , fullUrl )
166- assert . isTrue ( cachedResponse . found )
167- assert . equal ( cachedResponse . text . trim ( ) , jsonResponse . text . trim ( ) , "Cached content should match response" )
130+ const jsonContent = await fetchContent ( page , dynamicJsonUrl )
131+ await assertCachedContent ( page , "test-network-first" , dynamicJsonUrl , jsonContent )
168132
169133 // Request without header - should NOT be cached
170134 const notCachedTxtResponse = await testFetch ( page , dynamicTxtUrl )
171135 assert . equal ( notCachedTxtResponse . ok , true )
136+ await assertNotCached ( page , "test-cache-first" , dynamicTxtUrl )
172137
173- // Verify it wasn't cached (no matching rule)
174- fullUrl = "http://localhost:9000" + dynamicTxtUrl
175- cachedResponse = await getCachedResponse ( page , "test-cache-first" , fullUrl )
176- assert . isFalse ( cachedResponse . found , "Response for request without X-Cache header should not be cached" )
177138
178139 // Request with header - should be cached
179- const cachedTxtResponse = await testFetch ( page , dynamicTxtUrl , { "X-Cache" : "yes" } )
180- assert . equal ( cachedTxtResponse . ok , true )
181-
182- // Wait a bit for caching
183- await page . waitForTimeout ( 200 )
184-
185- // Verify it was cached
186- cachedResponse = await getCachedResponse ( page , "test-cache-first" , fullUrl )
187- assert . isTrue ( cachedResponse . found , "Response for request with X-Cache header should be cached" )
188- assert . equal ( cachedResponse . text . trim ( ) , cachedTxtResponse . text . trim ( ) , "Cached content should match response requested with header" )
140+ const cachedTxtContent = await fetchContent ( page , dynamicTxtUrl , { "X-Cache" : "yes" } )
141+ await assertCachedContent ( page , "test-cache-first" , dynamicTxtUrl , cachedTxtContent )
189142
190143 // Make the same request again - should return cached content
191- const secondCachedTxtResponse = await testFetch ( page , dynamicTxtUrl , { "X-Cache" : "yes" } )
192- assert . equal ( secondCachedTxtResponse . text . trim ( ) , cachedTxtResponse . text . trim ( ) , "Second request with header should return cached content" )
144+ const secondCachedTxtContent = await fetchContent ( page , dynamicTxtUrl , { "X-Cache" : "yes" } )
145+ assert . equal ( secondCachedTxtContent , cachedTxtContent , "Second request with header should return cached content" )
193146} )
194147
195148test ( "network timeout triggers cache fallback for network-first" , async ( { page } ) => {
@@ -198,11 +151,9 @@ test("network timeout triggers cache fallback for network-first", async ({ page
198151
199152 const dynamicTxtUrl = "/__turbo/dynamic.txt"
200153
201- const initialResponse = await testFetch ( page , dynamicTxtUrl )
202- assert . equal ( initialResponse . ok , true )
203- const initialContent = initialResponse . text . trim ( )
154+ const initialContent = await fetchContent ( page , dynamicTxtUrl )
204155
205- // Set a long delay that exceeds the network timeout (2 seconds)
156+ // Set a long delay that exceeds the network timeout configured in the network-first service worker
206157 await setNetworkDelay ( page , 5000 )
207158
208159 const timeoutResponse = await testFetch ( page , dynamicTxtUrl )
@@ -217,61 +168,70 @@ test("deletes cached entries after maxAge per cache", async ({ page }) => {
217168 const dynamicTxtUrl = "/__turbo/dynamic.txt"
218169 const dynamicJsonUrl = "/__turbo/dynamic.json"
219170
220- // Cache in short-lived cache using X-Cache header (0.5 second maxAge)
221- const shortLivedResponse = await testFetch ( page , dynamicTxtUrl )
222- assert . equal ( shortLivedResponse . ok , true )
171+ // Cache in short-lived cache using (0.5 second maxAge)
172+ const shortLivedContent = await fetchContent ( page , dynamicTxtUrl )
223173
224174 // Cache in long-lived cache (5 minute maxAge)
225- const longLivedResponse = await testFetch ( page , dynamicJsonUrl )
226- assert . equal ( longLivedResponse . ok , true )
175+ const longLivedContent = await fetchContent ( page , dynamicJsonUrl )
227176
228177 // Wait for caching to complete
229178 await page . waitForTimeout ( 200 )
230179
231180 // Verify both are cached
232- const shortLivedUrl = "http://localhost:9000" + dynamicTxtUrl
233- const longLivedUrl = "http://localhost:9000" + dynamicJsonUrl
234-
235- let shortLivedCached = await getCachedResponse ( page , "test-cache-trimming-short" , shortLivedUrl )
236- let longLivedCached = await getCachedResponse ( page , "test-cache-stable" , longLivedUrl )
237-
238- assert . isTrue ( shortLivedCached . found , "Short-lived cache entry should be cached" )
239- assert . isTrue ( longLivedCached . found , "Long-lived cache entry should be cached" )
181+ await assertCachedContent ( page , "test-cache-short-lived" , dynamicTxtUrl , shortLivedContent )
182+ await assertCachedContent ( page , "test-cache-stable" , dynamicJsonUrl , longLivedContent )
240183
241184 // Wait for the short-lived cache to expire (0.5 seconds + buffer)
242185 await page . waitForTimeout ( 750 )
243186
244187 // Make a request to a different URL to trigger caching (and therefore trimming)
245188 const triggerTrimUrl = "/__turbo/dynamic.txt?trigger=trim"
246- const firstTriggerTrimResponse = await testFetch ( page , triggerTrimUrl )
247- assert . equal ( firstTriggerTrimResponse . ok , true )
189+ const firstTriggerTrimContent = await fetchContent ( page , triggerTrimUrl )
248190
249191 // Wait a bit for trimming to potentially complete
250192 await page . waitForTimeout ( 500 )
251193
252- // Check cache states after trimming
253- shortLivedCached = await getCachedResponse ( page , "test-cache-trimming-short" , shortLivedUrl )
254- longLivedCached = await getCachedResponse ( page , "test-cache-stable" , longLivedUrl )
255-
256194 // The expired short-lived entry should be removed
257- assert . isFalse ( shortLivedCached . found , "Expired short-lived entry should be trimmed" )
195+ await assertNotCached ( page , "test-cache- short-lived" , dynamicTxtUrl )
258196
259- // The long-lived cache should be unaffected (different cache, different trimmer, longer maxAge)
260- assert . isTrue ( longLivedCached . found , "Long-lived cache should not be affected by short-lived cache trimming" )
261- assert . equal ( longLivedCached . text . trim ( ) , longLivedResponse . text . trim ( ) , "Long-lived cached content should remain unchanged" )
197+ // The long-lived cache should be unaffected
198+ await assertCachedContent ( page , "test-cache-stable" , dynamicJsonUrl , longLivedContent )
262199
263200 // And now, request the last cached response in the short-lived cache, which will be expired, yet returned,
264201 // to trigger trimming as well
265202 // Wait a bit to ensure it has really expired
266203 await page . waitForTimeout ( 200 )
267204
268- const secondTriggerTrimResponse = await testFetch ( page , triggerTrimUrl )
269- assert . equal ( secondTriggerTrimResponse . ok , true )
270- assert . equal ( secondTriggerTrimResponse . text , firstTriggerTrimResponse . text , "Second request should return identical content from cache" )
205+ const secondTriggerTrimContent = await fetchContent ( page , triggerTrimUrl )
206+ assert . equal ( secondTriggerTrimContent , firstTriggerTrimContent , "Second request should return identical content from cache" )
271207
272208 // Wait a bit for trimming to potentially complete
273209 await page . waitForTimeout ( 500 )
274210 // And finally check that it's gone
275- const triggerTrimCached = await getCachedResponse ( page , "test-cache-trimming-short" , "http://localhost:9000" + triggerTrimUrl )
276- assert . isFalse ( triggerTrimCached . found , "Expired short-lived entry should be trimmed" )
211+ await assertNotCached ( page , "test-cache-short-lived" , triggerTrimUrl )
277212} )
213+
214+ async function fetchContent ( page , url , headers = { } ) {
215+ const response = await testFetch ( page , url , headers )
216+ assert . equal ( response . ok , true )
217+ return response . text . trim ( )
218+ }
219+
220+ async function getCachedContent ( page , cacheName , url ) {
221+ const fullUrl = "http://localhost:9000" + url
222+ const cachedResponse = await getCachedResponse ( page , cacheName , fullUrl )
223+ assert . isTrue ( cachedResponse . found )
224+
225+ return cachedResponse . text . trim ( )
226+ }
227+
228+ async function assertCachedContent ( page , cacheName , url , expectedContent ) {
229+ const cachedContent = await getCachedContent ( page , cacheName , url )
230+ assert . equal ( cachedContent , expectedContent , "Cached content should match expected content" )
231+ }
232+
233+ async function assertNotCached ( page , cacheName , url ) {
234+ const fullUrl = "http://localhost:9000" + url
235+ const cachedResponse = await getCachedResponse ( page , cacheName , fullUrl )
236+ assert . isFalse ( cachedResponse . found )
237+ }
0 commit comments