11import { mkdirSync , mkdtempSync , rmSync , writeFileSync } from 'node:fs' ;
22import { dirname , join } from 'node:path' ;
3- import { chromium } from 'playwright' ;
4- import { preview } from 'vite' ;
3+ import { chromium , type Browser } from 'playwright' ;
4+ import { preview , type PreviewServer } from 'vite' ;
55import solid from 'vite-plugin-solid' ;
6- import { describe , expect , it } from 'vite-plus/test' ;
6+ import { afterAll , beforeAll , describe , expect , it } from 'vite-plus/test' ;
77import { collectBrowserDiagnostics } from '../../../../test/browser-helpers.ts' ;
88import { buildIslandApp } from '../../../../test/island-css-build.ts' ;
99import { openIslandPage , type IslandPageVisit } from '../../../../test/island-page-browser.ts' ;
@@ -69,12 +69,7 @@ export default function Page() {
6969}` ,
7070} ;
7171
72- async function visitFixture (
73- production : boolean ,
74- ) : Promise < { visit : IslandPageVisit ; close ( ) : Promise < void > } > {
75- if ( production ) {
76- return visitProductionFixture ( ) ;
77- }
72+ async function visitFixture ( ) : Promise < { visit : IslandPageVisit ; close ( ) : Promise < void > } > {
7873 const root = mkdtempSync ( join ( import . meta. dirname , '__tmp_island_hydration_' ) ) ;
7974 for ( const [ file , content ] of Object . entries ( files ) ) {
8075 mkdirSync ( dirname ( join ( root , file ) ) , { recursive : true } ) ;
@@ -98,32 +93,20 @@ async function visitFixture(
9893 }
9994}
10095
101- async function visitProductionFixture ( ) : Promise < {
96+ async function visitProductionFixture (
97+ browser : Browser ,
98+ base : string ,
99+ ) : Promise < {
102100 visit : IslandPageVisit ;
103101 close ( ) : Promise < void > ;
104102} > {
105- const build = buildIslandApp ( {
106- packageDir : join ( import . meta. dirname , '../..' ) ,
107- pluginName : 'voidSolid' ,
108- files,
109- } ) ;
110- const server = await preview ( {
111- root : build . root ,
112- configFile : false ,
113- logLevel : 'silent' ,
114- build : { outDir : 'dist/client' } ,
115- preview : { host : '127.0.0.1' , port : 0 } ,
116- } ) ;
117- const browser = await chromium . launch ( ) ;
118- const close = async ( ) => {
119- await browser . close ( ) ;
120- await server . close ( ) ;
121- build . cleanup ( ) ;
122- } ;
103+ const context = await browser . newContext ( ) ;
104+ const close = ( ) => context . close ( ) ;
123105 try {
124- const page = await browser . newPage ( ) ;
106+ const page = await context . newPage ( ) ;
107+ page . setDefaultTimeout ( 10_000 ) ;
125108 const diagnostics = collectBrowserDiagnostics ( page ) ;
126- const response = await page . goto ( server . resolvedUrls ! . local [ 0 ] ) ;
109+ const response = await page . goto ( base ) ;
127110 const visit = { page, diagnostics, html : await response ! . text ( ) , close } ;
128111 return { visit, close } ;
129112 } catch ( error ) {
@@ -164,24 +147,62 @@ async function expectReused(visit: IslandPageVisit, name: string): Promise<void>
164147}
165148
166149describe . each ( [ 'dev' , 'production' ] ) ( '%s island hydration' , ( mode ) => {
150+ let productionBuild : ReturnType < typeof buildIslandApp > | undefined ;
151+ let productionServer : PreviewServer | undefined ;
152+ let productionBrowser : Browser | undefined ;
153+
154+ beforeAll ( async ( ) => {
155+ if ( mode === 'production' ) {
156+ productionBuild = buildIslandApp ( {
157+ packageDir : join ( import . meta. dirname , '../..' ) ,
158+ pluginName : 'voidSolid' ,
159+ files,
160+ } ) ;
161+ productionServer = await preview ( {
162+ root : productionBuild . root ,
163+ configFile : false ,
164+ logLevel : 'silent' ,
165+ build : { outDir : 'dist/client' } ,
166+ preview : { host : '127.0.0.1' , port : 0 } ,
167+ } ) ;
168+ productionBrowser = await chromium . launch ( ) ;
169+ }
170+ } ) ;
171+
172+ afterAll ( async ( ) => {
173+ await productionBrowser ?. close ( ) ;
174+ await productionServer ?. close ( ) ;
175+ productionBuild ?. cleanup ( ) ;
176+ } ) ;
177+
178+ function newFixture ( ) {
179+ return mode === 'production'
180+ ? visitProductionFixture ( productionBrowser ! , productionServer ! . resolvedUrls ! . local [ 0 ] )
181+ : visitFixture ( ) ;
182+ }
183+
167184 it ( 'reuses SSR DOM and preserves input in repeated islands and an island layout' , async ( ) => {
168- const fixture = await visitFixture ( mode === 'production' ) ;
185+ const fixture = await newFixture ( ) ;
169186 try {
170187 for ( const name of [ 'layout' , 'first' , 'second' ] ) {
171188 await expectReused ( fixture . visit , name ) ;
172189 }
173190 const { page } = fixture . visit ;
174191 await page . locator ( '[data-counter="first"] button' ) . click ( ) ;
175- expect ( await page . locator ( '[data-counter="first"] button' ) . textContent ( ) ) . toBe ( '1' ) ;
176- expect ( await page . locator ( '[data-counter="second"] button' ) . textContent ( ) ) . toBe ( '10' ) ;
192+ await expect
193+ . poll ( ( ) => page . locator ( '[data-counter="first"] button' ) . textContent ( ) )
194+ . toBe ( '1' ) ;
195+ await expect
196+ . poll ( ( ) => page . locator ( '[data-counter="second"] button' ) . textContent ( ) )
197+ . toBe ( '10' ) ;
177198 expect ( fixture . visit . diagnostics ( ) ) . not . toContain ( 'pageerror' ) ;
178199 } finally {
179200 await fixture . close ( ) ;
180201 }
181202 } ) ;
182203
183204 it ( 'hydrates visible islands in reverse order after another island handles an event' , async ( ) => {
184- const fixture = await visitFixture ( mode === 'production' ) ;
205+ const fixture = await newFixture ( ) ;
185206 try {
186207 const { page } = fixture . visit ;
187208 await page . waitForSelector ( '[data-counter="first"]' ) ;
@@ -201,9 +222,9 @@ describe.each(['dev', 'production'])('%s island hydration', (mode) => {
201222 await page . locator ( `[data-counter="${ name } "]` ) . scrollIntoViewIfNeeded ( ) ;
202223 await expectReused ( fixture . visit , name ) ;
203224 await page . locator ( `[data-counter="${ name } "] button` ) . click ( ) ;
204- expect ( await page . locator ( `[data-counter=" ${ name } "] button` ) . textContent ( ) ) . toBe (
205- String ( initial + 1 ) ,
206- ) ;
225+ await expect
226+ . poll ( ( ) => page . locator ( `[data-counter=" ${ name } "] button` ) . textContent ( ) )
227+ . toBe ( String ( initial + 1 ) ) ;
207228 }
208229 expect ( fixture . visit . diagnostics ( ) ) . not . toContain ( 'pageerror' ) ;
209230 } finally {
@@ -212,13 +233,13 @@ describe.each(['dev', 'production'])('%s island hydration', (mode) => {
212233 } ) ;
213234
214235 it ( 'hydrates an async resource inside Suspense without replacing the resolved SSR DOM' , async ( ) => {
215- const fixture = await visitFixture ( mode === 'production' ) ;
236+ const fixture = await newFixture ( ) ;
216237 try {
217238 expect ( fixture . visit . html ) . toContain ( 'data-counter="async"' ) ;
218239 await expectReused ( fixture . visit , 'async' ) ;
219240 const button = fixture . visit . page . locator ( '[data-counter="async"] button' ) ;
220241 await button . click ( ) ;
221- expect ( await button . textContent ( ) ) . toBe ( '51' ) ;
242+ await expect . poll ( ( ) => button . textContent ( ) ) . toBe ( '51' ) ;
222243 expect ( fixture . visit . diagnostics ( ) ) . not . toContain ( 'pageerror' ) ;
223244 } finally {
224245 await fixture . close ( ) ;
0 commit comments