Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rpc): pass more tests #2896

Merged
merged 1 commit into from Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 6 additions & 30 deletions src/chromium/crCoverage.ts
Expand Up @@ -21,30 +21,6 @@ import { Protocol } from './protocol';
import * as types from '../types';
import * as sourceMap from '../utils/sourceMap';

type JSRange = {
startOffset: number,
endOffset: number,
count: number
}

type CSSCoverageEntry = {
url: string,
text?: string,
ranges: {
start: number,
end: number
}[]
};

type JSCoverageEntry = {
url: string,
source?: string,
functions: {
functionName: string,
ranges: JSRange[]
}[]
};

export class CRCoverage {
private _jsCoverage: JSCoverage;
private _cssCoverage: CSSCoverage;
Expand All @@ -58,15 +34,15 @@ export class CRCoverage {
return await this._jsCoverage.start(options);
}

async stopJSCoverage(): Promise<JSCoverageEntry[]> {
async stopJSCoverage(): Promise<types.JSCoverageEntry[]> {
return await this._jsCoverage.stop();
}

async startCSSCoverage(options?: types.CSSCoverageOptions) {
return await this._cssCoverage.start(options);
}

async stopCSSCoverage(): Promise<CSSCoverageEntry[]> {
async stopCSSCoverage(): Promise<types.CSSCoverageEntry[]> {
return await this._cssCoverage.stop();
}
}
Expand Down Expand Up @@ -134,7 +110,7 @@ class JSCoverage {
this._scriptSources.set(event.scriptId, response.scriptSource);
}

async stop(): Promise<JSCoverageEntry[]> {
async stop(): Promise<types.JSCoverageEntry[]> {
assert(this._enabled, 'JSCoverage is not enabled');
this._enabled = false;
const [profileResponse] = await Promise.all([
Expand All @@ -145,7 +121,7 @@ class JSCoverage {
] as const);
helper.removeEventListeners(this._eventListeners);

const coverage: JSCoverageEntry[] = [];
const coverage: types.JSCoverageEntry[] = [];
for (const entry of profileResponse.result) {
if (!this._scriptIds.has(entry.scriptId))
continue;
Expand Down Expand Up @@ -216,7 +192,7 @@ class CSSCoverage {
}
}

async stop(): Promise<CSSCoverageEntry[]> {
async stop(): Promise<types.CSSCoverageEntry[]> {
assert(this._enabled, 'CSSCoverage is not enabled');
this._enabled = false;
const ruleTrackingResponse = await this._client.send('CSS.stopRuleUsageTracking');
Expand All @@ -241,7 +217,7 @@ class CSSCoverage {
});
}

const coverage: CSSCoverageEntry[] = [];
const coverage: types.CSSCoverageEntry[] = [];
for (const styleSheetId of this._stylesheetURLs.keys()) {
const url = this._stylesheetURLs.get(styleSheetId)!;
const text = this._stylesheetSources.get(styleSheetId)!;
Expand Down
8 changes: 7 additions & 1 deletion src/rpc/channels.ts
Expand Up @@ -64,6 +64,8 @@ export interface BrowserChannel extends Channel {
newContext(params: types.BrowserContextOptions): Promise<BrowserContextChannel>;

crNewBrowserCDPSession(): Promise<CDPSessionChannel>;
crStartTracing(params: { page?: PageChannel, path?: string, screenshots?: boolean, categories?: string[] }): Promise<void>;
crStopTracing(): Promise<Binary>;
}
export type BrowserInitializer = {};

Expand Down Expand Up @@ -154,9 +156,13 @@ export interface PageChannel extends Channel {
mouseUp(params: { button?: types.MouseButton, clickCount?: number }): Promise<void>;
mouseClick(params: { x: number, y: number, delay?: number, button?: types.MouseButton, clickCount?: number }): Promise<void>;

// A11Y
accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<types.SerializedAXNode | null>;
pdf: (params: types.PDFOptions) => Promise<Binary>;

crStartJSCoverage(params: types.JSCoverageOptions): Promise<void>;
crStopJSCoverage(): Promise<types.JSCoverageEntry[]>;
crStartCSSCoverage(params: types.CSSCoverageOptions): Promise<void>;
crStopCSSCoverage(): Promise<types.CSSCoverageEntry[]>;
}

export type PageInitializer = {
Expand Down
20 changes: 15 additions & 5 deletions src/rpc/client/browser.ts
Expand Up @@ -27,7 +27,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
readonly _contexts = new Set<BrowserContext>();
private _isConnected = true;
private _isClosedOrClosing = false;

private _closedPromise: Promise<void>;

static from(browser: BrowserChannel): Browser {
return (browser as any)._object;
Expand All @@ -45,6 +45,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
this._isClosedOrClosing = true;
this._scope.dispose();
});
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
}

async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
Expand Down Expand Up @@ -73,13 +74,22 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
}

async close(): Promise<void> {
if (this._isClosedOrClosing)
return;
this._isClosedOrClosing = true;
await this._channel.close();
if (!this._isClosedOrClosing) {
this._isClosedOrClosing = true;
await this._channel.close();
}
await this._closedPromise;
}

async newBrowserCDPSession(): Promise<CDPSession> {
return CDPSession.from(await this._channel.crNewBrowserCDPSession());
}

async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
await this._channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
}

async stopTracing(): Promise<Buffer> {
return Buffer.from(await this._channel.crStopTracing(), 'base64');
}
}
10 changes: 9 additions & 1 deletion src/rpc/client/browserContext.ts
Expand Up @@ -40,6 +40,8 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
private _pendingWaitForEvents = new Map<(error: Error) => void, string>();
_timeoutSettings = new TimeoutSettings();
_ownerPage: Page | undefined;
private _isClosedOrClosing = false;
private _closedPromise: Promise<void>;

static from(context: BrowserContextChannel): BrowserContext {
return (context as any)._object;
Expand All @@ -60,6 +62,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
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._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));

initializer.crBackgroundPages.forEach(p => {
const page = Page.from(p);
Expand Down Expand Up @@ -211,6 +214,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
}

private async _onClose() {
this._isClosedOrClosing = true;
if (this._browser)
this._browser._contexts.delete(this);

Expand All @@ -225,7 +229,11 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
}

async close(): Promise<void> {
await this._channel.close();
if (!this._isClosedOrClosing) {
this._isClosedOrClosing = true;
await this._channel.close();
}
await this._closedPromise;
}

async newCDPSession(page: Page): Promise<CDPSession> {
Expand Down
42 changes: 42 additions & 0 deletions src/rpc/client/coverage.ts
@@ -0,0 +1,42 @@
/**
* 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 * as types from '../../types';
import { PageChannel } from '../channels';

export class Coverage {
private _channel: PageChannel;

constructor(channel: PageChannel) {
this._channel = channel;
}

async startJSCoverage(options: types.JSCoverageOptions = {}) {
await this._channel.crStartJSCoverage(options);
}

async stopJSCoverage(): Promise<types.JSCoverageEntry[]> {
return await this._channel.crStopJSCoverage();
}

async startCSSCoverage(options: types.CSSCoverageOptions = {}) {
await this._channel.crStartCSSCoverage(options);
}

async stopCSSCoverage(): Promise<types.CSSCoverageEntry[]> {
return await this._channel.crStopCSSCoverage();
}
}
3 changes: 3 additions & 0 deletions src/rpc/client/page.ts
Expand Up @@ -38,6 +38,7 @@ import { Func1, FuncOn, SmartHandle } from './jsHandle';
import { Request, Response, Route, RouteHandler } from './network';
import { FileChooser } from './fileChooser';
import { Buffer } from 'buffer';
import { Coverage } from './coverage';

export class Page extends ChannelOwner<PageChannel, PageInitializer> {

Expand All @@ -54,6 +55,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
readonly accessibility: Accessibility;
readonly keyboard: Keyboard;
readonly mouse: Mouse;
readonly coverage: Coverage;
readonly _bindings = new Map<string, FunctionWithSource>();
private _pendingWaitForEvents = new Map<(error: Error) => void, string>();
private _timeoutSettings = new TimeoutSettings();
Expand All @@ -72,6 +74,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
this.accessibility = new Accessibility(this._channel);
this.keyboard = new Keyboard(this._channel);
this.mouse = new Mouse(this._channel);
this.coverage = new Coverage(this._channel);
dgozman marked this conversation as resolved.
Show resolved Hide resolved

this._mainFrame = Frame.from(initializer.mainFrame);
this._mainFrame._page = this;
Expand Down
14 changes: 13 additions & 1 deletion src/rpc/server/browserDispatcher.ts
Expand Up @@ -18,11 +18,12 @@ import { Browser, BrowserBase } from '../../browser';
import { BrowserContextBase } from '../../browserContext';
import { Events } from '../../events';
import * as types from '../../types';
import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel } from '../channels';
import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel, Binary } from '../channels';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { Dispatcher, DispatcherScope } from './dispatcher';
import { CRBrowser } from '../../chromium/crBrowser';
import { PageDispatcher } from './pageDispatcher';

export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> implements BrowserChannel {
constructor(scope: DispatcherScope, browser: BrowserBase) {
Expand All @@ -45,4 +46,15 @@ export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> i
const crBrowser = this._object as CRBrowser;
return new CDPSessionDispatcher(this._scope, await crBrowser.newBrowserCDPSession());
}

async crStartTracing(params: { page?: PageDispatcher, path?: string, screenshots?: boolean, categories?: string[] }): Promise<void> {
const crBrowser = this._object as CRBrowser;
await crBrowser.startTracing(params.page ? params.page._object : undefined, params);
}

async crStopTracing(): Promise<Binary> {
const crBrowser = this._object as CRBrowser;
const buffer = await crBrowser.stopTracing();
return buffer.toString('base64');
}
}
23 changes: 22 additions & 1 deletion src/rpc/server/pageDispatcher.ts
Expand Up @@ -31,6 +31,7 @@ import { RequestDispatcher, ResponseDispatcher, RouteDispatcher } from './networ
import { serializeResult, parseArgument } from './jsHandleDispatcher';
import { ElementHandleDispatcher, createHandle } from './elementHandlerDispatcher';
import { FileChooser } from '../../fileChooser';
import { CRCoverage } from '../../chromium/crCoverage';

export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements PageChannel {
private _page: Page;
Expand Down Expand Up @@ -125,7 +126,7 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
});
}

async screenshot(params: types.ScreenshotOptions): Promise<string> {
async screenshot(params: types.ScreenshotOptions): Promise<Binary> {
return (await this._page.screenshot(params)).toString('base64');
}

Expand Down Expand Up @@ -190,6 +191,26 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
return binary.toString('base64');
}

async crStartJSCoverage(params: types.JSCoverageOptions): Promise<void> {
const coverage = this._page.coverage as CRCoverage;
await coverage.startJSCoverage(params);
}

async crStopJSCoverage(): Promise<types.JSCoverageEntry[]> {
const coverage = this._page.coverage as CRCoverage;
return await coverage.stopJSCoverage();
}

async crStartCSSCoverage(params: types.CSSCoverageOptions): Promise<void> {
const coverage = this._page.coverage as CRCoverage;
await coverage.startCSSCoverage(params);
}

async crStopCSSCoverage(): Promise<types.CSSCoverageEntry[]> {
const coverage = this._page.coverage as CRCoverage;
return await coverage.stopCSSCoverage();
}

_onFrameAttached(frame: Frame) {
this._dispatchEvent('frameAttached', FrameDispatcher.from(this._scope, frame));
}
Expand Down
30 changes: 24 additions & 6 deletions src/types.ts
Expand Up @@ -123,12 +123,6 @@ export type PDFOptions = {
path?: string,
}

export type CoverageEntry = {
url: string,
text: string,
ranges: {start: number, end: number}[]
};

export type CSSCoverageOptions = {
resetOnNavigation?: boolean,
};
Expand All @@ -138,6 +132,30 @@ export type JSCoverageOptions = {
reportAnonymousScripts?: boolean,
};

export type JSRange = {
startOffset: number,
endOffset: number,
count: number
};

export type CSSCoverageEntry = {
url: string,
text?: string,
ranges: {
start: number,
end: number
}[]
};

export type JSCoverageEntry = {
url: string,
source?: string,
functions: {
functionName: string,
ranges: JSRange[]
}[]
};

export type InjectedScriptProgress = {
aborted: boolean,
log: (message: string) => void,
Expand Down
2 changes: 1 addition & 1 deletion test/browsercontext.spec.js
Expand Up @@ -121,7 +121,7 @@ describe('BrowserContext', function() {
let error = await promise;
expect(error.message).toContain('Context closed');
});
it.fail(CHANNEL)('close() should be callable twice', async({browser}) => {
it('close() should be callable twice', async({browser}) => {
const context = await browser.newContext();
await Promise.all([
context.close(),
Expand Down