Skip to content

Commit

Permalink
chore(recorder): move recording output into the gui app (#5425)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Feb 12, 2021
1 parent a42c46b commit 449adfd
Show file tree
Hide file tree
Showing 39 changed files with 583 additions and 698 deletions.
1 change: 0 additions & 1 deletion index.js
Expand Up @@ -15,5 +15,4 @@
*/

const { setUnderTest } = require('./lib/utils/utils');
setUnderTest(); // Note: we must call setUnderTest before initializing.
module.exports = require('./lib/inprocess');
2 changes: 0 additions & 2 deletions src/cli/cli.ts
Expand Up @@ -332,7 +332,6 @@ async function open(options: Options, url: string | undefined, language: string)
contextOptions,
device: options.device,
saveStorage: options.saveStorage,
terminal: !!process.stdout.columns,
});
await openPage(context, url);
if (process.env.PWCLI_EXIT_FOR_TEST)
Expand All @@ -350,7 +349,6 @@ async function codegen(options: Options, url: string | undefined, language: stri
device: options.device,
saveStorage: options.saveStorage,
startRecording: true,
terminal: !!process.stdout.columns,
outputFile: outputFile ? path.resolve(outputFile) : undefined
});
await openPage(context, url);
Expand Down
6 changes: 3 additions & 3 deletions src/client/android.ts
Expand Up @@ -19,7 +19,7 @@ import * as util from 'util';
import { isString } from '../utils/utils';
import * as channels from '../protocol/channels';
import { Events } from './events';
import { BrowserContext, prepareBrowserContextOptions } from './browserContext';
import { BrowserContext, prepareBrowserContextParams } from './browserContext';
import { ChannelOwner } from './channelOwner';
import * as api from '../../types/types';
import * as types from './types';
Expand Down Expand Up @@ -230,7 +230,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c

async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<ChromiumBrowserContext> {
return this._wrapApiCall('androidDevice.launchBrowser', async () => {
const contextOptions = await prepareBrowserContextOptions(options);
const contextOptions = await prepareBrowserContextParams(options);
const { context } = await this._channel.launchBrowser(contextOptions);
return BrowserContext.from(context) as ChromiumBrowserContext;
});
Expand Down Expand Up @@ -394,7 +394,7 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView {

private async _fetchPage(): Promise<Page> {
return this._device._wrapApiCall('androidWebView.page', async () => {
const { context } = await this._device._channel.connectToWebView({ pid: this._data.pid });
const { context } = await this._device._channel.connectToWebView({ pid: this._data.pid, sdkLanguage: 'javascript' });
return BrowserContext.from(context).pages()[0];
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/client/browser.ts
Expand Up @@ -15,7 +15,7 @@
*/

import * as channels from '../protocol/channels';
import { BrowserContext, prepareBrowserContextOptions } from './browserContext';
import { BrowserContext, prepareBrowserContextParams } from './browserContext';
import { Page } from './page';
import { ChannelOwner } from './channelOwner';
import { Events } from './events';
Expand Down Expand Up @@ -47,7 +47,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel, channels.Brow
return this._wrapApiCall('browser.newContext', async () => {
if (this._isRemote && options._traceDir)
throw new Error(`"_traceDir" is not supported in connected browser`);
const contextOptions = await prepareBrowserContextOptions(options);
const contextOptions = await prepareBrowserContextParams(options);
const context = BrowserContext.from((await this._channel.newContext(contextOptions)).context);
context._options = contextOptions;
this._contexts.add(context);
Expand Down
33 changes: 9 additions & 24 deletions src/client/browserContext.ts
Expand Up @@ -43,9 +43,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
_timeoutSettings = new TimeoutSettings();
_ownerPage: Page | undefined;
private _closedPromise: Promise<void>;
_options: channels.BrowserNewContextParams = {};
private _stdout: NodeJS.WriteStream;
private _stderr: NodeJS.WriteStream;
_options: channels.BrowserNewContextParams = {
sdkLanguage: 'javascript'
};

static from(context: channels.BrowserContextChannel): BrowserContext {
return (context as any)._object;
Expand All @@ -64,23 +64,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
this._channel.on('close', () => this._onClose());
this._channel.on('page', ({page}) => this._onPage(Page.from(page)));
this._channel.on('route', ({ route, request }) => this._onRoute(network.Route.from(route), network.Request.from(request)));
this._stdout = process.stdout;
this._stderr = process.stderr;
this._channel.on('stdout', ({ data }) => {
this._stdout.write(Buffer.from(data, 'base64'));
this._pushTerminalSize();
});
this._channel.on('stderr', ({ data }) => {
this._stderr.write(Buffer.from(data, 'base64'));
this._pushTerminalSize();
});
this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));
}

private _pushTerminalSize() {
this._channel.setTerminalSizeNoReply({ rows: process.stdout.rows, columns: process.stdout.columns }).catch(() => {});
}

private _onPage(page: Page): void {
this._pages.add(page);
this.emit(Events.BrowserContext.Page, page);
Expand Down Expand Up @@ -283,31 +269,30 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
device?: string,
saveStorage?: string,
startRecording?: boolean,
terminal?: boolean,
outputFile?: string
}) {
this._pushTerminalSize();
await this._channel.recorderSupplementEnable(params);
}
}

export async function prepareBrowserContextOptions(options: BrowserContextOptions): Promise<channels.BrowserNewContextOptions> {
export async function prepareBrowserContextParams(options: BrowserContextOptions): Promise<channels.BrowserNewContextParams> {
if (options.videoSize && !options.videosPath)
throw new Error(`"videoSize" option requires "videosPath" to be specified`);
if (options.extraHTTPHeaders)
network.validateHeaders(options.extraHTTPHeaders);
const contextOptions: channels.BrowserNewContextParams = {
const contextParams: channels.BrowserNewContextParams = {
sdkLanguage: 'javascript',
...options,
viewport: options.viewport === null ? undefined : options.viewport,
noDefaultViewport: options.viewport === null,
extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined,
storageState: typeof options.storageState === 'string' ? JSON.parse(await fsReadFileAsync(options.storageState, 'utf8')) : options.storageState,
};
if (!contextOptions.recordVideo && options.videosPath) {
contextOptions.recordVideo = {
if (!contextParams.recordVideo && options.videosPath) {
contextParams.recordVideo = {
dir: options.videosPath,
size: options.videoSize
};
}
return contextOptions;
return contextParams;
}
13 changes: 7 additions & 6 deletions src/client/browserType.ts
Expand Up @@ -16,7 +16,7 @@

import * as channels from '../protocol/channels';
import { Browser } from './browser';
import { BrowserContext, prepareBrowserContextOptions } from './browserContext';
import { BrowserContext, prepareBrowserContextParams } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { LaunchOptions, LaunchServerOptions, ConnectOptions, LaunchPersistentContextOptions } from './types';
import WebSocket from 'ws';
Expand Down Expand Up @@ -94,17 +94,17 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, chann
async launchPersistentContext(userDataDir: string, options: LaunchPersistentContextOptions = {}): Promise<BrowserContext> {
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
const contextOptions = await prepareBrowserContextOptions(options);
const persistentOptions: channels.BrowserTypeLaunchPersistentContextParams = {
...contextOptions,
const contextParams = await prepareBrowserContextParams(options);
const persistentParams: channels.BrowserTypeLaunchPersistentContextParams = {
...contextParams,
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined,
userDataDir,
};
const result = await this._channel.launchPersistentContext(persistentOptions);
const result = await this._channel.launchPersistentContext(persistentParams);
const context = BrowserContext.from(result.context);
context._options = contextOptions;
context._options = contextParams;
context._logger = options.logger;
return context;
}, options.logger);
Expand Down Expand Up @@ -192,6 +192,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, chann
const logger = params.logger;
return this._wrapApiCall('browserType.connectOverCDP', async () => {
const result = await this._channel.connectOverCDP({
sdkLanguage: 'javascript',
wsEndpoint: params.wsEndpoint,
slowMo: params.slowMo,
timeout: params.timeout
Expand Down
1 change: 1 addition & 0 deletions src/client/electron.ts
Expand Up @@ -46,6 +46,7 @@ export class Electron extends ChannelOwner<channels.ElectronChannel, channels.El
async launch(options: ElectronOptions = {}): Promise<ElectronApplication> {
return this._wrapApiCall('electron.launch', async () => {
const params: channels.ElectronLaunchParams = {
sdkLanguage: 'javascript',
...options,
env: envObjectToArray(options.env ? options.env : process.env),
};
Expand Down
2 changes: 1 addition & 1 deletion src/dispatchers/androidDispatcher.ts
Expand Up @@ -165,7 +165,7 @@ export class AndroidDeviceDispatcher extends Dispatcher<AndroidDevice, channels.
}

async connectToWebView(params: channels.AndroidDeviceConnectToWebViewParams): Promise<channels.AndroidDeviceConnectToWebViewResult> {
return { context: new BrowserContextDispatcher(this._scope, await this._object.connectToWebView(params.pid)) };
return { context: new BrowserContextDispatcher(this._scope, await this._object.connectToWebView(params.pid, params.sdkLanguage)) };
}
}

Expand Down
14 changes: 3 additions & 11 deletions src/dispatchers/browserContextDispatcher.ts
Expand Up @@ -23,6 +23,7 @@ import { CRBrowserContext } from '../server/chromium/crBrowser';
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { RecorderSupplement } from '../server/supplements/recorderSupplement';
import { CallMetadata } from '../server/instrumentation';
import { isUnderTest } from '../utils/utils';

export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channels.BrowserContextInitializer> implements channels.BrowserContextChannel {
private _context: BrowserContext;
Expand All @@ -38,8 +39,6 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
this._dispatchEvent('close');
this._dispose();
});
context.on(BrowserContext.Events.StdOut, data => this._dispatchEvent('stdout', { data: Buffer.from(data, 'utf8').toString('base64') }));
context.on(BrowserContext.Events.StdErr, data => this._dispatchEvent('stderr', { data: Buffer.from(data, 'utf8').toString('base64') }));

if (context._browser.options.name === 'chromium') {
for (const page of (context as CRBrowserContext).backgroundPages())
Expand Down Expand Up @@ -134,12 +133,9 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
}

async pause() {
if (!this._context._browser.options.headful)
if (!this._context._browser.options.headful && !isUnderTest())
return;
const recorder = await RecorderSupplement.getOrCreate(this._context, {
language: 'javascript',
terminal: true
});
const recorder = await RecorderSupplement.getOrCreate(this._context);
await recorder.pause();
}

Expand All @@ -149,8 +145,4 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
const crBrowserContext = this._object as CRBrowserContext;
return { session: new CDPSessionDispatcher(this._scope, await crBrowserContext.newCDPSession((params.page as PageDispatcher)._object)) };
}

async setTerminalSizeNoReply(params: channels.BrowserContextSetTerminalSizeNoReplyParams): Promise<void> {
this._context.terminalSize = params;
}
}
29 changes: 8 additions & 21 deletions src/protocol/channels.ts
Expand Up @@ -255,6 +255,7 @@ export type BrowserTypeLaunchResult = {
};
export type BrowserTypeLaunchPersistentContextParams = {
userDataDir: string,
sdkLanguage: string,
executablePath?: string,
args?: string[],
ignoreAllDefaultArgs?: boolean,
Expand Down Expand Up @@ -384,6 +385,7 @@ export type BrowserTypeLaunchPersistentContextResult = {
context: BrowserContextChannel,
};
export type BrowserTypeConnectOverCDPParams = {
sdkLanguage: string,
wsEndpoint: string,
slowMo?: number,
timeout?: number,
Expand Down Expand Up @@ -415,6 +417,7 @@ export type BrowserCloseParams = {};
export type BrowserCloseOptions = {};
export type BrowserCloseResult = void;
export type BrowserNewContextParams = {
sdkLanguage: string,
noDefaultViewport?: boolean,
viewport?: {
width: number,
Expand Down Expand Up @@ -556,8 +559,6 @@ export interface BrowserContextChannel extends Channel {
on(event: 'close', callback: (params: BrowserContextCloseEvent) => void): this;
on(event: 'page', callback: (params: BrowserContextPageEvent) => void): this;
on(event: 'route', callback: (params: BrowserContextRouteEvent) => void): this;
on(event: 'stdout', callback: (params: BrowserContextStdoutEvent) => void): this;
on(event: 'stderr', callback: (params: BrowserContextStderrEvent) => void): this;
on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this;
on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this;
addCookies(params: BrowserContextAddCookiesParams, metadata?: Metadata): Promise<BrowserContextAddCookiesResult>;
Expand All @@ -580,7 +581,6 @@ export interface BrowserContextChannel extends Channel {
pause(params?: BrowserContextPauseParams, metadata?: Metadata): Promise<BrowserContextPauseResult>;
recorderSupplementEnable(params: BrowserContextRecorderSupplementEnableParams, metadata?: Metadata): Promise<BrowserContextRecorderSupplementEnableResult>;
crNewCDPSession(params: BrowserContextCrNewCDPSessionParams, metadata?: Metadata): Promise<BrowserContextCrNewCDPSessionResult>;
setTerminalSizeNoReply(params: BrowserContextSetTerminalSizeNoReplyParams, metadata?: Metadata): Promise<BrowserContextSetTerminalSizeNoReplyResult>;
}
export type BrowserContextBindingCallEvent = {
binding: BindingCallChannel,
Expand All @@ -593,12 +593,6 @@ export type BrowserContextRouteEvent = {
route: RouteChannel,
request: RequestChannel,
};
export type BrowserContextStdoutEvent = {
data: Binary,
};
export type BrowserContextStderrEvent = {
data: Binary,
};
export type BrowserContextCrBackgroundPageEvent = {
page: PageChannel,
};
Expand Down Expand Up @@ -731,22 +725,21 @@ export type BrowserContextPauseParams = {};
export type BrowserContextPauseOptions = {};
export type BrowserContextPauseResult = void;
export type BrowserContextRecorderSupplementEnableParams = {
language: string,
language?: string,
startRecording?: boolean,
launchOptions?: any,
contextOptions?: any,
device?: string,
saveStorage?: string,
terminal?: boolean,
outputFile?: string,
};
export type BrowserContextRecorderSupplementEnableOptions = {
language?: string,
startRecording?: boolean,
launchOptions?: any,
contextOptions?: any,
device?: string,
saveStorage?: string,
terminal?: boolean,
outputFile?: string,
};
export type BrowserContextRecorderSupplementEnableResult = void;
Expand All @@ -759,15 +752,6 @@ export type BrowserContextCrNewCDPSessionOptions = {
export type BrowserContextCrNewCDPSessionResult = {
session: CDPSessionChannel,
};
export type BrowserContextSetTerminalSizeNoReplyParams = {
rows?: number,
columns?: number,
};
export type BrowserContextSetTerminalSizeNoReplyOptions = {
rows?: number,
columns?: number,
};
export type BrowserContextSetTerminalSizeNoReplyResult = void;

// ----------- Page -----------
export type PageInitializer = {
Expand Down Expand Up @@ -2482,6 +2466,7 @@ export interface ElectronChannel extends Channel {
launch(params: ElectronLaunchParams, metadata?: Metadata): Promise<ElectronLaunchResult>;
}
export type ElectronLaunchParams = {
sdkLanguage: string,
executablePath?: string,
args?: string[],
cwd?: string,
Expand Down Expand Up @@ -2783,6 +2768,7 @@ export type AndroidDeviceInputDragOptions = {
};
export type AndroidDeviceInputDragResult = void;
export type AndroidDeviceLaunchBrowserParams = {
sdkLanguage: string,
pkg?: string,
ignoreHTTPSErrors?: boolean,
javaScriptEnabled?: boolean,
Expand Down Expand Up @@ -2918,6 +2904,7 @@ export type AndroidDeviceSetDefaultTimeoutNoReplyOptions = {
};
export type AndroidDeviceSetDefaultTimeoutNoReplyResult = void;
export type AndroidDeviceConnectToWebViewParams = {
sdkLanguage: string,
pid: number,
};
export type AndroidDeviceConnectToWebViewOptions = {
Expand Down

0 comments on commit 449adfd

Please sign in to comment.