chore: report paused signal to the debug controller clients (#18701)
This commit is contained in:
Родитель
f52fa4ceba
Коммит
ca2e7ef199
|
@ -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;
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче