diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index 3b00333a0d..9090371a58 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import * as path from 'path'; import * as os from 'os'; import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser'; import { CRConnection, CRSession } from '../chromium/crConnection'; @@ -77,17 +76,18 @@ export class ElectronApplication extends EventEmitter { private async _onPage(page: ElectronPage) { // Needs to be sync. const windowId = ++this._lastWindowId; - // Can be async. - const handle = await this._nodeElectronHandle!.evaluateHandle(({ BrowserWindow }, windowId) => BrowserWindow.fromId(windowId), windowId).catch(e => {}); - if (!handle) - return; - page.browserWindow = handle; - page._browserWindowId = windowId; page.on(Page.Events.Close, () => { page.browserWindow.dispose(); this._windows.delete(page); }); + page._browserWindowId = windowId; this._windows.add(page); + + // Below is async. + const handle = await this._nodeElectronHandle!.evaluateHandle(({ BrowserWindow }, windowId) => BrowserWindow.fromId(windowId), windowId).catch(e => {}); + if (!handle) + return; + page.browserWindow = handle; await runAbortableTask(progress => page.mainFrame()._waitForLoadState(progress, 'domcontentloaded'), page._timeoutSettings.navigationTimeout({})).catch(e => {}); // can happen after detach this.emit(ElectronApplication.Events.Window, page); } @@ -126,16 +126,12 @@ export class ElectronApplication extends EventEmitter { } async _init() { - this._nodeSession.once('Runtime.executionContextCreated', event => { - this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context)); + this._nodeSession.on('Runtime.executionContextCreated', (event: any) => { + if (event.context.auxData && event.context.auxData.isDefault) + this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context)); }); await this._nodeSession.send('Runtime.enable', {}).catch(e => {}); - this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, () => { - // Resolving the race between the debugger and the boot-time script. - if ((global as any)._playwrightRun) - return (global as any)._playwrightRun(); - return new Promise(f => (global as any)._playwrightRunCallback = f); - }); + this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, `process.mainModule.require('electron')`); } } @@ -151,7 +147,7 @@ export class Electron { controller.setLogName('browser'); return controller.run(async progress => { let app: ElectronApplication | undefined = undefined; - const electronArguments = ['--inspect=0', '--remote-debugging-port=0', '--require', path.join(__dirname, 'electronLoader.js'), ...args]; + const electronArguments = ['--inspect=0', '--remote-debugging-port=0', ...args]; if (os.platform() === 'linux') { const runningAsRoot = process.geteuid && process.geteuid() === 0; @@ -171,7 +167,7 @@ export class Electron { cwd: options.cwd, tempDirectories: [], attemptToGracefullyClose: () => app!.close(), - onExit: (exitCode, signal) => {}, + onExit: () => {}, }); const nodeMatch = await waitForLine(progress, launchedProcess, launchedProcess.stderr, /^Debugger listening on (ws:\/\/.*)$/); diff --git a/src/server/electron/electronLoader.ts b/src/server/electron/electronLoader.ts deleted file mode 100644 index 178c77c752..0000000000 --- a/src/server/electron/electronLoader.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as electron from 'electron'; - -// Electron loader is passed to Electron as --require electronLoader.js and -// defers the app ready event until remote debugging is established. - -(async () => { - const app = electron.app; - const originalEmitMethod = app.emit.bind(app); - const originalIsReadyMethod = app.isReady.bind(app); - const originalWhenReadyMethod = app.whenReady.bind(app); - - const deferredEmits: { event: string | symbol, args: any[] }[] = []; - let attached = false; - let isReady = false; - let readyCallback: () => void; - const readyPromise = new Promise(f => readyCallback = f); - - app.isReady = () => { - if (attached) - return originalIsReadyMethod(); - return isReady; - }; - - app.whenReady = async () => { - if (attached) - return originalWhenReadyMethod(); - await readyPromise; - }; - - app.emit = (event: string | symbol, ...args: any[]): boolean => { - if (attached) - return originalEmitMethod(event, ...args); - deferredEmits.push({ event, args }); - return true; - }; - - const playwrightRun = () => { - while (deferredEmits.length) { - const emit = deferredEmits.shift(); - if (emit!.event === 'ready') { - isReady = true; - readyCallback(); - } - originalEmitMethod(emit!.event, ...emit!.args); - } - attached = true; - return electron; - }; - - // Resolving the race between the debugger and the boot-time script. - if ((global as any)._playwrightRunCallback) { - (global as any)._playwrightRunCallback(playwrightRun()); - return; - } - (global as any)._playwrightRun = playwrightRun; -})();