1- import { chromium } from '@playwright/test'
21import {
32 e2eStartDummyServer ,
43 getTestServerPort ,
4+ preOptimizeDevServer ,
5+ waitForServer ,
56} from '@tanstack/router-e2e-utils'
67import packageJson from '../../package.json' with { type : 'json' }
78
8- async function waitForServer ( url : string ) {
9- const start = Date . now ( )
10- while ( Date . now ( ) - start < 30_000 ) {
11- const controller = new AbortController ( )
12- const timer = setTimeout ( ( ) => controller . abort ( ) , 5_000 )
13- try {
14- const res = await fetch ( url , {
15- redirect : 'manual' ,
16- signal : controller . signal ,
17- } )
18- if ( res . status >= 200 && res . status < 400 ) return
19- } catch {
20- // ignore aborted/network errors
21- } finally {
22- clearTimeout ( timer )
23- }
24- await new Promise ( ( r ) => setTimeout ( r , 250 ) )
25- }
26- throw new Error ( `Timed out waiting for dev server at ${ url } ` )
27- }
28-
29- async function preOptimizeDevServer ( baseURL : string ) {
30- const browser = await chromium . launch ( )
31- const context = await browser . newContext ( )
32- const page = await context . newPage ( )
33-
34- try {
35- await page . goto ( `${ baseURL } /` , { waitUntil : 'domcontentloaded' } )
36- await page . getByTestId ( 'global-styled' ) . waitFor ( { state : 'visible' } )
37- await page . waitForLoadState ( 'networkidle' )
38-
39- await page . goto ( `${ baseURL } /modules` , { waitUntil : 'domcontentloaded' } )
40- await page . getByTestId ( 'module-card' ) . waitFor ( { state : 'visible' } )
41- await page . waitForLoadState ( 'networkidle' )
42-
43- await page . goto ( `${ baseURL } /sass-mixin` , { waitUntil : 'domcontentloaded' } )
44- await page . getByTestId ( 'mixin-styled' ) . waitFor ( { state : 'visible' } )
45- await page . waitForLoadState ( 'networkidle' )
46-
47- await page . goto ( `${ baseURL } /quotes` , { waitUntil : 'domcontentloaded' } )
48- await page . getByTestId ( 'quote-styled' ) . waitFor ( { state : 'visible' } )
49- await page . getByTestId ( 'after-quote-styled' ) . waitFor ( { state : 'visible' } )
50- await page . waitForLoadState ( 'networkidle' )
51-
52- // Exercise client-side navigation so Vite discovers any remaining deps
53- // that only load via the client router (not full-page navigations).
54- await page . goto ( `${ baseURL } /` , { waitUntil : 'domcontentloaded' } )
55- await page . getByTestId ( 'global-styled' ) . waitFor ( { state : 'visible' } )
56- await page . waitForLoadState ( 'networkidle' )
57-
58- await page . getByTestId ( 'nav-modules' ) . click ( )
59- await page . waitForURL ( '**/modules' )
60- await page . getByTestId ( 'module-card' ) . waitFor ( { state : 'visible' } )
61- await page . waitForLoadState ( 'networkidle' )
62-
63- await page . getByTestId ( 'nav-home' ) . click ( )
64- await page . waitForURL ( / \/ ( [ ^ / ] * ) ( \/ ) ? ( $ | \? ) / )
65- await page . getByTestId ( 'global-styled' ) . waitFor ( { state : 'visible' } )
66- await page . waitForLoadState ( 'networkidle' )
67-
68- // Ensure we end in a stable state. Vite's optimize step triggers a reload;
69- // this waits until no further navigations happen for a short window.
70- for ( let i = 0 ; i < 40 ; i ++ ) {
71- const currentUrl = page . url ( )
72- await page . waitForTimeout ( 250 )
73- if ( page . url ( ) === currentUrl ) {
74- await page . waitForTimeout ( 250 )
75- if ( page . url ( ) === currentUrl ) return
76- }
77- }
78-
79- throw new Error ( 'Dev server did not reach a stable URL after warmup' )
80- } finally {
81- await context . close ( )
82- await browser . close ( )
83- }
84- }
85-
869export default async function setup ( ) {
8710 await e2eStartDummyServer ( packageJson . name )
8811
@@ -96,5 +19,40 @@ export default async function setup() {
9619 const baseURL = `http://localhost:${ port } ${ basePath } `
9720
9821 await waitForServer ( baseURL )
99- await preOptimizeDevServer ( baseURL )
22+ await preOptimizeDevServer ( {
23+ baseURL,
24+ readyTestId : 'global-styled' ,
25+ warmup : async ( page ) => {
26+ await page . goto ( `${ baseURL } /modules` , { waitUntil : 'domcontentloaded' } )
27+ await page . getByTestId ( 'module-card' ) . waitFor ( { state : 'visible' } )
28+ await page . waitForLoadState ( 'networkidle' )
29+
30+ await page . goto ( `${ baseURL } /sass-mixin` , {
31+ waitUntil : 'domcontentloaded' ,
32+ } )
33+ await page . getByTestId ( 'mixin-styled' ) . waitFor ( { state : 'visible' } )
34+ await page . waitForLoadState ( 'networkidle' )
35+
36+ await page . goto ( `${ baseURL } /quotes` , { waitUntil : 'domcontentloaded' } )
37+ await page . getByTestId ( 'quote-styled' ) . waitFor ( { state : 'visible' } )
38+ await page . getByTestId ( 'after-quote-styled' ) . waitFor ( {
39+ state : 'visible' ,
40+ } )
41+ await page . waitForLoadState ( 'networkidle' )
42+
43+ await page . goto ( `${ baseURL } /` , { waitUntil : 'domcontentloaded' } )
44+ await page . getByTestId ( 'global-styled' ) . waitFor ( { state : 'visible' } )
45+ await page . waitForLoadState ( 'networkidle' )
46+
47+ await page . getByTestId ( 'nav-modules' ) . click ( )
48+ await page . waitForURL ( '**/modules' )
49+ await page . getByTestId ( 'module-card' ) . waitFor ( { state : 'visible' } )
50+ await page . waitForLoadState ( 'networkidle' )
51+
52+ await page . getByTestId ( 'nav-home' ) . click ( )
53+ await page . waitForURL ( / \/ ( [ ^ / ] * ) ( \/ ) ? ( $ | \? ) / )
54+ await page . getByTestId ( 'global-styled' ) . waitFor ( { state : 'visible' } )
55+ await page . waitForLoadState ( 'networkidle' )
56+ } ,
57+ } )
10058}
0 commit comments