@@ -5,48 +5,86 @@ const test = testFactory({
5
5
root : './fixtures/prefetch/' ,
6
6
} ) ;
7
7
8
+ // Used to track fetch request urls
9
+ /** @type {string[] } */
10
+ const reqUrls = [ ] ;
11
+ test . beforeEach ( async ( { page } ) => {
12
+ page . on ( 'request' , ( req ) => {
13
+ const urlObj = new URL ( req . url ( ) ) ;
14
+ reqUrls . push ( urlObj . pathname + urlObj . search ) ;
15
+ } ) ;
16
+ } ) ;
17
+ test . afterEach ( ( ) => {
18
+ reqUrls . length = 0 ;
19
+ } ) ;
20
+
21
+ /**
22
+ * Check if url is prefetched via `link[rel="prefetch"]` or `fetch()` (from `reqUrls`)
23
+ * @param {string } url
24
+ * @param {import('@playwright/test').Page } page
25
+ * @param {number } [count] Also expect that it's prefetched this amount of times
26
+ */
27
+ async function expectUrlPrefetched ( url , page , count ) {
28
+ try {
29
+ await expect ( page . locator ( `link[rel="prefetch"][href$="${ url } "]` ) ) . toBeAttached ( ) ;
30
+ } catch {
31
+ // If link is not found, check if it was fetched via `fetch()`
32
+ expect ( reqUrls , `${ url } is not prefetched via link or fetch` ) . toContainEqual ( url ) ;
33
+ }
34
+
35
+ if ( count != null ) {
36
+ const linkCount = await page . locator ( `link[rel="prefetch"][href$="${ url } "]` ) . count ( ) ;
37
+ try {
38
+ expect ( linkCount ) . toBe ( count ) ;
39
+ } catch {
40
+ const fetchCount = reqUrls . filter ( ( u ) => u . includes ( url ) ) . length ;
41
+ expect (
42
+ fetchCount ,
43
+ `${ url } should be prefetched ${ count } time(s), but is prefetch with link ${ linkCount } time(s) and with fetch ${ fetchCount } time(s)`
44
+ ) . toEqual ( count ) ;
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Check if url is not prefetched via `link[rel="prefetch"]` and `fetch()` (from `reqUrls`)
51
+ * @param {string } url
52
+ * @param {import('@playwright/test').Page } page
53
+ */
54
+ async function expectUrlNotPrefetched ( url , page ) {
55
+ await expect ( page . locator ( `link[rel="prefetch"][href$="${ url } "]` ) ) . not . toBeAttached ( ) ;
56
+ expect ( reqUrls ) . not . toContainEqual ( url ) ;
57
+ }
58
+
8
59
test . describe ( 'Prefetch (default)' , ( ) => {
9
60
let devServer ;
10
- /** @type {string[] } */
11
- const reqUrls = [ ] ;
12
61
13
62
test . beforeAll ( async ( { astro } ) => {
14
63
devServer = await astro . startDevServer ( ) ;
15
64
} ) ;
16
65
17
- test . beforeEach ( async ( { page } ) => {
18
- page . on ( 'request' , ( req ) => {
19
- const urlObj = new URL ( req . url ( ) ) ;
20
- reqUrls . push ( urlObj . pathname + urlObj . search ) ;
21
- } ) ;
22
- } ) ;
23
-
24
- test . afterEach ( ( ) => {
25
- reqUrls . length = 0 ;
26
- } ) ;
27
-
28
66
test . afterAll ( async ( ) => {
29
67
await devServer . stop ( ) ;
30
68
} ) ;
31
69
32
70
test ( 'Link without data-astro-prefetch should not prefetch' , async ( { page, astro } ) => {
33
71
await page . goto ( astro . resolveUrl ( '/' ) ) ;
34
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-default' ) ;
72
+ await expectUrlNotPrefetched ( '/prefetch-default' , page ) ;
35
73
} ) ;
36
74
37
75
test ( 'data-astro-prefetch="false" should not prefetch' , async ( { page, astro } ) => {
38
76
await page . goto ( astro . resolveUrl ( '/' ) ) ;
39
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-false' ) ;
77
+ await expectUrlNotPrefetched ( '/prefetch-false' , page ) ;
40
78
} ) ;
41
79
42
80
test ( 'Link with search param should prefetch' , async ( { page, astro } ) => {
43
81
await page . goto ( astro . resolveUrl ( '/' ) ) ;
44
- expect ( reqUrls ) . not . toContainEqual ( '/?search-param=true' ) ;
82
+ await expectUrlNotPrefetched ( '/?search-param=true' , page ) ;
45
83
await Promise . all ( [
46
84
page . waitForEvent ( 'request' ) , // wait prefetch request
47
85
page . locator ( '#prefetch-search-param' ) . hover ( ) ,
48
86
] ) ;
49
- expect ( reqUrls ) . toContainEqual ( '/?search-param=true' ) ;
87
+ await expectUrlPrefetched ( '/?search-param=true' , page ) ;
50
88
} ) ;
51
89
52
90
test ( 'data-astro-prefetch="tap" should prefetch on tap' , async ( { page, astro } ) => {
@@ -61,52 +99,47 @@ test.describe('Prefetch (default)', () => {
61
99
62
100
test ( 'data-astro-prefetch="hover" should prefetch on hover' , async ( { page, astro } ) => {
63
101
await page . goto ( astro . resolveUrl ( '/' ) ) ;
64
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-hover' ) ;
102
+ await expectUrlNotPrefetched ( '/prefetch-hover' , page ) ;
65
103
await Promise . all ( [
66
104
page . waitForEvent ( 'request' ) , // wait prefetch request
67
105
page . locator ( '#prefetch-hover' ) . hover ( ) ,
68
106
] ) ;
69
- expect ( reqUrls ) . toContainEqual ( '/prefetch-hover' ) ;
107
+ await expectUrlPrefetched ( '/prefetch-hover' , page ) ;
70
108
} ) ;
71
109
72
110
test ( 'data-astro-prefetch="viewport" should prefetch on viewport' , async ( { page, astro } ) => {
73
111
await page . goto ( astro . resolveUrl ( '/' ) ) ;
74
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-viewport' ) ;
112
+ await expectUrlNotPrefetched ( '/prefetch-viewport' , page ) ;
75
113
// Scroll down to show the element
76
114
await Promise . all ( [
77
115
page . waitForEvent ( 'request' ) , // wait prefetch request
78
116
page . locator ( '#prefetch-viewport' ) . scrollIntoViewIfNeeded ( ) ,
79
117
] ) ;
80
- expect ( reqUrls ) . toContainEqual ( '/prefetch-viewport' ) ;
81
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-viewport"]' ) ) . toBeDefined ( ) ;
118
+ await expectUrlPrefetched ( '/prefetch-viewport' , page ) ;
82
119
} ) ;
83
120
84
121
test ( 'manual prefetch() works once' , async ( { page, astro } ) => {
85
122
await page . goto ( astro . resolveUrl ( '/' ) ) ;
86
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-manual' ) ;
123
+ await expectUrlNotPrefetched ( '/prefetch-manual' , page ) ;
87
124
await Promise . all ( [
88
125
page . waitForEvent ( 'request' ) , // wait prefetch request
89
126
page . locator ( '#prefetch-manual' ) . click ( ) ,
90
127
] ) ;
91
- expect ( reqUrls ) . toContainEqual ( '/prefetch-manual' ) ;
92
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-manual"]' ) ) . toBeDefined ( ) ;
128
+ await expectUrlPrefetched ( '/prefetch-manual' , page ) ;
93
129
94
130
// prefetch again should have no effect
95
131
await page . locator ( '#prefetch-manual' ) . click ( ) ;
96
- expect ( reqUrls . filter ( ( u ) => u . includes ( '/prefetch-manual' ) ) . length ) . toEqual ( 1 ) ;
132
+ await expectUrlPrefetched ( '/prefetch-manual' , page , 1 ) ;
97
133
} ) ;
98
134
99
135
test ( 'data-astro-prefetch="load" should prefetch' , async ( { page, astro } ) => {
100
136
await page . goto ( astro . resolveUrl ( '/' ) ) ;
101
- expect ( reqUrls ) . toContainEqual ( '/prefetch-load' ) ;
102
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-load"]' ) ) . toBeDefined ( ) ;
137
+ await expectUrlPrefetched ( '/prefetch-load' , page ) ;
103
138
} ) ;
104
139
} ) ;
105
140
106
141
test . describe ( "Prefetch (prefetchAll: true, defaultStrategy: 'tap')" , ( ) => {
107
142
let devServer ;
108
- /** @type {string[] } */
109
- const reqUrls = [ ] ;
110
143
111
144
test . beforeAll ( async ( { astro } ) => {
112
145
devServer = await astro . startDevServer ( {
@@ -117,89 +150,74 @@ test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'tap')", () => {
117
150
} ) ;
118
151
} ) ;
119
152
120
- test . beforeEach ( async ( { page } ) => {
121
- page . on ( 'request' , ( req ) => {
122
- const urlObj = new URL ( req . url ( ) ) ;
123
- reqUrls . push ( urlObj . pathname + urlObj . search ) ;
124
- } ) ;
125
- } ) ;
126
-
127
- test . afterEach ( ( ) => {
128
- reqUrls . length = 0 ;
129
- } ) ;
130
-
131
153
test . afterAll ( async ( ) => {
132
154
await devServer . stop ( ) ;
133
155
} ) ;
134
156
135
157
test ( 'Link without data-astro-prefetch should prefetch' , async ( { page, astro } ) => {
136
158
await page . goto ( astro . resolveUrl ( '/' ) ) ;
137
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-default' ) ;
159
+ await expectUrlNotPrefetched ( '/prefetch-default' , page ) ;
138
160
await Promise . all ( [
139
161
page . waitForEvent ( 'request' ) , // wait prefetch request
140
162
page . locator ( '#prefetch-default' ) . click ( ) ,
141
163
] ) ;
142
- expect ( reqUrls ) . toContainEqual ( '/prefetch-default' ) ;
164
+ await expectUrlPrefetched ( '/prefetch-default' , page ) ;
143
165
} ) ;
144
166
145
167
test ( 'data-astro-prefetch="false" should not prefetch' , async ( { page, astro } ) => {
146
168
await page . goto ( astro . resolveUrl ( '/' ) ) ;
147
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-false' ) ;
169
+ await expectUrlNotPrefetched ( '/prefetch-false' , page ) ;
148
170
} ) ;
149
171
150
172
test ( 'Link with search param should prefetch' , async ( { page, astro } ) => {
151
173
await page . goto ( astro . resolveUrl ( '/' ) ) ;
152
- expect ( reqUrls ) . not . toContainEqual ( '/?search-param=true' ) ;
174
+ await expectUrlNotPrefetched ( '/?search-param=true' , page ) ;
153
175
await Promise . all ( [
154
176
page . waitForEvent ( 'request' ) , // wait prefetch request
155
177
page . locator ( '#prefetch-search-param' ) . hover ( ) ,
156
178
] ) ;
157
- expect ( reqUrls ) . toContainEqual ( '/?search-param=true' ) ;
179
+ await expectUrlPrefetched ( '/?search-param=true' , page ) ;
158
180
} ) ;
159
181
160
182
test ( 'data-astro-prefetch="tap" should prefetch on tap' , async ( { page, astro } ) => {
161
183
await page . goto ( astro . resolveUrl ( '/' ) ) ;
162
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-tap' ) ;
184
+ await expectUrlNotPrefetched ( '/prefetch-tap' , page ) ;
163
185
await Promise . all ( [
164
186
page . waitForEvent ( 'request' ) , // wait prefetch request
165
187
page . locator ( '#prefetch-tap' ) . click ( ) ,
166
188
] ) ;
167
- expect ( reqUrls ) . toContainEqual ( '/prefetch-tap' ) ;
189
+ await expectUrlPrefetched ( '/prefetch-tap' , page ) ;
168
190
} ) ;
169
191
170
192
test ( 'data-astro-prefetch="hover" should prefetch on hover' , async ( { page, astro } ) => {
171
193
await page . goto ( astro . resolveUrl ( '/' ) ) ;
172
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-hover' ) ;
194
+ await expectUrlNotPrefetched ( '/prefetch-hover' , page ) ;
173
195
await Promise . all ( [
174
196
page . waitForEvent ( 'request' ) , // wait prefetch request
175
197
page . locator ( '#prefetch-hover' ) . hover ( ) ,
176
198
] ) ;
177
- expect ( reqUrls ) . toContainEqual ( '/prefetch-hover' ) ;
199
+ await expectUrlPrefetched ( '/prefetch-hover' , page ) ;
178
200
} ) ;
179
201
180
202
test ( 'data-astro-prefetch="viewport" should prefetch on viewport' , async ( { page, astro } ) => {
181
203
await page . goto ( astro . resolveUrl ( '/' ) ) ;
182
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-viewport' ) ;
204
+ await expectUrlNotPrefetched ( '/prefetch-viewport' , page ) ;
183
205
// Scroll down to show the element
184
206
await Promise . all ( [
185
207
page . waitForEvent ( 'request' ) , // wait prefetch request
186
208
page . locator ( '#prefetch-viewport' ) . scrollIntoViewIfNeeded ( ) ,
187
209
] ) ;
188
- expect ( reqUrls ) . toContainEqual ( '/prefetch-viewport' ) ;
189
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-viewport"]' ) ) . toBeDefined ( ) ;
210
+ await expectUrlPrefetched ( '/prefetch-viewport' , page ) ;
190
211
} ) ;
191
212
192
213
test ( 'data-astro-prefetch="load" should prefetch' , async ( { page, astro } ) => {
193
214
await page . goto ( astro . resolveUrl ( '/' ) ) ;
194
- expect ( reqUrls ) . toContainEqual ( '/prefetch-load' ) ;
195
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-load"]' ) ) . toBeDefined ( ) ;
215
+ await expectUrlPrefetched ( '/prefetch-load' , page ) ;
196
216
} ) ;
197
217
} ) ;
198
218
199
219
test . describe ( "Prefetch (prefetchAll: true, defaultStrategy: 'load')" , ( ) => {
200
220
let devServer ;
201
- /** @type {string[] } */
202
- const reqUrls = [ ] ;
203
221
204
222
test . beforeAll ( async ( { astro } ) => {
205
223
devServer = await astro . startDevServer ( {
@@ -210,78 +228,64 @@ test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'load')", () => {
210
228
} ) ;
211
229
} ) ;
212
230
213
- test . beforeEach ( async ( { page } ) => {
214
- page . on ( 'request' , ( req ) => {
215
- const urlObj = new URL ( req . url ( ) ) ;
216
- reqUrls . push ( urlObj . pathname + urlObj . search ) ;
217
- } ) ;
218
- } ) ;
219
-
220
- test . afterEach ( ( ) => {
221
- reqUrls . length = 0 ;
222
- } ) ;
223
-
224
231
test . afterAll ( async ( ) => {
225
232
await devServer . stop ( ) ;
226
233
} ) ;
227
234
228
235
test ( 'Link without data-astro-prefetch should prefetch' , async ( { page, astro } ) => {
229
236
await page . goto ( astro . resolveUrl ( '/' ) ) ;
230
- expect ( reqUrls ) . toContainEqual ( '/prefetch-default' ) ;
231
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-default"]' ) ) . toBeDefined ( ) ;
237
+ await expectUrlPrefetched ( '/prefetch-default' , page ) ;
232
238
} ) ;
233
239
234
240
test ( 'data-astro-prefetch="false" should not prefetch' , async ( { page, astro } ) => {
235
241
await page . goto ( astro . resolveUrl ( '/' ) ) ;
236
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-false' ) ;
242
+ await expectUrlNotPrefetched ( '/prefetch-false' , page ) ;
237
243
} ) ;
238
244
239
245
test ( 'Link with search param should prefetch' , async ( { page, astro } ) => {
240
246
await page . goto ( astro . resolveUrl ( '/' ) ) ;
241
- expect ( reqUrls ) . not . toContainEqual ( '/?search-param=true' ) ;
247
+ await expectUrlNotPrefetched ( '/?search-param=true' , page ) ;
242
248
await Promise . all ( [
243
249
page . waitForEvent ( 'request' ) , // wait prefetch request
244
250
page . locator ( '#prefetch-search-param' ) . hover ( ) ,
245
251
] ) ;
246
- expect ( reqUrls ) . toContainEqual ( '/?search-param=true' ) ;
252
+ await expectUrlPrefetched ( '/?search-param=true' , page ) ;
247
253
} ) ;
248
254
249
255
test ( 'data-astro-prefetch="tap" should prefetch on tap' , async ( { page, astro } ) => {
250
256
await page . goto ( astro . resolveUrl ( '/' ) ) ;
251
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-tap' ) ;
257
+ await expectUrlNotPrefetched ( '/prefetch-tap' , page ) ;
252
258
await Promise . all ( [
253
259
page . waitForEvent ( 'request' ) , // wait prefetch request
254
260
page . locator ( '#prefetch-tap' ) . click ( ) ,
255
261
] ) ;
256
- expect ( reqUrls ) . toContainEqual ( '/prefetch-tap' ) ;
262
+ await expectUrlPrefetched ( '/prefetch-tap' , page ) ;
257
263
} ) ;
258
264
259
265
test ( 'data-astro-prefetch="hover" should prefetch on hover' , async ( { page, astro } ) => {
260
266
await page . goto ( astro . resolveUrl ( '/' ) ) ;
261
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-hover' ) ;
267
+ await expectUrlNotPrefetched ( '/prefetch-hover' , page ) ;
262
268
await Promise . all ( [
263
269
page . waitForEvent ( 'request' ) , // wait prefetch request
264
270
page . locator ( '#prefetch-hover' ) . hover ( ) ,
265
271
] ) ;
266
- expect ( reqUrls ) . toContainEqual ( '/prefetch-hover' ) ;
272
+ await expectUrlPrefetched ( '/prefetch-hover' , page ) ;
267
273
} ) ;
268
274
269
275
test ( 'data-astro-prefetch="viewport" should prefetch on viewport' , async ( { page, astro } ) => {
270
276
await page . goto ( astro . resolveUrl ( '/' ) ) ;
271
- expect ( reqUrls ) . not . toContainEqual ( '/prefetch-viewport' ) ;
277
+ await expectUrlNotPrefetched ( '/prefetch-viewport' , page ) ;
272
278
// Scroll down to show the element
273
279
await Promise . all ( [
274
280
page . waitForEvent ( 'request' ) , // wait prefetch request
275
281
page . locator ( '#prefetch-viewport' ) . scrollIntoViewIfNeeded ( ) ,
276
282
] ) ;
277
- expect ( reqUrls ) . toContainEqual ( '/prefetch-viewport' ) ;
278
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-viewport"]' ) ) . toBeDefined ( ) ;
283
+ await expectUrlPrefetched ( '/prefetch-viewport' , page ) ;
279
284
} ) ;
280
285
281
286
test ( 'data-astro-prefetch="load" should prefetch' , async ( { page, astro } ) => {
282
287
await page . goto ( astro . resolveUrl ( '/' ) ) ;
283
- expect ( reqUrls ) . toContainEqual ( '/prefetch-load' ) ;
284
- expect ( page . locator ( 'link[rel="prefetch"][href$="/prefetch-load"]' ) ) . toBeDefined ( ) ;
288
+ await expectUrlPrefetched ( '/prefetch-load' , page ) ;
285
289
} ) ;
286
290
} ) ;
287
291
@@ -311,7 +315,9 @@ test.describe('Prefetch (default), Experimental ({ clientPrerender: true })', ()
311
315
312
316
let devServer ;
313
317
314
- test . beforeAll ( async ( { astro } ) => {
318
+ test . beforeAll ( async ( { astro, browserName } ) => {
319
+ test . skip ( browserName !== 'chromium' , 'Only Chromium supports clientPrerender' )
320
+
315
321
devServer = await astro . startDevServer ( {
316
322
experimental : {
317
323
clientPrerender : true ,
@@ -320,7 +326,7 @@ test.describe('Prefetch (default), Experimental ({ clientPrerender: true })', ()
320
326
} ) ;
321
327
322
328
test . afterAll ( async ( ) => {
323
- await devServer . stop ( ) ;
329
+ await devServer ? .stop ( ) ;
324
330
} ) ;
325
331
326
332
test ( 'Link without data-astro-prefetch should not prefetch' , async ( { page, astro } ) => {
0 commit comments