Skip to content

Commit

Permalink
chore: introduce "instrumentation" that is used for debug and trace (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dgozman committed Sep 4, 2020
1 parent 25fe115 commit 675ce00
Show file tree
Hide file tree
Showing 21 changed files with 216 additions and 148 deletions.
61 changes: 61 additions & 0 deletions src/debug/debugController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* 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 { BrowserContext } from '../server/browserContext';
import * as frames from '../server/frames';
import * as js from '../server/javascript';
import { Page } from '../server/page';
import { InstrumentingAgent } from '../server/instrumentation';
import type DebugScript from './injected/debugScript';
import { Progress } from '../server/progress';
import { isDebugMode } from '../utils/utils';
import * as debugScriptSource from '../generated/debugScriptSource';

const debugScriptSymbol = Symbol('debugScript');

export class DebugController implements InstrumentingAgent {
private async ensureInstalledInFrame(frame: frames.Frame) {
try {
const mainContext = await frame._mainContext();
if ((mainContext as any)[debugScriptSymbol])
return;
(mainContext as any)[debugScriptSymbol] = true;
const objectId = await mainContext._delegate.rawEvaluate(`new (${debugScriptSource.source})()`);
const debugScript = new js.JSHandle(mainContext, 'object', objectId) as js.JSHandle<DebugScript>;
const injectedScript = await mainContext.injectedScript();
await debugScript.evaluate((debugScript, injectedScript) => {
debugScript.initialize(injectedScript, { console: true });
}, injectedScript);
} catch (e) {
}
}

async onContextCreated(context: BrowserContext): Promise<void> {
if (!isDebugMode())
return;
context.on(BrowserContext.Events.Page, (page: Page) => {
for (const frame of page.frames())
this.ensureInstalledInFrame(frame);
page.on(Page.Events.FrameNavigated, frame => this.ensureInstalledInFrame(frame));
});
}

async onContextDestroyed(context: BrowserContext): Promise<void> {
}

async onBeforePageAction(page: Page, progress: Progress): Promise<void> {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

import { ParsedSelector, parseSelector } from '../../common/selectorParser';
import type InjectedScript from '../../injected/injectedScript';
import { ParsedSelector, parseSelector } from '../../server/common/selectorParser';
import type InjectedScript from '../../server/injected/injectedScript';
import { html } from './html';

export class ConsoleAPI {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import { ConsoleAPI } from './consoleApi';
import type InjectedScript from '../../injected/injectedScript';
import type InjectedScript from '../../server/injected/injectedScript';

export default class DebugScript {
consoleAPI: ConsoleAPI | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

const path = require('path');
const InlineSource = require('../../injected/webpack-inline-source-plugin');
const InlineSource = require('../../server/injected/webpack-inline-source-plugin');

module.exports = {
entry: path.join(__dirname, 'debugScript.ts'),
Expand All @@ -38,9 +38,9 @@ module.exports = {
output: {
libraryTarget: 'var',
filename: 'debugScriptSource.js',
path: path.resolve(__dirname, '../../../../lib/server/injected/packed')
path: path.resolve(__dirname, '../../../lib/server/injected/packed')
},
plugins: [
new InlineSource(path.join(__dirname, '..', '..', '..', 'generated', 'debugScriptSource.ts')),
new InlineSource(path.join(__dirname, '..', '..', 'generated', 'debugScriptSource.ts')),
]
};
File renamed without changes.
4 changes: 4 additions & 0 deletions src/inprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import { PlaywrightDispatcher } from './dispatchers/playwrightDispatcher';
import { Connection } from './client/connection';
import { BrowserServerLauncherImpl } from './browserServerImpl';
import { isDevMode } from './utils/utils';
import { instrumentingAgents } from './server/instrumentation';
import { DebugController } from './debug/debugController';

export function setupInProcess(playwright: PlaywrightImpl): PlaywrightAPI {
instrumentingAgents.add(new DebugController());

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

Expand Down
4 changes: 4 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import { Playwright } from './server/playwright';
import { PlaywrightDispatcher } from './dispatchers/playwrightDispatcher';
import { Electron } from './server/electron/electron';
import { gracefullyCloseAll } from './server/processLauncher';
import { instrumentingAgents } from './server/instrumentation';
import { DebugController } from './debug/debugController';

instrumentingAgents.add(new DebugController());

const dispatcherConnection = new DispatcherConnection();
const transport = new Transport(process.stdout, process.stdin);
Expand Down
19 changes: 5 additions & 14 deletions src/server/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ import { Download } from './download';
import { Browser } from './browser';
import { EventEmitter } from 'events';
import { Progress } from './progress';
import { DebugController } from './debug/debugController';
import { isDebugMode } from '../utils/utils';
import { Snapshotter, SnapshotterDelegate } from './snapshotter';
import { Selectors, serverSelectors } from './selectors';
import { instrumentingAgents } from './instrumentation';

export class Screencast {
readonly page: Page;
Expand Down Expand Up @@ -70,7 +68,6 @@ export abstract class BrowserContext extends EventEmitter {
readonly _browser: Browser;
readonly _browserContextId: string | undefined;
private _selectors?: Selectors;
_snapshotter?: Snapshotter;

constructor(browser: Browser, options: types.BrowserContextOptions, browserContextId: string | undefined) {
super();
Expand All @@ -90,14 +87,8 @@ export abstract class BrowserContext extends EventEmitter {
}

async _initialize() {
if (isDebugMode())
new DebugController(this);
}

// Used by test runner.
async _initSnapshotter(delegate: SnapshotterDelegate): Promise<Snapshotter> {
this._snapshotter = new Snapshotter(this, delegate);
return this._snapshotter;
for (const agent of instrumentingAgents)
await agent.onContextCreated(this);
}

_browserClosed() {
Expand Down Expand Up @@ -250,8 +241,8 @@ export abstract class BrowserContext extends EventEmitter {
this._closedStatus = 'closing';
await this._doClose();
await Promise.all([...this._downloads].map(d => d.delete()));
if (this._snapshotter)
this._snapshotter._dispose();
for (const agent of instrumentingAgents)
await agent.onContextDestroyed(this);
this._didCloseInternal();
}
await this._closePromise;
Expand Down
39 changes: 0 additions & 39 deletions src/server/debug/debugController.ts

This file was deleted.

14 changes: 0 additions & 14 deletions src/server/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ import * as frames from './frames';
import { assert } from '../utils/utils';
import type { InjectedScript, InjectedScriptPoll } from './injected/injectedScript';
import * as injectedScriptSource from '../generated/injectedScriptSource';
import * as debugScriptSource from '../generated/debugScriptSource';
import * as js from './javascript';
import { Page } from './page';
import { SelectorInfo } from './selectors';
import * as types from './types';
import { Progress } from './progress';
import type DebugScript from './debug/injected/debugScript';
import { FatalDOMError, RetargetableDOMError } from './common/domErrors';

export class FrameExecutionContext extends js.ExecutionContext {
Expand Down Expand Up @@ -92,18 +90,6 @@ export class FrameExecutionContext extends js.ExecutionContext {
return this._injectedScriptPromise;
}

createDebugScript(options: { console?: boolean }): Promise<js.JSHandle<DebugScript> | undefined> {
if (!this._debugScriptPromise) {
const source = `new (${debugScriptSource.source})()`;
this._debugScriptPromise = this._delegate.rawEvaluate(source).then(objectId => new js.JSHandle(this, 'object', objectId)).then(async debugScript => {
const injectedScript = await this.injectedScript();
await debugScript.evaluate((debugScript: DebugScript, { injectedScript, options }) => debugScript.initialize(injectedScript, options), { injectedScript, options });
return debugScript;
}).catch(e => undefined);
}
return this._debugScriptPromise;
}

async doSlowMo() {
return this.frame._page._doSlowMo();
}
Expand Down
27 changes: 27 additions & 0 deletions src/server/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* 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 { BrowserContext } from './browserContext';
import { Page } from './page';
import { Progress } from './progress';

export interface InstrumentingAgent {
onContextCreated(context: BrowserContext): Promise<void>;
onContextDestroyed(context: BrowserContext): Promise<void>;
onBeforePageAction(page: Page, progress: Progress): Promise<void>;
}

export const instrumentingAgents = new Set<InstrumentingAgent>();
5 changes: 3 additions & 2 deletions src/server/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { Progress, runAbortableTask } from './progress';
import { assert, isError } from '../utils/utils';
import { debugLogger } from '../utils/debugLogger';
import { Selectors } from './selectors';
import { instrumentingAgents } from './instrumentation';

export interface PageDelegate {
readonly rawMouse: input.RawMouse;
Expand Down Expand Up @@ -199,8 +200,8 @@ export class Page extends EventEmitter {

async _runAbortableTask<T>(task: (progress: Progress) => Promise<T>, timeout: number): Promise<T> {
return runAbortableTask(async progress => {
if (this._browserContext._snapshotter)
await this._browserContext._snapshotter._doSnapshot(progress, this, 'progress');
for (const agent of instrumentingAgents)
await agent.onBeforePageAction(this, progress);
return task(progress);
}, timeout);
}
Expand Down
43 changes: 16 additions & 27 deletions src/server/snapshotter.ts → src/trace/snapshotter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
* limitations under the License.
*/

import { BrowserContext } from './browserContext';
import { Page } from './page';
import * as network from './network';
import { helper, RegisteredListener } from './helper';
import { Progress, runAbortableTask } from './progress';
import { BrowserContext } from '../server/browserContext';
import { Page } from '../server/page';
import * as network from '../server/network';
import { helper, RegisteredListener } from '../server/helper';
import { Progress } from '../server/progress';
import { debugLogger } from '../utils/debugLogger';
import { Frame } from './frames';
import * as js from './javascript';
import * as types from './types';
import { Frame } from '../server/frames';
import * as js from '../server/javascript';
import { SnapshotData, takeSnapshotInFrame } from './snapshotterInjected';
import { assert, calculateSha1, createGuid } from '../utils/utils';

Expand Down Expand Up @@ -53,11 +52,9 @@ export type PageSnapshot = {
};

export interface SnapshotterDelegate {
onContextCreated(context: BrowserContext): void;
onContextDestroyed(context: BrowserContext): void;
onBlob(context: BrowserContext, blob: SnapshotterBlob): void;
onResource(context: BrowserContext, resource: SanpshotterResource): void;
onSnapshot(context: BrowserContext, snapshot: PageSnapshot): void;
onBlob(blob: SnapshotterBlob): void;
onResource(resource: SanpshotterResource): void;
onSnapshot(snapshot: PageSnapshot): void;
}

export class Snapshotter {
Expand All @@ -71,25 +68,17 @@ export class Snapshotter {
this._eventListeners = [
helper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)),
];
this._delegate.onContextCreated(this._context);
}

async captureSnapshot(page: Page, options: types.TimeoutOptions & { label?: string } = {}): Promise<void> {
return runAbortableTask(async progress => {
await this._doSnapshot(progress, page, options.label || 'snapshot');
}, page._timeoutSettings.timeout(options));
}

_dispose() {
dispose() {
helper.removeEventListeners(this._eventListeners);
this._delegate.onContextDestroyed(this._context);
}

async _doSnapshot(progress: Progress, page: Page, label: string): Promise<void> {
async takeSnapshot(progress: Progress, page: Page, label: string): Promise<void> {
assert(page.context() === this._context);
const snapshot = await this._snapshotPage(progress, page, label);
if (snapshot)
this._delegate.onSnapshot(this._context, snapshot);
this._delegate.onSnapshot(snapshot);
}

private _onPage(page: Page) {
Expand Down Expand Up @@ -124,9 +113,9 @@ export class Snapshotter {
responseHeaders: response.headers(),
sha1,
};
this._delegate.onResource(this._context, resource);
this._delegate.onResource(resource);
if (body)
this._delegate.onBlob(this._context, { sha1, buffer: body });
this._delegate.onBlob({ sha1, buffer: body });
}

private async _snapshotPage(progress: Progress, page: Page, label: string): Promise<PageSnapshot | null> {
Expand Down Expand Up @@ -214,7 +203,7 @@ export class Snapshotter {
for (const { url, content } of data.resourceOverrides) {
const buffer = Buffer.from(content);
const sha1 = calculateSha1(buffer);
this._delegate.onBlob(this._context, { sha1, buffer });
this._delegate.onBlob({ sha1, buffer });
snapshot.resourceOverrides.push({ url, sha1 });
}

Expand Down
File renamed without changes.
5 changes: 0 additions & 5 deletions src/trace/traceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
* limitations under the License.
*/

import type * as snapshotter from '../server/snapshotter';

export type ContextCreatedTraceEvent = {
type: 'context-created',
browserName: string,
Expand Down Expand Up @@ -46,6 +44,3 @@ export type SnapshotTraceEvent = {
label: string,
sha1: string,
};

export type FrameSnapshot = snapshotter.FrameSnapshot;
export type PageSnapshot = snapshotter.PageSnapshot;
Loading

0 comments on commit 675ce00

Please sign in to comment.