chore(protocol): do client hello instead of server hello (#8019)
This commit is contained in:
parent
166851e7d8
commit
ddcdb6d413
|
|
@ -17,7 +17,7 @@
|
||||||
import { LaunchServerOptions, Logger } from './client/types';
|
import { LaunchServerOptions, Logger } from './client/types';
|
||||||
import { Browser } from './server/browser';
|
import { Browser } from './server/browser';
|
||||||
import { EventEmitter } from 'ws';
|
import { EventEmitter } from 'ws';
|
||||||
import { Dispatcher, DispatcherScope } from './dispatchers/dispatcher';
|
import { Dispatcher, DispatcherConnection, DispatcherScope, Root } from './dispatchers/dispatcher';
|
||||||
import { BrowserContextDispatcher } from './dispatchers/browserContextDispatcher';
|
import { BrowserContextDispatcher } from './dispatchers/browserContextDispatcher';
|
||||||
import * as channels from './protocol/channels';
|
import * as channels from './protocol/channels';
|
||||||
import { BrowserServerLauncher, BrowserServer } from './client/browserType';
|
import { BrowserServerLauncher, BrowserServer } from './client/browserType';
|
||||||
|
|
@ -80,18 +80,21 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
||||||
return browserServer;
|
return browserServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onConnect(playwright: Playwright, browser: Browser, scope: DispatcherScope, forceDisconnect: () => void) {
|
private async _onConnect(playwright: Playwright, browser: Browser, connection: DispatcherConnection, forceDisconnect: () => void) {
|
||||||
const selectors = new Selectors();
|
let browserDispatcher: ConnectedBrowserDispatcher | undefined;
|
||||||
const selectorsDispatcher = new SelectorsDispatcher(scope, selectors);
|
new Root(connection, async (scope: DispatcherScope): Promise<PlaywrightDispatcher> => {
|
||||||
const browserDispatcher = new ConnectedBrowserDispatcher(scope, browser, selectors);
|
const selectors = new Selectors();
|
||||||
browser.on(Browser.Events.Disconnected, () => {
|
const selectorsDispatcher = new SelectorsDispatcher(scope, selectors);
|
||||||
// Underlying browser did close for some reason - force disconnect the client.
|
browserDispatcher = new ConnectedBrowserDispatcher(scope, browser, selectors);
|
||||||
forceDisconnect();
|
browser.on(Browser.Events.Disconnected, () => {
|
||||||
|
// Underlying browser did close for some reason - force disconnect the client.
|
||||||
|
forceDisconnect();
|
||||||
|
});
|
||||||
|
return new PlaywrightDispatcher(scope, playwright, selectorsDispatcher, browserDispatcher);
|
||||||
});
|
});
|
||||||
new PlaywrightDispatcher(scope, playwright, selectorsDispatcher, browserDispatcher);
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup contexts upon disconnect.
|
// Cleanup contexts upon disconnect.
|
||||||
browserDispatcher.cleanupContexts().catch(e => {});
|
browserDispatcher?.cleanupContexts().catch(e => {});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import fs from 'fs';
|
||||||
import * as playwright from '../..';
|
import * as playwright from '../..';
|
||||||
import { BrowserType } from '../client/browserType';
|
import { BrowserType } from '../client/browserType';
|
||||||
import { LaunchServerOptions } from '../client/types';
|
import { LaunchServerOptions } from '../client/types';
|
||||||
import { DispatcherConnection } from '../dispatchers/dispatcher';
|
import { DispatcherConnection, Root } from '../dispatchers/dispatcher';
|
||||||
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
|
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
|
||||||
import { Transport } from '../protocol/transport';
|
import { Transport } from '../protocol/transport';
|
||||||
import { PlaywrightServer, PlaywrightServerOptions } from '../remote/playwrightServer';
|
import { PlaywrightServer, PlaywrightServerOptions } from '../remote/playwrightServer';
|
||||||
|
|
@ -34,6 +34,10 @@ export function printApiJson() {
|
||||||
|
|
||||||
export function runDriver() {
|
export function runDriver() {
|
||||||
const dispatcherConnection = new DispatcherConnection();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
|
new Root(dispatcherConnection, async rootScope => {
|
||||||
|
const playwright = createPlaywright();
|
||||||
|
return new PlaywrightDispatcher(rootScope, playwright);
|
||||||
|
});
|
||||||
const transport = new Transport(process.stdout, process.stdin);
|
const transport = new Transport(process.stdout, process.stdin);
|
||||||
transport.onmessage = message => dispatcherConnection.dispatch(JSON.parse(message));
|
transport.onmessage = message => dispatcherConnection.dispatch(JSON.parse(message));
|
||||||
dispatcherConnection.onmessage = message => transport.send(JSON.stringify(message));
|
dispatcherConnection.onmessage = message => transport.send(JSON.stringify(message));
|
||||||
|
|
@ -46,9 +50,6 @@ export function runDriver() {
|
||||||
await gracefullyCloseAll();
|
await gracefullyCloseAll();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const playwright = createPlaywright();
|
|
||||||
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runServer(port: number | undefined, configFile?: string) {
|
export async function runServer(port: number | undefined, configFile?: string) {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import { envObjectToArray } from './clientHelper';
|
||||||
import { assert, headersObjectToArray, makeWaitForNextTask, getUserAgent } from '../utils/utils';
|
import { assert, headersObjectToArray, makeWaitForNextTask, getUserAgent } from '../utils/utils';
|
||||||
import { kBrowserClosedError } from '../utils/errors';
|
import { kBrowserClosedError } from '../utils/errors';
|
||||||
import * as api from '../../types/types';
|
import * as api from '../../types/types';
|
||||||
import type { Playwright } from './playwright';
|
|
||||||
|
|
||||||
export interface BrowserServerLauncher {
|
export interface BrowserServerLauncher {
|
||||||
launchServer(options?: LaunchServerOptions): Promise<api.BrowserServer>;
|
launchServer(options?: LaunchServerOptions): Promise<api.BrowserServer>;
|
||||||
|
|
@ -182,7 +181,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, chann
|
||||||
reject(new Error(`WebSocket server disconnected (${event.code}) ${event.reason}`));
|
reject(new Error(`WebSocket server disconnected (${event.code}) ${event.reason}`));
|
||||||
};
|
};
|
||||||
ws.addEventListener('close', prematureCloseListener);
|
ws.addEventListener('close', prematureCloseListener);
|
||||||
const playwright = await connection.waitForObjectWithKnownName('Playwright') as Playwright;
|
const playwright = await connection.initializePlaywright();
|
||||||
|
|
||||||
if (!playwright._initializer.preLaunchedBrowser) {
|
if (!playwright._initializer.preLaunchedBrowser) {
|
||||||
reject(new Error('Malformed endpoint. Did you use launchServer method?'));
|
reject(new Error('Malformed endpoint. Did you use launchServer method?'));
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,15 @@ import { ParsedStackTrace } from '../utils/stackTrace';
|
||||||
import { Artifact } from './artifact';
|
import { Artifact } from './artifact';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
class Root extends ChannelOwner<channels.Channel, {}> {
|
class Root extends ChannelOwner<channels.RootChannel, {}> {
|
||||||
constructor(connection: Connection) {
|
constructor(connection: Connection) {
|
||||||
super(connection, '', '', {});
|
super(connection, 'Root', '', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize(): Promise<Playwright> {
|
||||||
|
return Playwright.from((await this._channel.initialize({
|
||||||
|
language: 'javascript',
|
||||||
|
})).playwright);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +58,7 @@ export class Connection extends EventEmitter {
|
||||||
onmessage = (message: object): void => {};
|
onmessage = (message: object): void => {};
|
||||||
private _lastId = 0;
|
private _lastId = 0;
|
||||||
private _callbacks = new Map<number, { resolve: (a: any) => void, reject: (a: Error) => void, metadata: channels.Metadata }>();
|
private _callbacks = new Map<number, { resolve: (a: any) => void, reject: (a: Error) => void, metadata: channels.Metadata }>();
|
||||||
private _rootObject: ChannelOwner;
|
private _rootObject: Root;
|
||||||
private _disconnectedErrorMessage: string | undefined;
|
private _disconnectedErrorMessage: string | undefined;
|
||||||
private _onClose?: () => void;
|
private _onClose?: () => void;
|
||||||
|
|
||||||
|
|
@ -62,10 +68,8 @@ export class Connection extends EventEmitter {
|
||||||
this._onClose = onClose;
|
this._onClose = onClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForObjectWithKnownName(guid: string): Promise<any> {
|
async initializePlaywright(): Promise<Playwright> {
|
||||||
if (this._objects.has(guid))
|
return await this._rootObject.initialize();
|
||||||
return this._objects.get(guid)!;
|
|
||||||
return new Promise(f => this._waitingForObject.set(guid, f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingProtocolCalls(): channels.Metadata[] {
|
pendingProtocolCalls(): channels.Metadata[] {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,10 @@ export class Playwright extends ChannelOwner<channels.PlaywrightChannel, channel
|
||||||
this._channel.on('incomingSocksSocket', ({socket}) => SocksSocket.from(socket));
|
this._channel.on('incomingSocksSocket', ({socket}) => SocksSocket.from(socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static from(channel: channels.PlaywrightChannel): Playwright {
|
||||||
|
return (channel as any)._object;
|
||||||
|
}
|
||||||
|
|
||||||
async _enablePortForwarding(ports: number[]) {
|
async _enablePortForwarding(ports: number[]) {
|
||||||
this._forwardPorts = ports;
|
this._forwardPorts = ports;
|
||||||
await this._channel.setForwardedPorts({ports});
|
await this._channel.setForwardedPorts({ports});
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import { tOptional } from '../protocol/validatorPrimitives';
|
||||||
import { kBrowserOrContextClosedError } from '../utils/errors';
|
import { kBrowserOrContextClosedError } from '../utils/errors';
|
||||||
import { CallMetadata, SdkObject } from '../server/instrumentation';
|
import { CallMetadata, SdkObject } from '../server/instrumentation';
|
||||||
import { rewriteErrorMessage } from '../utils/stackTrace';
|
import { rewriteErrorMessage } from '../utils/stackTrace';
|
||||||
|
import type { PlaywrightDispatcher } from './playwrightDispatcher';
|
||||||
|
|
||||||
export const dispatcherSymbol = Symbol('dispatcher');
|
export const dispatcherSymbol = Symbol('dispatcher');
|
||||||
|
|
||||||
|
|
@ -121,15 +122,25 @@ export class Dispatcher<Type extends { guid: string }, Initializer> extends Even
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DispatcherScope = Dispatcher<any, any>;
|
export type DispatcherScope = Dispatcher<any, any>;
|
||||||
class Root extends Dispatcher<{ guid: '' }, {}> {
|
export class Root extends Dispatcher<{ guid: '' }, {}> {
|
||||||
constructor(connection: DispatcherConnection) {
|
private _initialized = false;
|
||||||
super(connection, { guid: '' }, '', {}, true);
|
|
||||||
|
constructor(connection: DispatcherConnection, private readonly createPlaywright?: (scope: DispatcherScope) => Promise<PlaywrightDispatcher>) {
|
||||||
|
super(connection, { guid: '' }, 'Root', {}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize(params: { language?: string }): Promise<channels.RootInitializeResult> {
|
||||||
|
assert(this.createPlaywright);
|
||||||
|
assert(!this._initialized);
|
||||||
|
this._initialized = true;
|
||||||
|
return {
|
||||||
|
playwright: await this.createPlaywright(this),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DispatcherConnection {
|
export class DispatcherConnection {
|
||||||
readonly _dispatchers = new Map<string, Dispatcher<any, any>>();
|
readonly _dispatchers = new Map<string, Dispatcher<any, any>>();
|
||||||
private _rootDispatcher: Root;
|
|
||||||
onmessage = (message: object) => {};
|
onmessage = (message: object) => {};
|
||||||
private _validateParams: (type: string, method: string, params: any) => any;
|
private _validateParams: (type: string, method: string, params: any) => any;
|
||||||
private _validateMetadata: (metadata: any) => { stack?: channels.StackFrame[] };
|
private _validateMetadata: (metadata: any) => { stack?: channels.StackFrame[] };
|
||||||
|
|
@ -157,8 +168,6 @@ export class DispatcherConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._rootDispatcher = new Root(this);
|
|
||||||
|
|
||||||
const tChannel = (name: string): Validator => {
|
const tChannel = (name: string): Validator => {
|
||||||
return (arg: any, path: string) => {
|
return (arg: any, path: string) => {
|
||||||
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
|
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
|
||||||
|
|
@ -185,10 +194,6 @@ export class DispatcherConnection {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rootDispatcher(): Dispatcher<any, any> {
|
|
||||||
return this._rootDispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
async dispatch(message: object) {
|
async dispatch(message: object) {
|
||||||
const { id, guid, method, params, metadata } = message as any;
|
const { id, guid, method, params, metadata } = message as any;
|
||||||
const dispatcher = this._dispatchers.get(guid);
|
const dispatcher = this._dispatchers.get(guid);
|
||||||
|
|
@ -197,7 +202,8 @@ export class DispatcherConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (method === 'debugScopeState') {
|
if (method === 'debugScopeState') {
|
||||||
this.onmessage({ id, result: this._rootDispatcher._debugScopeState() });
|
const rootDispatcher = this._dispatchers.get('')!;
|
||||||
|
this.onmessage({ id, result: rootDispatcher._debugScopeState() });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DispatcherConnection } from './dispatchers/dispatcher';
|
import { DispatcherConnection, Root } from './dispatchers/dispatcher';
|
||||||
import { createPlaywright } from './server/playwright';
|
import { createPlaywright } from './server/playwright';
|
||||||
import type { Playwright as PlaywrightAPI } from './client/playwright';
|
import type { Playwright as PlaywrightAPI } from './client/playwright';
|
||||||
import { PlaywrightDispatcher } from './dispatchers/playwrightDispatcher';
|
import { PlaywrightDispatcher } from './dispatchers/playwrightDispatcher';
|
||||||
|
|
@ -31,8 +31,10 @@ function setupInProcess(): PlaywrightAPI {
|
||||||
dispatcherConnection.onmessage = message => clientConnection.dispatch(message);
|
dispatcherConnection.onmessage = message => clientConnection.dispatch(message);
|
||||||
clientConnection.onmessage = message => dispatcherConnection.dispatch(message);
|
clientConnection.onmessage = message => dispatcherConnection.dispatch(message);
|
||||||
|
|
||||||
|
const rootScope = new Root(dispatcherConnection);
|
||||||
|
|
||||||
// Initialize Playwright channel.
|
// Initialize Playwright channel.
|
||||||
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
|
new PlaywrightDispatcher(rootScope, playwright);
|
||||||
const playwrightAPI = clientConnection.getObjectWithKnownName('Playwright') as PlaywrightAPI;
|
const playwrightAPI = clientConnection.getObjectWithKnownName('Playwright') as PlaywrightAPI;
|
||||||
playwrightAPI.chromium._serverLauncher = new BrowserServerLauncherImpl('chromium');
|
playwrightAPI.chromium._serverLauncher = new BrowserServerLauncherImpl('chromium');
|
||||||
playwrightAPI.firefox._serverLauncher = new BrowserServerLauncherImpl('firefox');
|
playwrightAPI.firefox._serverLauncher = new BrowserServerLauncherImpl('firefox');
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class PlaywrightClient {
|
||||||
transport.onmessage = message => connection.dispatch(JSON.parse(message));
|
transport.onmessage = message => connection.dispatch(JSON.parse(message));
|
||||||
this._closePromise = new Promise(f => transport.onclose = f);
|
this._closePromise = new Promise(f => transport.onclose = f);
|
||||||
|
|
||||||
this._playwright = connection.waitForObjectWithKnownName('Playwright');
|
this._playwright = connection.initializePlaywright();
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop() {
|
async stop() {
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,21 @@ export type InterceptedResponse = {
|
||||||
}[],
|
}[],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----------- Root -----------
|
||||||
|
export type RootInitializer = {};
|
||||||
|
export interface RootChannel extends Channel {
|
||||||
|
initialize(params: RootInitializeParams, metadata?: Metadata): Promise<RootInitializeResult>;
|
||||||
|
}
|
||||||
|
export type RootInitializeParams = {
|
||||||
|
language: string,
|
||||||
|
};
|
||||||
|
export type RootInitializeOptions = {
|
||||||
|
|
||||||
|
};
|
||||||
|
export type RootInitializeResult = {
|
||||||
|
playwright: PlaywrightChannel,
|
||||||
|
};
|
||||||
|
|
||||||
// ----------- Playwright -----------
|
// ----------- Playwright -----------
|
||||||
export type PlaywrightInitializer = {
|
export type PlaywrightInitializer = {
|
||||||
chromium: BrowserTypeChannel,
|
chromium: BrowserTypeChannel,
|
||||||
|
|
|
||||||
|
|
@ -325,6 +325,16 @@ ContextOptions:
|
||||||
path: string
|
path: string
|
||||||
strictSelectors: boolean?
|
strictSelectors: boolean?
|
||||||
|
|
||||||
|
Root:
|
||||||
|
type: interface
|
||||||
|
|
||||||
|
commands:
|
||||||
|
|
||||||
|
initialize:
|
||||||
|
parameters:
|
||||||
|
language: string
|
||||||
|
returns:
|
||||||
|
playwright: Playwright
|
||||||
|
|
||||||
Playwright:
|
Playwright:
|
||||||
type: interface
|
type: interface
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,9 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||||
value: tString,
|
value: tString,
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
scheme.RootInitializeParams = tObject({
|
||||||
|
language: tString,
|
||||||
|
});
|
||||||
scheme.PlaywrightSetForwardedPortsParams = tObject({
|
scheme.PlaywrightSetForwardedPortsParams = tObject({
|
||||||
ports: tArray(tNumber),
|
ports: tArray(tNumber),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,13 @@ export class PlaywrightClient {
|
||||||
ws.on('message', message => connection.dispatch(JSON.parse(message.toString())));
|
ws.on('message', message => connection.dispatch(JSON.parse(message.toString())));
|
||||||
const errorPromise = new Promise((_, reject) => ws.on('error', error => reject(error)));
|
const errorPromise = new Promise((_, reject) => ws.on('error', error => reject(error)));
|
||||||
const closePromise = new Promise((_, reject) => ws.on('close', () => reject(new Error('Connection closed'))));
|
const closePromise = new Promise((_, reject) => ws.on('close', () => reject(new Error('Connection closed'))));
|
||||||
const playwrightClientPromise = new Promise<PlaywrightClient>(async (resolve, reject) => {
|
const playwrightClientPromise = new Promise<PlaywrightClient>((resolve, reject) => {
|
||||||
const playwright = await connection.waitForObjectWithKnownName('Playwright') as Playwright;
|
ws.on('open', async () => {
|
||||||
if (forwardPorts)
|
const playwright = await connection.initializePlaywright();
|
||||||
await playwright._enablePortForwarding(forwardPorts).catch(reject);
|
if (forwardPorts)
|
||||||
resolve(new PlaywrightClient(playwright, ws));
|
await playwright._enablePortForwarding(forwardPorts).catch(reject);
|
||||||
|
resolve(new PlaywrightClient(playwright, ws));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
let timer: NodeJS.Timeout;
|
let timer: NodeJS.Timeout;
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as ws from 'ws';
|
import * as ws from 'ws';
|
||||||
import { DispatcherConnection, DispatcherScope } from '../dispatchers/dispatcher';
|
import { DispatcherConnection, Root } from '../dispatchers/dispatcher';
|
||||||
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
|
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
|
||||||
import { createPlaywright } from '../server/playwright';
|
import { createPlaywright, Playwright } from '../server/playwright';
|
||||||
import { gracefullyCloseAll } from '../utils/processLauncher';
|
import { gracefullyCloseAll } from '../utils/processLauncher';
|
||||||
|
|
||||||
const debugLog = debug('pw:server');
|
const debugLog = debug('pw:server');
|
||||||
|
|
@ -27,7 +27,7 @@ const debugLog = debug('pw:server');
|
||||||
export interface PlaywrightServerDelegate {
|
export interface PlaywrightServerDelegate {
|
||||||
path: string;
|
path: string;
|
||||||
allowMultipleClients: boolean;
|
allowMultipleClients: boolean;
|
||||||
onConnect(rootScope: DispatcherScope, forceDisconnect: () => void): Promise<() => any>;
|
onConnect(connection: DispatcherConnection, forceDisconnect: () => void): Promise<() => any>;
|
||||||
onClose: () => any;
|
onClose: () => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,15 +49,18 @@ export class PlaywrightServer {
|
||||||
path: '/ws',
|
path: '/ws',
|
||||||
allowMultipleClients: false,
|
allowMultipleClients: false,
|
||||||
onClose: cleanup,
|
onClose: cleanup,
|
||||||
onConnect: async (rootScope: DispatcherScope) => {
|
onConnect: async (connection: DispatcherConnection) => {
|
||||||
const playwright = createPlaywright();
|
let playwright: Playwright | undefined;
|
||||||
if (acceptForwardedPorts)
|
new Root(connection, async (rootScope): Promise<PlaywrightDispatcher> => {
|
||||||
await playwright._enablePortForwarding();
|
playwright = createPlaywright();
|
||||||
new PlaywrightDispatcher(rootScope, playwright);
|
if (acceptForwardedPorts)
|
||||||
|
await playwright._enablePortForwarding();
|
||||||
|
return new PlaywrightDispatcher(rootScope, playwright);
|
||||||
|
});
|
||||||
return () => {
|
return () => {
|
||||||
cleanup();
|
cleanup();
|
||||||
playwright._disablePortForwarding();
|
playwright?._disablePortForwarding();
|
||||||
playwright.selectors.unregisterAll();
|
playwright?.selectors.unregisterAll();
|
||||||
onDisconnect?.();
|
onDisconnect?.();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -105,7 +108,6 @@ export class PlaywrightServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
const forceDisconnect = () => socket.close();
|
const forceDisconnect = () => socket.close();
|
||||||
const scope = connection.rootDispatcher();
|
|
||||||
let onDisconnect = () => {};
|
let onDisconnect = () => {};
|
||||||
const disconnected = () => {
|
const disconnected = () => {
|
||||||
this._clientsCount--;
|
this._clientsCount--;
|
||||||
|
|
@ -121,7 +123,7 @@ export class PlaywrightServer {
|
||||||
debugLog('Client error ' + error);
|
debugLog('Client error ' + error);
|
||||||
disconnected();
|
disconnected();
|
||||||
});
|
});
|
||||||
onDisconnect = await this._delegate.onConnect(scope, forceDisconnect);
|
onDisconnect = await this._delegate.onConnect(connection, forceDisconnect);
|
||||||
});
|
});
|
||||||
|
|
||||||
return wsEndpoint;
|
return wsEndpoint;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ test('should be able to connect two browsers at the same time', async ({browserT
|
||||||
expect(browser1.contexts().length).toBe(1);
|
expect(browser1.contexts().length).toBe(1);
|
||||||
|
|
||||||
await browser1.close();
|
await browser1.close();
|
||||||
|
expect(browser2.contexts().length).toBe(1);
|
||||||
const page2 = await browser2.newPage();
|
const page2 = await browser2.newPage();
|
||||||
expect(await page2.evaluate(() => 7 * 6)).toBe(42); // original browser should still work
|
expect(await page2.evaluate(() => 7 * 6)).toBe(42); // original browser should still work
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue