diff --git a/packages/playwright-core/src/server/electron/loader.ts b/packages/playwright-core/src/server/electron/loader.ts index b95687083ca2f..862c344402328 100644 --- a/packages/playwright-core/src/server/electron/loader.ts +++ b/packages/playwright-core/src/server/electron/loader.ts @@ -32,6 +32,25 @@ for (const arg of chromiumSwitches) { app.getAppPath = () => path.dirname(appPath); } -(globalThis as any).__playwright_run = () => { +let launchInfoEventPayload: any; +app.on('ready', launchInfo => launchInfoEventPayload = launchInfo); + +(globalThis as any).__playwright_run = async () => { + // Wait for app to be ready to avoid browser initialization races. + await app.whenReady(); + + // Override isReady pipeline. + let isReady = false; + let whenReadyCallback: () => void; + const whenReadyPromise = new Promise(f => whenReadyCallback = f); + app.isReady = () => isReady; + app.whenReady = () => whenReadyPromise; + require(appPath); + + // Trigger isReady. + isReady = true; + whenReadyCallback!(); + app.emit('will-finish-launching'); + app.emit('ready', launchInfoEventPayload); }; diff --git a/tests/electron/electron-app-ready-event.js b/tests/electron/electron-app-ready-event.js new file mode 100644 index 0000000000000..e7fbd1c93fc8d --- /dev/null +++ b/tests/electron/electron-app-ready-event.js @@ -0,0 +1,12 @@ +const { app } = require('electron'); + +globalThis.__playwrightLog = []; + +globalThis.__playwrightLog.push(`isReady == ${app.isReady()}`); +app.whenReady().then(() => { + globalThis.__playwrightLog.push(`whenReady resolved`); + globalThis.__playwrightLog.push(`isReady == ${app.isReady()}`); +}); + +app.on('will-finish-launching', () => globalThis.__playwrightLog.push('will-finish-launching fired')); +app.on('ready', () => globalThis.__playwrightLog.push('ready fired')); diff --git a/tests/electron/electron-app.spec.ts b/tests/electron/electron-app.spec.ts index 9fc88906a05ed..e017c0c67e7a0 100644 --- a/tests/electron/electron-app.spec.ts +++ b/tests/electron/electron-app.spec.ts @@ -33,6 +33,24 @@ test('should fire close event', async ({ playwright }) => { expect(events.join('|')).toBe('context|application'); }); +test('should dispatch ready event', async ({ playwright }) => { + const electronApp = await playwright._electron.launch({ + args: [path.join(__dirname, 'electron-app-ready-event.js')], + }); + try { + const events = await electronApp.evaluate(() => globalThis.__playwrightLog); + expect(events).toEqual([ + 'isReady == false', + 'will-finish-launching fired', + 'ready fired', + 'whenReady resolved', + 'isReady == true', + ]); + } finally { + await electronApp.close(); + } +}); + test('should script application', async ({ electronApp }) => { const appPath = await electronApp.evaluate(async ({ app }) => app.getAppPath()); expect(appPath).toBe(path.resolve(__dirname));