/** * 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 { Connection } from './client/connection'; import { Transport } from './protocol/transport'; import { Playwright } from './client/playwright'; import * as childProcess from 'child_process'; import * as path from 'path'; export async function start() { const client = new PlaywrightClient(); const playwright = await client._playwright; (playwright as any).stop = () => client.stop(); (playwright as any).driverProcess = client._driverProcess; return playwright; } class PlaywrightClient { _playwright: Promise; _driverProcess: childProcess.ChildProcess; private _closePromise: Promise; private _onExit: (exitCode: number | null, signal: string | null) => {}; constructor() { this._onExit = (exitCode: number | null, signal: string | null) => { throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`); }; this._driverProcess = childProcess.fork(path.join(__dirname, 'cli', 'cli.js'), ['run-driver'], { stdio: 'pipe', detached: true, }); this._driverProcess.unref(); this._driverProcess.on('exit', this._onExit); const connection = new Connection(); const transport = new Transport(this._driverProcess.stdin, this._driverProcess.stdout); connection.onmessage = message => transport.send(JSON.stringify(message)); transport.onmessage = message => connection.dispatch(JSON.parse(message)); this._closePromise = new Promise(f => transport.onclose = f); this._playwright = connection.waitForObjectWithKnownName('Playwright'); } async stop() { this._driverProcess.removeListener('exit', this._onExit); this._driverProcess.stdin.destroy(); this._driverProcess.stdout.destroy(); this._driverProcess.stderr.destroy(); await this._closePromise; } }