From adb2e19b4d1714175e4cc3644562ca5a233586cd Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 14 Oct 2024 11:07:52 -0700 Subject: [PATCH] chore: fix codegen selector while debugging --- .../playwright-core/src/server/recorder.ts | 3 ++- .../src/server/recorder/recorderApp.ts | 6 ++--- .../src/server/recorder/recorderFrontend.ts | 2 +- .../server/recorder/recorderInTraceViewer.ts | 4 ++-- packages/recorder/src/recorder.tsx | 18 +++++++------- packages/recorder/src/recorderTypes.ts | 2 +- packages/web/src/components/sourceChooser.tsx | 24 +++++++++++-------- packages/web/src/components/toolbarButton.tsx | 3 +++ tests/library/inspector/pause.spec.ts | 16 +++++++++++++ 9 files changed, 50 insertions(+), 28 deletions(-) diff --git a/packages/playwright-core/src/server/recorder.ts b/packages/playwright-core/src/server/recorder.ts index 4aab712b9bd64..386e4dece6f1d 100644 --- a/packages/playwright-core/src/server/recorder.ts +++ b/packages/playwright-core/src/server/recorder.ts @@ -140,6 +140,7 @@ export class Recorder implements InstrumentationListener, IRecorder { this._contextRecorder.on(ContextRecorder.Events.Change, (data: { sources: Source[], actions: actions.ActionInContext[] }) => { this._recorderSources = data.sources; recorderApp.setActions(data.actions, data.sources); + recorderApp.setRunningFile(undefined); this._pushAllSources(); }); @@ -299,7 +300,7 @@ export class Recorder implements InstrumentationListener, IRecorder { } this._pushAllSources(); if (fileToSelect) - this._recorderApp?.setFile(fileToSelect); + this._recorderApp?.setRunningFile(fileToSelect); } private _pushAllSources() { diff --git a/packages/playwright-core/src/server/recorder/recorderApp.ts b/packages/playwright-core/src/server/recorder/recorderApp.ts index 30149f9816ca2..3f9a636579efe 100644 --- a/packages/playwright-core/src/server/recorder/recorderApp.ts +++ b/packages/playwright-core/src/server/recorder/recorderApp.ts @@ -34,7 +34,7 @@ export class EmptyRecorderApp extends EventEmitter implements IRecorderApp { async close(): Promise {} async setPaused(paused: boolean): Promise {} async setMode(mode: Mode): Promise {} - async setFile(file: string): Promise {} + async setRunningFile(file: string | undefined): Promise {} async setSelector(selector: string, userGesture?: boolean): Promise {} async updateCallLogs(callLogs: CallLog[]): Promise {} async setSources(sources: Source[]): Promise {} @@ -131,9 +131,9 @@ export class RecorderApp extends EventEmitter implements IRecorderApp { }).toString(), { isFunction: true }, mode).catch(() => {}); } - async setFile(file: string): Promise { + async setRunningFile(file: string | undefined): Promise { await this._page.mainFrame().evaluateExpression(((file: string) => { - window.playwrightSetFile(file); + window.playwrightSetRunningFile(file); }).toString(), { isFunction: true }, file).catch(() => {}); } diff --git a/packages/playwright-core/src/server/recorder/recorderFrontend.ts b/packages/playwright-core/src/server/recorder/recorderFrontend.ts index 97df1d3ceb6c4..9bf48022a7087 100644 --- a/packages/playwright-core/src/server/recorder/recorderFrontend.ts +++ b/packages/playwright-core/src/server/recorder/recorderFrontend.ts @@ -28,7 +28,7 @@ export interface IRecorderApp extends EventEmitter { close(): Promise; setPaused(paused: boolean): Promise; setMode(mode: Mode): Promise; - setFile(file: string): Promise; + setRunningFile(file: string | undefined): Promise; setSelector(selector: string, userGesture?: boolean): Promise; updateCallLogs(callLogs: CallLog[]): Promise; setSources(sources: Source[]): Promise; diff --git a/packages/playwright-core/src/server/recorder/recorderInTraceViewer.ts b/packages/playwright-core/src/server/recorder/recorderInTraceViewer.ts index ab67fe562cf7f..e11ef1283a80f 100644 --- a/packages/playwright-core/src/server/recorder/recorderInTraceViewer.ts +++ b/packages/playwright-core/src/server/recorder/recorderInTraceViewer.ts @@ -66,8 +66,8 @@ export class RecorderInTraceViewer extends EventEmitter implements IRecorderApp this._transport.deliverEvent('setMode', { mode }); } - async setFile(file: string): Promise { - this._transport.deliverEvent('setFileIfNeeded', { file }); + async setRunningFile(file: string | undefined): Promise { + this._transport.deliverEvent('setRunningFile', { file }); } async setSelector(selector: string, userGesture?: boolean): Promise { diff --git a/packages/recorder/src/recorder.tsx b/packages/recorder/src/recorder.tsx index 9d5c0feebac94..19b7bc12a70ad 100644 --- a/packages/recorder/src/recorder.tsx +++ b/packages/recorder/src/recorder.tsx @@ -41,13 +41,11 @@ export const Recorder: React.FC = ({ log, mode, }) => { - const [fileId, setFileId] = React.useState(); + const [selectedFileId, setSelectedFileId] = React.useState(); + const [runningFileId, setRunningFileId] = React.useState(); const [selectedTab, setSelectedTab] = React.useState('log'); - React.useEffect(() => { - if (!fileId && sources.length > 0) - setFileId(sources[0].id); - }, [fileId, sources]); + const fileId = selectedFileId || runningFileId || sources[0]?.id; const source = React.useMemo(() => { if (fileId) { @@ -66,7 +64,7 @@ export const Recorder: React.FC = ({ setLocator(asLocator(language, selector)); }; - window.playwrightSetFile = setFileId; + window.playwrightSetRunningFile = setRunningFileId; const messagesEndRef = React.useRef(null); React.useLayoutEffect(() => { @@ -134,19 +132,19 @@ export const Recorder: React.FC = ({ { copy(source.text); }}> - { + { window.dispatch({ event: 'resume' }); }}> - { + { window.dispatch({ event: 'pause' }); }}> - { + { window.dispatch({ event: 'step' }); }}>
Target:
{ - setFileId(fileId); + setSelectedFileId(fileId); window.dispatch({ event: 'fileChanged', params: { file: fileId } }); }} /> { diff --git a/packages/recorder/src/recorderTypes.ts b/packages/recorder/src/recorderTypes.ts index a5791e2306522..dd379f7ccd7ee 100644 --- a/packages/recorder/src/recorderTypes.ts +++ b/packages/recorder/src/recorderTypes.ts @@ -96,7 +96,7 @@ declare global { playwrightSetSources: (sources: Source[]) => void; playwrightSetOverlayVisible: (visible: boolean) => void; playwrightUpdateLogs: (callLogs: CallLog[]) => void; - playwrightSetFile: (file: string) => void; + playwrightSetRunningFile: (file: string | undefined) => void; playwrightSetSelector: (selector: string, focus?: boolean) => void; playwrightSourcesEchoForTest: Source[]; dispatch(data: any): Promise; diff --git a/packages/web/src/components/sourceChooser.tsx b/packages/web/src/components/sourceChooser.tsx index 0645480a03c65..22b91c61a511b 100644 --- a/packages/web/src/components/sourceChooser.tsx +++ b/packages/web/src/components/sourceChooser.tsx @@ -22,7 +22,7 @@ export const SourceChooser: React.FC<{ fileId: string | undefined, setFileId: (fileId: string) => void, }> = ({ sources, fileId, setFileId }) => { - return { setFileId(event.target.selectedOptions[0].value); }}>{renderSourceOptions(sources)}; }; @@ -33,17 +33,21 @@ function renderSourceOptions(sources: Source[]): React.ReactNode { ); - const hasGroup = sources.some(s => s.group); - if (hasGroup) { - const groups = new Set(sources.map(s => s.group)); - return [...groups].filter(Boolean).map(group => ( - - {sources.filter(s => s.group === group).map(source => renderOption(source))} - - )); + const sourcesByGroups = new Map(); + for (const source of sources) { + let list = sourcesByGroups.get(source.group || 'Debugger'); + if (!list) { + list = []; + sourcesByGroups.set(source.group || 'Debugger', list); + } + list.push(source); } - return sources.map(source => renderOption(source)); + return [...sourcesByGroups.entries()].map(([group, sources]) => ( + + {sources.filter(s => (s.group || 'Debugger') === group).map(source => renderOption(source))} + + )); } export function emptySource(): Source { diff --git a/packages/web/src/components/toolbarButton.tsx b/packages/web/src/components/toolbarButton.tsx index 00b9babd59940..184642b395e7f 100644 --- a/packages/web/src/components/toolbarButton.tsx +++ b/packages/web/src/components/toolbarButton.tsx @@ -28,6 +28,7 @@ export interface ToolbarButtonProps { style?: React.CSSProperties, testId?: string, className?: string, + ariaLabel?: string, } export const ToolbarButton: React.FC> = ({ @@ -40,6 +41,7 @@ export const ToolbarButton: React.FC style, testId, className, + ariaLabel, }) => { return