Skip to content

Commit

Permalink
feat(rpc): run fixtures.jest.js with channel (#3227)
Browse files Browse the repository at this point in the history
Also, introduce setupInProcess wrapper to be used for in-process rpc.
  • Loading branch information
dgozman authored Jul 30, 2020
1 parent 4961c2d commit cefb1b9
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 50 deletions.
4 changes: 4 additions & 0 deletions src/rpc/client/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export class Connection {
return new Promise(f => this._waitingForObject.set(guid, f));
}

getObjectWithKnownName(guid: string): any {
return this._objects.get(guid)!;
}

async sendMessageToServer(type: string, guid: string, method: string, params: any): Promise<any> {
const id = ++this._lastId;
const validated = method === 'debugScopeState' ? params : validateParams(type, method, params);
Expand Down
46 changes: 46 additions & 0 deletions src/rpc/inprocess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* 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 { DispatcherConnection } from './server/dispatcher';
import type { Playwright as PlaywrightImpl } from '../server/playwright';
import type { Playwright as PlaywrightAPI } from './client/playwright';
import { PlaywrightDispatcher } from './server/playwrightDispatcher';
import { setUseApiName } from '../progress';
import { Connection } from './client/connection';
import { isUnderTest } from '../helper';

export function setupInProcess(playwright: PlaywrightImpl): PlaywrightAPI {
setUseApiName(false);

const clientConnection = new Connection();
const dispatcherConnection = new DispatcherConnection();

// Dispatch synchronously at first.
dispatcherConnection.onmessage = message => clientConnection.dispatch(message);
clientConnection.onmessage = message => dispatcherConnection.dispatch(message);

// Initialize Playwright channel.
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
const playwrightAPI = clientConnection.getObjectWithKnownName('Playwright');

// Switch to async dispatch after we got Playwright object.
dispatcherConnection.onmessage = message => setImmediate(() => clientConnection.dispatch(message));
clientConnection.onmessage = message => setImmediate(() => dispatcherConnection.dispatch(message));

if (isUnderTest())
playwrightAPI._toImpl = (x: any) => dispatcherConnection._dispatchers.get(x._guid)!._object;
return playwrightAPI;
}
10 changes: 8 additions & 2 deletions src/server/processLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as childProcess from 'child_process';
import * as readline from 'readline';
import * as removeFolder from 'rimraf';
import * as stream from 'stream';
import { helper } from '../helper';
import { helper, isUnderTest } from '../helper';
import { Progress } from '../progress';

export type Env = {[key: string]: string | number | boolean | undefined};
Expand Down Expand Up @@ -113,7 +113,13 @@ export async function launchProcess(options: LaunchProcessOptions): Promise<Laun
const listeners = [ helper.addEventListener(process, 'exit', killProcess) ];
if (options.handleSIGINT) {
listeners.push(helper.addEventListener(process, 'SIGINT', () => {
gracefullyClose().then(() => process.exit(130));
gracefullyClose().then(() => {
// Give tests a chance to dispatch any async calls.
if (isUnderTest())
setTimeout(() => process.exit(130), 0);
else
process.exit(130);
});
}));
}
if (options.handleSIGTERM)
Expand Down
6 changes: 4 additions & 2 deletions test/fixtures/closeme.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

const path = require('path');
const { setUnderTest } = require(path.join(playwrightPath, 'lib', 'helper'));
const { setupInProcess } = require(path.join(playwrightPath, 'lib', 'rpc', 'inprocess'));
setUnderTest();
const playwrightFile = path.join(playwrightPath, 'index');
const playwrightImpl = require(path.join(playwrightPath, 'index'));
const playwright = process.env.PWCHANNEL ? setupInProcess(playwrightImpl) : playwrightImpl;

const browserServer = await require(playwrightFile)[browserTypeName].launchServer(launchOptions);
const browserServer = await playwright[browserTypeName].launchServer(launchOptions);
browserServer.on('close', (exitCode, signal) => {
console.log(`(exitCode=>${exitCode})`);
console.log(`(signal=>${signal})`);
Expand Down
71 changes: 25 additions & 46 deletions test/jest/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@

const path = require('path');
const childProcess = require('child_process');
const playwrightImpl = require('../../index');

const playwright = require('../../index');
const { TestServer } = require('../../utils/testserver/');
const { DispatcherConnection } = require('../../lib/rpc/server/dispatcher');
const { Connection } = require('../../lib/rpc/client/connection');
const { Transport } = require('../../lib/rpc/transport');
const { PlaywrightDispatcher } = require('../../lib/rpc/server/playwrightDispatcher');
const { setUseApiName } = require('../../lib/progress');
const { setupInProcess } = require('../../lib/rpc/inprocess');
const { setUnderTest } = require('../../lib/helper');
setUnderTest();

Expand Down Expand Up @@ -80,57 +78,38 @@ module.exports = function registerFixtures(global) {
});

global.registerWorkerFixture('playwright', async({}, test) => {
Error.stackTraceLimit = 15;
if (process.env.PWCHANNEL) {
setUseApiName(false);
if (process.env.PWCHANNEL === 'wire') {
const connection = new Connection();
let toImpl;
let spawnedProcess;
let onExit;
if (process.env.PWCHANNEL === 'wire') {
spawnedProcess = childProcess.fork(path.join(__dirname, '..', '..', 'lib', 'rpc', 'server'), [], {
stdio: 'pipe',
detached: true,
});
spawnedProcess.unref();
onExit = (exitCode, signal) => {
throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`);
};
spawnedProcess.on('exit', onExit);
const transport = new Transport(spawnedProcess.stdin, spawnedProcess.stdout);
connection.onmessage = message => transport.send(JSON.stringify(message));
transport.onmessage = message => connection.dispatch(JSON.parse(message));
} else {
const dispatcherConnection = new DispatcherConnection();
dispatcherConnection.onmessage = async message => {
setImmediate(() => connection.dispatch(message));
};
connection.onmessage = async message => {
const result = await dispatcherConnection.dispatch(message);
await new Promise(f => setImmediate(f));
return result;
};
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
toImpl = x => dispatcherConnection._dispatchers.get(x._guid)._object;
}

const spawnedProcess = childProcess.fork(path.join(__dirname, '..', '..', 'lib', 'rpc', 'server'), [], {
stdio: 'pipe',
detached: true,
});
spawnedProcess.unref();
const onExit = (exitCode, signal) => {
throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`);
};
spawnedProcess.on('exit', onExit);
const transport = new Transport(spawnedProcess.stdin, spawnedProcess.stdout);
connection.onmessage = message => transport.send(JSON.stringify(message));
transport.onmessage = message => connection.dispatch(JSON.parse(message));
const playwrightObject = await connection.waitForObjectWithKnownName('Playwright');
playwrightObject.toImpl = toImpl;
await test(playwrightObject);
if (spawnedProcess) {
spawnedProcess.removeListener('exit', onExit);
spawnedProcess.stdin.destroy();
spawnedProcess.stdout.destroy();
spawnedProcess.stderr.destroy();
}
spawnedProcess.removeListener('exit', onExit);
spawnedProcess.stdin.destroy();
spawnedProcess.stdout.destroy();
spawnedProcess.stderr.destroy();
} else if (process.env.PWCHANNEL) {
const playwright = setupInProcess(playwrightImpl);
await test(playwright);
} else {
playwright.toImpl = x => x;
const playwright = playwrightImpl;
playwright._toImpl = x => x;
await test(playwright);
}
});

global.registerFixture('toImpl', async ({playwright}, test) => {
await test(playwright.toImpl);
await test(playwright._toImpl);
});

global.registerWorkerFixture('browserType', async ({playwright}, test) => {
Expand Down

0 comments on commit cefb1b9

Please sign in to comment.