mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-15 06:02:57 +03:00
feat(inspector): render api names from metainfo (#5530)
This commit is contained in:
parent
d6ac3e6883
commit
600f731a67
@ -239,7 +239,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
|
||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(this, event);
|
||||
const waiter = Waiter.createForEvent(this, 'androidDevice', event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.AndroidDevice.Close)
|
||||
waiter.rejectOnEvent(this, Events.AndroidDevice.Close, new Error('Device closed'));
|
||||
|
@ -217,7 +217,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(this, event);
|
||||
const waiter = Waiter.createForEvent(this, 'browserContext', event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.BrowserContext.Close)
|
||||
waiter.rejectOnEvent(this, Events.BrowserContext.Close, new Error('Context closed'));
|
||||
@ -256,12 +256,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
}
|
||||
}
|
||||
|
||||
async _pause() {
|
||||
return this._wrapApiCall('browserContext.pause', async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.pause();
|
||||
});
|
||||
}
|
||||
|
||||
async _enableRecorder(params: {
|
||||
language: string,
|
||||
launchOptions?: LaunchOptions,
|
||||
|
@ -48,20 +48,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
this._logger = this._parent._logger;
|
||||
}
|
||||
|
||||
const base = new EventEmitter();
|
||||
this._channel = new Proxy(base, {
|
||||
get: (obj: any, prop) => {
|
||||
if (prop === 'debugScopeState')
|
||||
return (params: any) => this._connection.sendMessageToServer(guid, prop, params);
|
||||
if (typeof prop === 'string') {
|
||||
const validator = scheme[paramsName(type, prop)];
|
||||
if (validator)
|
||||
return (params: any) => this._connection.sendMessageToServer(guid, prop, validator(params, ''));
|
||||
}
|
||||
return obj[prop];
|
||||
},
|
||||
});
|
||||
(this._channel as any)._object = this;
|
||||
this._channel = this._createChannel(new EventEmitter(), '');
|
||||
this._initializer = initializer;
|
||||
}
|
||||
|
||||
@ -84,11 +71,29 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
};
|
||||
}
|
||||
|
||||
async _wrapApiCall<T, K extends channels.Channel>(apiName: string, func: (channel: K) => Promise<T>, logger?: Logger): Promise<T> {
|
||||
_createChannel(base: Object, apiName: string): T {
|
||||
const channel = new Proxy(base, {
|
||||
get: (obj: any, prop) => {
|
||||
if (prop === 'debugScopeState')
|
||||
return (params: any) => this._connection.sendMessageToServer(this._guid, prop, params, apiName);
|
||||
if (typeof prop === 'string') {
|
||||
const validator = scheme[paramsName(this._type, prop)];
|
||||
if (validator)
|
||||
return (params: any) => this._connection.sendMessageToServer(this._guid, prop, validator(params, ''), apiName);
|
||||
}
|
||||
return obj[prop];
|
||||
},
|
||||
});
|
||||
(channel as any)._object = this;
|
||||
return channel;
|
||||
}
|
||||
|
||||
async _wrapApiCall<R, C extends channels.Channel>(apiName: string, func: (channel: C) => Promise<R>, logger?: Logger): Promise<R> {
|
||||
logger = logger || this._logger;
|
||||
try {
|
||||
logApiCall(logger, `=> ${apiName} started`);
|
||||
const result = await func(this._channel as any);
|
||||
const channel = this._createChannel({}, apiName);
|
||||
const result = await func(channel as any);
|
||||
logApiCall(logger, `<= ${apiName} succeeded`);
|
||||
return result;
|
||||
} catch (e) {
|
||||
@ -99,15 +104,15 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
}
|
||||
|
||||
_waitForEventInfoBefore(waitId: string, name: string, stack: StackFrame[]) {
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { name, waitId, phase: 'before', stack } }).catch(() => {});
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { name, waitId, phase: 'before', stack } }, undefined).catch(() => {});
|
||||
}
|
||||
|
||||
_waitForEventInfoAfter(waitId: string, error?: string) {
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { waitId, phase: 'after', error } }).catch(() => {});
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { waitId, phase: 'after', error } }, undefined).catch(() => {});
|
||||
}
|
||||
|
||||
_waitForEventInfoLog(waitId: string, message: string) {
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { waitId, phase: 'log', message } }).catch(() => {});
|
||||
this._connection.sendMessageToServer(this._guid, 'waitForEventInfo', { info: { waitId, phase: 'log', message } }, undefined).catch(() => {});
|
||||
}
|
||||
|
||||
private toJSON() {
|
||||
|
@ -71,13 +71,13 @@ export class Connection {
|
||||
return this._objects.get(guid)!;
|
||||
}
|
||||
|
||||
async sendMessageToServer(guid: string, method: string, params: any): Promise<any> {
|
||||
async sendMessageToServer(guid: string, method: string, params: any, apiName: string | undefined): Promise<any> {
|
||||
const { stack, frames } = captureStackTrace();
|
||||
const id = ++this._lastId;
|
||||
const converted = { id, guid, method, params };
|
||||
// Do not include metadata in debug logs to avoid noise.
|
||||
debugLogger.log('channel:command', converted);
|
||||
this.onmessage({ ...converted, metadata: { stack: frames } });
|
||||
this.onmessage({ ...converted, metadata: { stack: frames, apiName } });
|
||||
try {
|
||||
return await new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject }));
|
||||
} catch (e) {
|
||||
|
@ -101,7 +101,7 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(this, event);
|
||||
const waiter = Waiter.createForEvent(this, 'electronApplication', event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.ElectronApplication.Close)
|
||||
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, new Error('Electron application closed'));
|
||||
|
@ -113,7 +113,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
|
||||
async waitForNavigation(options: WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||
return this._wrapApiCall(this._apiName('waitForNavigation'), async (channel: channels.FrameChannel) => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
const waiter = this._setupNavigationWaiter('waitForNavigation', options);
|
||||
const waiter = this._setupNavigationWaiter(this._apiName('waitForNavigation'), options);
|
||||
|
||||
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
||||
waiter.log(`waiting for navigation${toUrl} until "${waitUntil}"`);
|
||||
@ -150,7 +150,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
|
||||
if (this._loadStates.has(state))
|
||||
return;
|
||||
return this._wrapApiCall(this._apiName('waitForLoadState'), async (channel: channels.FrameChannel) => {
|
||||
const waiter = this._setupNavigationWaiter('waitForLoadState', options);
|
||||
const waiter = this._setupNavigationWaiter(this._apiName('waitForLoadState'), options);
|
||||
await waiter.waitForEvent<LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
return s === state;
|
||||
|
@ -365,7 +365,7 @@ export class WebSocket extends ChannelOwner<channels.WebSocketChannel, channels.
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._page._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(this, event);
|
||||
const waiter = Waiter.createForEvent(this, 'webSocket', event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.WebSocket.Error)
|
||||
waiter.rejectOnEvent(this, Events.WebSocket.Error, new Error('Socket error'));
|
||||
|
@ -397,7 +397,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
|
||||
private async _waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions, logLine?: string): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(this, event);
|
||||
const waiter = Waiter.createForEvent(this, 'page', event);
|
||||
if (logLine)
|
||||
waiter.log(logLine);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
@ -644,7 +644,9 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
|
||||
}
|
||||
|
||||
async pause() {
|
||||
await this.context()._pause();
|
||||
return this.context()._wrapApiCall('page.pause', async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.pause();
|
||||
});
|
||||
}
|
||||
|
||||
async _pdf(options: PDFOptions = {}): Promise<Buffer> {
|
||||
|
@ -38,8 +38,8 @@ export class Waiter {
|
||||
];
|
||||
}
|
||||
|
||||
static createForEvent(channelOwner: ChannelOwner, event: string) {
|
||||
return new Waiter(channelOwner, `waitForEvent(${event})`);
|
||||
static createForEvent(channelOwner: ChannelOwner, target: string, event: string) {
|
||||
return new Waiter(channelOwner, `${target}.waitForEvent(${event})`);
|
||||
}
|
||||
|
||||
async waitForEvent<T = void>(emitter: EventEmitter, event: string, predicate?: (arg: T) => boolean): Promise<T> {
|
||||
|
@ -32,6 +32,7 @@ export type StackFrame = {
|
||||
|
||||
export type Metadata = {
|
||||
stack?: StackFrame[],
|
||||
apiName?: string,
|
||||
};
|
||||
|
||||
export type WaitForEventInfo = {
|
||||
|
@ -28,6 +28,7 @@ Metadata:
|
||||
stack:
|
||||
type: array?
|
||||
items: StackFrame
|
||||
apiName: string?
|
||||
|
||||
|
||||
WaitForEventInfo:
|
||||
|
@ -41,6 +41,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||
});
|
||||
scheme.Metadata = tObject({
|
||||
stack: tOptional(tArray(tType('StackFrame'))),
|
||||
apiName: tOptional(tString),
|
||||
});
|
||||
scheme.WaitForEventInfo = tObject({
|
||||
waitId: tString,
|
||||
|
@ -39,6 +39,7 @@ export type CallMetadata = {
|
||||
type: string;
|
||||
method: string;
|
||||
params: any;
|
||||
apiName?: string;
|
||||
stack?: StackFrame[];
|
||||
log: string[];
|
||||
error?: string;
|
||||
|
@ -434,7 +434,7 @@ export class RecorderSupplement {
|
||||
for (const metadata of metadatas) {
|
||||
if (!metadata.method)
|
||||
continue;
|
||||
const title = metadata.method;
|
||||
const title = metadata.apiName || metadata.method;
|
||||
let status: 'done' | 'in-progress' | 'paused' | 'error' = 'done';
|
||||
if (this._currentCallsMetadata.has(metadata))
|
||||
status = 'in-progress';
|
||||
@ -452,7 +452,8 @@ export class RecorderSupplement {
|
||||
logs.push({
|
||||
id: metadata.id,
|
||||
messages: metadata.log,
|
||||
title, status,
|
||||
title,
|
||||
status,
|
||||
error: metadata.error,
|
||||
params,
|
||||
duration
|
||||
|
@ -155,9 +155,9 @@ describe('pause', (suite, { mode }) => {
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")');
|
||||
expect(await sanitizeLog(recorderPage)).toEqual([
|
||||
'pause- XXms',
|
||||
'click(button)- XXms',
|
||||
'pause',
|
||||
'page.pause- XXms',
|
||||
'page.click(button)- XXms',
|
||||
'page.pause',
|
||||
]);
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
await scriptPromise;
|
||||
@ -177,10 +177,10 @@ describe('pause', (suite, { mode }) => {
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")');
|
||||
expect(await sanitizeLog(recorderPage)).toEqual([
|
||||
'pause- XXms',
|
||||
'waitForEvent(console)- XXms',
|
||||
'click(button)- XXms',
|
||||
'pause',
|
||||
'page.pause- XXms',
|
||||
'page.waitForEvent(console)- XXms',
|
||||
'page.click(button)- XXms',
|
||||
'page.pause',
|
||||
]);
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
await scriptPromise;
|
||||
@ -196,8 +196,8 @@ describe('pause', (suite, { mode }) => {
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
await recorderPage.waitForSelector('.source-line-error');
|
||||
expect(await sanitizeLog(recorderPage)).toEqual([
|
||||
'pause- XXms',
|
||||
'isChecked(button)- XXms',
|
||||
'page.pause- XXms',
|
||||
'page.isChecked(button)- XXms',
|
||||
'checking \"checked\" state of \"button\"',
|
||||
'selector resolved to <button onclick=\"console.log(1)\">Submit</button>',
|
||||
'Not a checkbox or radio button',
|
||||
|
Loading…
Reference in New Issue
Block a user