diff --git a/README.md b/README.md index a4b97c3..15d71b9 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ export default defineConfig({ }) ``` -After running a browser test through the extension, right-click the test in the Testing view or its editor gutter icon and select **Open Trace View**. The extension opens the generated HTML report in a reusable editor webview beside your code. Opening another test updates the same tab. Changes to the report reload the current test at its first trace step if its trace is still available. Otherwise, the view switches to the latest run's only recorded test, or asks you to select a test if there is no unambiguous target. +After running a browser test through the extension, right-click the test in the Testing view or its editor gutter icon and select **Open Trace View**. The extension opens the generated HTML report in a reusable editor webview beside your code. Opening another test updates the same tab. Changes to the report reload the current test at its selected trace step if its trace is still available. Vitest falls back to the first step if that step is no longer valid. Otherwise, the view switches to the latest run's only recorded test at its first step, or asks you to select a test if there is no unambiguous target. Retry and repeat selections are not preserved across refreshes. This webview prototype loads report resources through VS Code's local-resource API without a static server. Canvas replay and snapshots referencing external resources have not been verified. diff --git a/packages/extension/src/traceView.ts b/packages/extension/src/traceView.ts index afd270d..63612e9 100644 --- a/packages/extension/src/traceView.ts +++ b/packages/extension/src/traceView.ts @@ -14,6 +14,7 @@ export class TraceViewManager { private targets = new Map() private latestTargets = new Map() private currentTarget?: TraceViewTarget + private traceStep = 0 private panel?: vscode.WebviewPanel private reportPath?: string private watcher?: vscode.FileSystemWatcher @@ -78,6 +79,7 @@ export class TraceViewManager { const sameReport = this.reportPath === target.reportPath && !!this.currentTarget this.reportPath = target.reportPath this.currentTarget = target + this.traceStep = 0 const selection = createTraceViewUrl(target).split('#')[1] if (!this.panel) { const panel = vscode.window.createWebviewPanel( @@ -87,6 +89,16 @@ export class TraceViewManager { { enableScripts: true, retainContextWhenHidden: true }, ) this.panel = panel + panel.webview.onDidReceiveMessage((message) => { + if (message?.type === 'traceStep' + && panel === this.panel + && message.revision === this.revision + && message.testId === this.currentTarget?.testId + && Number.isSafeInteger(message.step) + && message.step >= 0) { + this.traceStep = message.step + } + }) panel.onDidDispose(() => { this.panel = undefined this.watcher?.dispose() @@ -121,8 +133,11 @@ export class TraceViewManager { const revision = ++this.revision if (selection === undefined) { const targets = this.latestTargets.get(reportPath) ?? [] + const previousTarget = this.currentTarget this.currentTarget = targets.find(target => target.testId === this.currentTarget?.testId) ?? (targets.length === 1 ? targets[0] : undefined) + if (this.currentTarget?.testId !== previousTarget?.testId) + this.traceStep = 0 if (!this.currentTarget) { panel.webview.html = ` @@ -130,7 +145,7 @@ export class TraceViewManager { Open Trace View on a test to select one.

` return } - selection = createTraceViewUrl(this.currentTarget).split('#')[1] + selection = createTraceViewUrl(this.currentTarget, this.traceStep).split('#')[1] } try { const reportUri = vscode.Uri.file(reportPath) @@ -166,6 +181,27 @@ export class TraceViewManager {