@@ -18,6 +18,9 @@ import type {
1818 TestProject ,
1919} from 'vitest/node'
2020import { createManualModuleSource } from '@vitest/mocker/node'
21+ import { createDebugger } from 'vitest/node'
22+
23+ const debug = createDebugger ( 'vitest:browser:playwright' )
2124
2225export const playwrightBrowsers = [ 'firefox' , 'webkit' , 'chromium' ] as const
2326export type PlaywrightBrowser = ( typeof playwrightBrowsers ) [ number ]
@@ -48,6 +51,8 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
4851
4952 public mocker : BrowserModuleMocker | undefined
5053
54+ private closing = false
55+
5156 getSupportedBrowsers ( ) : readonly string [ ] {
5257 return playwrightBrowsers
5358 }
@@ -56,18 +61,23 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
5661 project : TestProject ,
5762 { browser, options } : PlaywrightProviderOptions ,
5863 ) : void {
64+ this . closing = false
5965 this . project = project
6066 this . browserName = browser
6167 this . options = options as any
6268 this . mocker = this . createMocker ( )
6369 }
6470
6571 private async openBrowser ( ) {
72+ await this . _throwIfClosing ( )
73+
6674 if ( this . browserPromise ) {
75+ debug ?.( '[%s] the browser is resolving, reusing the promise' , this . browserName )
6776 return this . browserPromise
6877 }
6978
7079 if ( this . browser ) {
80+ debug ?.( '[%s] the browser is resolved, reusing it' , this . browserName )
7181 return this . browser
7282 }
7383
@@ -103,8 +113,8 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
103113 }
104114 }
105115
106- const browser = await playwright [ this . browserName ] . launch ( launchOptions )
107- this . browser = browser
116+ debug ?. ( '[%s] initializing the browser with launch options: %O' , this . browserName , launchOptions )
117+ this . browser = await playwright [ this . browserName ] . launch ( launchOptions )
108118 this . browserPromise = null
109119 return this . browser
110120 } ) ( )
@@ -243,11 +253,15 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
243253 }
244254
245255 private async createContext ( sessionId : string ) {
256+ await this . _throwIfClosing ( )
257+
246258 if ( this . contexts . has ( sessionId ) ) {
259+ debug ?.( '[%s][%s] the context already exists, reusing it' , sessionId , this . browserName )
247260 return this . contexts . get ( sessionId ) !
248261 }
249262
250263 const browser = await this . openBrowser ( )
264+ await this . _throwIfClosing ( browser )
251265 const { actionTimeout, ...contextOptions } = this . options ?. context ?? { }
252266 const options = {
253267 ...contextOptions ,
@@ -257,9 +271,11 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
257271 options . viewport = null
258272 }
259273 const context = await browser . newContext ( options )
274+ await this . _throwIfClosing ( context )
260275 if ( actionTimeout ) {
261276 context . setDefaultTimeout ( actionTimeout )
262277 }
278+ debug ?.( '[%s][%s] the context is ready' , sessionId , this . browserName )
263279 this . contexts . set ( sessionId , context )
264280 return context
265281 }
@@ -306,14 +322,19 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
306322 }
307323
308324 private async openBrowserPage ( sessionId : string ) {
325+ await this . _throwIfClosing ( )
326+
309327 if ( this . pages . has ( sessionId ) ) {
328+ debug ?.( '[%s][%s] the page already exists, closing the old one' , sessionId , this . browserName )
310329 const page = this . pages . get ( sessionId ) !
311330 await page . close ( )
312331 this . pages . delete ( sessionId )
313332 }
314333
315334 const context = await this . createContext ( sessionId )
316335 const page = await context . newPage ( )
336+ debug ?.( '[%s][%s] the page is ready' , sessionId , this . browserName )
337+ await this . _throwIfClosing ( page )
317338 this . pages . set ( sessionId , page )
318339
319340 if ( process . env . VITEST_PW_DEBUG ) {
@@ -333,9 +354,24 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
333354 }
334355
335356 async openPage ( sessionId : string , url : string , beforeNavigate ?: ( ) => Promise < void > ) : Promise < void > {
357+ debug ?.( '[%s][%s] creating the browser page for %s' , sessionId , this . browserName , url )
336358 const browserPage = await this . openBrowserPage ( sessionId )
337359 await beforeNavigate ?.( )
360+ debug ?.( '[%s][%s] browser page is created, opening %s' , sessionId , this . browserName , url )
338361 await browserPage . goto ( url , { timeout : 0 } )
362+ await this . _throwIfClosing ( browserPage )
363+ }
364+
365+ private async _throwIfClosing ( disposable ?: { close : ( ) => Promise < void > } ) {
366+ if ( this . closing ) {
367+ debug ?.( '[%s] provider was closed, cannot perform the action on %s' , this . browserName , String ( disposable ) )
368+ await disposable ?. close ( )
369+ this . pages . clear ( )
370+ this . contexts . clear ( )
371+ this . browser = null
372+ this . browserPromise = null
373+ throw new Error ( `[vitest] The provider was closed.` )
374+ }
339375 }
340376
341377 async getCDPSession ( sessionid : string ) : Promise < CDPSession > {
@@ -359,13 +395,20 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
359395 }
360396
361397 async close ( ) : Promise < void > {
398+ debug ?.( '[%s] closing provider' , this . browserName )
399+ this . closing = true
362400 const browser = this . browser
363401 this . browser = null
402+ if ( this . browserPromise ) {
403+ await this . browserPromise
404+ this . browserPromise = null
405+ }
364406 await Promise . all ( [ ...this . pages . values ( ) ] . map ( p => p . close ( ) ) )
365407 this . pages . clear ( )
366408 await Promise . all ( [ ...this . contexts . values ( ) ] . map ( c => c . close ( ) ) )
367409 this . contexts . clear ( )
368410 await browser ?. close ( )
411+ debug ?.( '[%s] provider is closed' , this . browserName )
369412 }
370413}
371414
0 commit comments