mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	feat(rpc): run fixtures.jest.js with channel (#3227)
Also, introduce setupInProcess wrapper to be used for in-process rpc.
This commit is contained in:
		
							parent
							
								
									4961c2ddbb
								
							
						
					
					
						commit
						cefb1b9727
					
				@ -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);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								src/rpc/inprocess.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/rpc/inprocess.ts
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
			
		||||
}
 | 
			
		||||
@ -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};
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								test/fixtures/closeme.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								test/fixtures/closeme.js
									
									
									
									
										vendored
									
									
								
							@ -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})`);
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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) => {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user