chore: report paused signal to the debug controller clients (#18701)

This commit is contained in:
Pavel Feldman 2022-11-10 12:15:29 -08:00 коммит произвёл GitHub
Родитель f52fa4ceba
Коммит ca2e7ef199
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 79 добавлений и 8 удалений

Просмотреть файл

@ -344,6 +344,9 @@ scheme.DebugControllerSourceChangedEvent = tObject({
footer: tOptional(tString),
actions: tOptional(tArray(tString)),
});
scheme.DebugControllerPausedEvent = tObject({
paused: tBoolean,
});
scheme.DebugControllerBrowsersChangedEvent = tObject({
browsers: tArray(tObject({
contexts: tArray(tObject({
@ -377,6 +380,8 @@ scheme.DebugControllerHighlightParams = tObject({
scheme.DebugControllerHighlightResult = tOptional(tObject({}));
scheme.DebugControllerHideHighlightParams = tOptional(tObject({}));
scheme.DebugControllerHideHighlightResult = tOptional(tObject({}));
scheme.DebugControllerResumeParams = tOptional(tObject({}));
scheme.DebugControllerResumeResult = tOptional(tObject({}));
scheme.DebugControllerKillParams = tOptional(tObject({}));
scheme.DebugControllerKillResult = tOptional(tObject({}));
scheme.DebugControllerCloseAllBrowsersParams = tOptional(tObject({}));

Просмотреть файл

@ -34,6 +34,7 @@ export class DebugController extends SdkObject {
StateChanged: 'stateChanged',
InspectRequested: 'inspectRequested',
SourceChanged: 'sourceChanged',
Paused: 'paused',
};
private _autoCloseTimer: NodeJS.Timeout | undefined;
@ -52,6 +53,7 @@ export class DebugController extends SdkObject {
initialize(codegenId: string, sdkLanguage: Language) {
this._codegenId = codegenId;
this._sdkLanguage = sdkLanguage;
Recorder.setAppFactory(async () => new InspectingRecorderApp(this));
}
setAutoCloseAllowed(allowed: boolean) {
@ -61,6 +63,7 @@ export class DebugController extends SdkObject {
dispose() {
this.setReportStateChanged(false);
this.setAutoCloseAllowed(false);
Recorder.setAppFactory(undefined);
}
setReportStateChanged(enabled: boolean) {
@ -157,6 +160,11 @@ export class DebugController extends SdkObject {
return [...this._playwright.allBrowsers()];
}
async resume() {
for (const recorder of await this._allRecorders())
recorder.resume();
}
async kill() {
selfDestruct();
}
@ -192,7 +200,7 @@ export class DebugController extends SdkObject {
const contexts = new Set<BrowserContext>();
for (const page of this._playwright.allPages())
contexts.add(page.context());
const result = await Promise.all([...contexts].map(c => Recorder.show(c, { omitCallTracking: true }, () => Promise.resolve(new InspectingRecorderApp(this)))));
const result = await Promise.all([...contexts].map(c => Recorder.show(c, { omitCallTracking: true })));
return result.filter(Boolean) as Recorder[];
}
@ -235,4 +243,8 @@ class InspectingRecorderApp extends EmptyRecorderApp {
const { text, header, footer, actions } = source || { text: '' };
this._debugController.emit(DebugController.Events.SourceChanged, { text, header, footer, actions });
}
override async setPaused(paused: boolean) {
this._debugController.emit(DebugController.Events.Paused, { paused });
}
}

Просмотреть файл

@ -83,6 +83,9 @@ export class Debugger extends EventEmitter implements InstrumentationListener {
}
resume(step: boolean) {
if (!this.isPaused())
return;
this._pauseOnNextStatement = step;
const endTime = monotonicTime();
for (const [metadata, { resolve }] of this._pausedCallsMetadata) {

Просмотреть файл

@ -34,6 +34,9 @@ export class DebugControllerDispatcher extends Dispatcher<DebugController, chann
this._object.on(DebugController.Events.SourceChanged, ({ text, header, footer, actions }) => {
this._dispatchEvent('sourceChanged', ({ text, header, footer, actions }));
});
this._object.on(DebugController.Events.Paused, ({ paused }) => {
this._dispatchEvent('paused', ({ paused }));
});
}
async initialize(params: channels.DebugControllerInitializeParams) {
@ -64,6 +67,10 @@ export class DebugControllerDispatcher extends Dispatcher<DebugController, chann
await this._object.hideHighlight();
}
async resume() {
await this._object.resume();
}
async kill() {
await this._object.kill();
}

Просмотреть файл

@ -58,27 +58,31 @@ export class Recorder implements InstrumentationListener {
private _debugger: Debugger;
private _contextRecorder: ContextRecorder;
private _handleSIGINT: boolean | undefined;
private _recorderAppFactory: (recorder: Recorder) => Promise<IRecorderApp>;
private _omitCallTracking = false;
private _currentLanguage: Language;
private static recorderAppFactory: ((recorder: Recorder) => Promise<IRecorderApp>) | undefined;
static setAppFactory(recorderAppFactory: ((recorder: Recorder) => Promise<IRecorderApp>) | undefined) {
Recorder.recorderAppFactory = recorderAppFactory;
}
static showInspector(context: BrowserContext) {
Recorder.show(context, {}).catch(() => {});
}
static show(context: BrowserContext, params: channels.BrowserContextRecorderSupplementEnableParams = {}, recorderAppFactory = Recorder.defaultRecorderAppFactory): Promise<Recorder> {
static show(context: BrowserContext, params: channels.BrowserContextRecorderSupplementEnableParams = {}): Promise<Recorder> {
let recorderPromise = (context as any)[recorderSymbol] as Promise<Recorder>;
if (!recorderPromise) {
const recorder = new Recorder(context, params, recorderAppFactory);
const recorder = new Recorder(context, params);
recorderPromise = recorder.install().then(() => recorder);
(context as any)[recorderSymbol] = recorderPromise;
}
return recorderPromise;
}
constructor(context: BrowserContext, params: channels.BrowserContextRecorderSupplementEnableParams, recorderAppFactory: (recorder: Recorder) => Promise<IRecorderApp>) {
constructor(context: BrowserContext, params: channels.BrowserContextRecorderSupplementEnableParams) {
this._mode = params.mode || 'none';
this._recorderAppFactory = recorderAppFactory;
this._contextRecorder = new ContextRecorder(context, params);
this._context = context;
this._omitCallTracking = !!params.omitCallTracking;
@ -95,7 +99,7 @@ export class Recorder implements InstrumentationListener {
}
async install() {
const recorderApp = await this._recorderAppFactory(this);
const recorderApp = await (Recorder.recorderAppFactory || Recorder.defaultRecorderAppFactory)(this);
this._recorderApp = recorderApp;
recorderApp.once('close', () => {
this._debugger.resume(false);
@ -215,6 +219,10 @@ export class Recorder implements InstrumentationListener {
this._refreshOverlay();
}
resume() {
this._debugger.resume(false);
}
setHighlightedSelector(language: Language, selector: string) {
this._highlightedSelector = locatorOrSelectorAsSelector(language, selector, this._contextRecorder.testIdAttributeName());
this._refreshOverlay();

Просмотреть файл

@ -592,6 +592,7 @@ export interface DebugControllerEventTarget {
on(event: 'inspectRequested', callback: (params: DebugControllerInspectRequestedEvent) => void): this;
on(event: 'stateChanged', callback: (params: DebugControllerStateChangedEvent) => void): this;
on(event: 'sourceChanged', callback: (params: DebugControllerSourceChangedEvent) => void): this;
on(event: 'paused', callback: (params: DebugControllerPausedEvent) => void): this;
on(event: 'browsersChanged', callback: (params: DebugControllerBrowsersChangedEvent) => void): this;
}
export interface DebugControllerChannel extends DebugControllerEventTarget, Channel {
@ -603,6 +604,7 @@ export interface DebugControllerChannel extends DebugControllerEventTarget, Chan
setRecorderMode(params: DebugControllerSetRecorderModeParams, metadata?: Metadata): Promise<DebugControllerSetRecorderModeResult>;
highlight(params: DebugControllerHighlightParams, metadata?: Metadata): Promise<DebugControllerHighlightResult>;
hideHighlight(params?: DebugControllerHideHighlightParams, metadata?: Metadata): Promise<DebugControllerHideHighlightResult>;
resume(params?: DebugControllerResumeParams, metadata?: Metadata): Promise<DebugControllerResumeResult>;
kill(params?: DebugControllerKillParams, metadata?: Metadata): Promise<DebugControllerKillResult>;
closeAllBrowsers(params?: DebugControllerCloseAllBrowsersParams, metadata?: Metadata): Promise<DebugControllerCloseAllBrowsersResult>;
}
@ -619,6 +621,9 @@ export type DebugControllerSourceChangedEvent = {
footer?: string,
actions?: string[],
};
export type DebugControllerPausedEvent = {
paused: boolean,
};
export type DebugControllerBrowsersChangedEvent = {
browsers: {
contexts: {
@ -669,6 +674,9 @@ export type DebugControllerHighlightResult = void;
export type DebugControllerHideHighlightParams = {};
export type DebugControllerHideHighlightOptions = {};
export type DebugControllerHideHighlightResult = void;
export type DebugControllerResumeParams = {};
export type DebugControllerResumeOptions = {};
export type DebugControllerResumeResult = void;
export type DebugControllerKillParams = {};
export type DebugControllerKillOptions = {};
export type DebugControllerKillResult = void;
@ -680,6 +688,7 @@ export interface DebugControllerEvents {
'inspectRequested': DebugControllerInspectRequestedEvent;
'stateChanged': DebugControllerStateChangedEvent;
'sourceChanged': DebugControllerSourceChangedEvent;
'paused': DebugControllerPausedEvent;
'browsersChanged': DebugControllerBrowsersChangedEvent;
}

Просмотреть файл

@ -700,6 +700,8 @@ DebugController:
hideHighlight:
resume:
kill:
closeAllBrowsers:
@ -722,7 +724,10 @@ DebugController:
actions:
type: array?
items: string
paused:
parameters:
paused: boolean
# Deprecated
browsersChanged:

Просмотреть файл

@ -137,6 +137,10 @@ export class Backend extends EventEmitter {
};
}
async initialize() {
await this._send('initialize', { codegenId: 'playwright-test', sdkLanguage: 'javascript' });
}
async close() {
await this._transport.closeAndWait();
}
@ -165,6 +169,10 @@ export class Backend extends EventEmitter {
await this._send('hideHighlight');
}
async resume() {
this._send('resume');
}
async kill() {
this._send('kill');
}

Просмотреть файл

@ -37,6 +37,7 @@ const test = baseTest.extend<Fixtures>({
backend: async ({ wsEndpoint }, use) => {
const backend = new Backend();
await backend.connect(wsEndpoint);
await backend.initialize();
await use(backend);
await backend.close();
},
@ -212,3 +213,16 @@ test('test', async ({ page }) => {
});`
});
});
test('should pause and resume', async ({ backend, connectedBrowser }) => {
const events = [];
backend.on('paused', event => events.push(event));
const context = await connectedBrowser._newContextForReuse();
const page = await context.newPage();
await page.setContent('<button>Submit</button>');
const pausePromise = page.pause();
await expect.poll(() => events[events.length - 1]).toEqual({ paused: true });
await backend.resume();
await pausePromise;
});