Skip to content

Commit cef289c

Browse files
committed
Compare tab UI changes
1 parent 5b8a5c8 commit cef289c

13 files changed

Lines changed: 1674 additions & 50 deletions

File tree

packages/app/src/components/sidebar/explorer.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
4040
#filterListener = this.#filterTests.bind(this)
4141
#runListener = this.#handleTestRun.bind(this)
4242
#stopListener = this.#handleTestStop.bind(this)
43+
#preserveRerunListener = this.#handlePreserveAndRerun.bind(this)
4344

4445
static styles = [
4546
...Element.styles,
@@ -82,6 +83,10 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
8283
window.addEventListener('app-test-filter', this.#filterListener)
8384
this.addEventListener('app-test-run', this.#runListener as EventListener)
8485
this.addEventListener('app-test-stop', this.#stopListener as EventListener)
86+
this.addEventListener(
87+
'app-test-preserve-rerun',
88+
this.#preserveRerunListener as EventListener
89+
)
8590
}
8691

8792
disconnectedCallback(): void {
@@ -92,6 +97,10 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
9297
'app-test-stop',
9398
this.#stopListener as EventListener
9499
)
100+
this.removeEventListener(
101+
'app-test-preserve-rerun',
102+
this.#preserveRerunListener as EventListener
103+
)
95104
}
96105

97106
#filterTests({ detail }: { detail: DevtoolsSidebarFilter }) {
@@ -133,6 +142,54 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
133142
await this.#postToBackend('/api/tests/stop', {})
134143
}
135144

145+
async #handlePreserveAndRerun(event: Event) {
146+
event.stopPropagation()
147+
const detail = (event as CustomEvent<TestRunDetail>).detail
148+
if (this.#isRunDisabledDetail(detail)) {
149+
this.#surfaceCapabilityWarning(detail)
150+
return
151+
}
152+
153+
// Preserve the current run's captured data BEFORE clearing it, so the
154+
// baseline can be compared against the upcoming rerun's live capture.
155+
try {
156+
const response = await fetch('/api/baseline/preserve', {
157+
method: 'POST',
158+
headers: { 'content-type': 'application/json' },
159+
body: JSON.stringify({
160+
testUid: detail.uid,
161+
scope: detail.entryType
162+
})
163+
})
164+
if (!response.ok) {
165+
const errorText = await response.text()
166+
window.dispatchEvent(
167+
new CustomEvent('app-logs', {
168+
detail: `Failed to preserve baseline: ${errorText}`
169+
})
170+
)
171+
// Don't trigger rerun if preserve failed — would lose comparison value.
172+
return
173+
}
174+
} catch (error) {
175+
window.dispatchEvent(
176+
new CustomEvent('app-logs', {
177+
detail: `Preserve error: ${(error as Error).message}`
178+
})
179+
)
180+
return
181+
}
182+
183+
// Hand off to the existing rerun flow now that the baseline is pinned.
184+
this.dispatchEvent(
185+
new CustomEvent<TestRunDetail>('app-test-run', {
186+
detail,
187+
bubbles: true,
188+
composed: true
189+
})
190+
)
191+
}
192+
136193
async #postToBackend(path: string, body: Record<string, unknown>) {
137194
try {
138195
const response = await fetch(path, {

packages/app/src/components/sidebar/test-suite.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import '~icons/mdi/window-close.js'
1717
import '~icons/mdi/debug-step-over.js'
1818
import '~icons/mdi/check.js'
1919
import '~icons/mdi/checkbox-blank-circle-outline.js'
20+
import '~icons/mdi/bug-play.js'
2021

2122
const TEST_SUITE = 'wdio-test-suite'
2223

@@ -169,6 +170,31 @@ export class ExplorerTestEntry extends CollapseableEntry {
169170
)
170171
}
171172

173+
#preserveAndRerun(event: Event) {
174+
event.stopPropagation()
175+
if (!this.uid || this.runDisabled) {
176+
return
177+
}
178+
const detail: TestRunDetail = {
179+
uid: this.uid,
180+
entryType: this.entryType,
181+
specFile: this.specFile,
182+
fullTitle: this.fullTitle,
183+
label: this.labelText,
184+
callSource: this.callSource,
185+
featureFile: this.featureFile,
186+
featureLine: this.featureLine,
187+
suiteType: this.suiteType
188+
}
189+
this.dispatchEvent(
190+
new CustomEvent<TestRunDetail>('app-test-preserve-rerun', {
191+
detail,
192+
bubbles: true,
193+
composed: true
194+
})
195+
)
196+
}
197+
172198
get hasPassed() {
173199
return this.state === TestState.PASSED
174200
}
@@ -256,6 +282,20 @@ export class ExplorerTestEntry extends CollapseableEntry {
256282
: 'group-hover/button:text-chartsGreen'}"
257283
></icon-mdi-play>
258284
</button>
285+
${this.hasFailed && !this.runDisabled
286+
? html`
287+
<button
288+
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group/button"
289+
title="Preserve current run and rerun for comparison"
290+
@click="${(event: Event) =>
291+
this.#preserveAndRerun(event)}"
292+
>
293+
<icon-mdi-bug-play
294+
class="group-hover/button:text-chartsBlue"
295+
></icon-mdi-bug-play>
296+
</button>
297+
`
298+
: nothing}
259299
`
260300
: !this.runDisabled
261301
? html`

packages/app/src/components/tabs.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,19 @@ export class DevtoolsTabs extends Element {
9595
}
9696
}
9797

98+
#refreshTabList() {
99+
this.#tabList =
100+
this.tabs
101+
.map((el) => el.getAttribute('label') as string)
102+
.filter(Boolean) || []
103+
this.requestUpdate()
104+
}
105+
98106
connectedCallback() {
99107
super.connectedCallback()
100108
setTimeout(() => {
101109
// wait till innerHTML is parsed
102-
this.#tabList =
103-
this.tabs
104-
.map((el) => el.getAttribute('label') as string)
105-
.filter(Boolean) || []
110+
this.#refreshTabList()
106111

107112
/**
108113
* get tab id either from local storage or a tab element that
@@ -120,7 +125,7 @@ export class DevtoolsTabs extends Element {
120125
*/
121126
if (!this.#activeTab) {
122127
this.#activeTab = this.#tabList[0]
123-
this.tabs[0].setAttribute('active', '')
128+
this.tabs[0]?.setAttribute('active', '')
124129
} else {
125130
this.activateTab(this.#activeTab)
126131
}
@@ -134,6 +139,16 @@ export class DevtoolsTabs extends Element {
134139
})
135140
}
136141

142+
firstUpdated() {
143+
// Refresh the tab list whenever the light-DOM slot contents change —
144+
// e.g. a conditionally-rendered tab like Compare mounting/unmounting
145+
// after the user clicks Preserve & Rerun.
146+
const slot = this.shadowRoot?.querySelector(
147+
'slot:not([name])'
148+
) as HTMLSlotElement | null
149+
slot?.addEventListener('slotchange', () => this.#refreshTabList())
150+
}
151+
137152
disconnectedCallback() {
138153
super.disconnectedCallback()
139154
if (this.#badgeCheckInterval) {

packages/app/src/components/workbench.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { consume } from '@lit/context'
66
import { DragController, Direction } from '../utils/DragController.js'
77
import {
88
consoleLogContext,
9-
networkRequestContext
9+
networkRequestContext,
10+
baselineContext
1011
} from '../controller/context.js'
12+
import type { PreservedAttempt } from '@wdio/devtools-service/types'
1113

1214
import '~icons/mdi/arrow-collapse-down.js'
1315
import '~icons/mdi/arrow-collapse-up.js'
@@ -21,6 +23,7 @@ import './workbench/logs.js'
2123
import './workbench/console.js'
2224
import './workbench/metadata.js'
2325
import './workbench/network.js'
26+
import './workbench/compare.js'
2427
import './browser/snapshot.js'
2528
import {
2629
MIN_WORKBENCH_HEIGHT,
@@ -43,6 +46,10 @@ export class DevtoolsWorkbench extends Element {
4346
@state()
4447
networkRequests: NetworkRequest[] | undefined = undefined
4548

49+
@consume({ context: baselineContext, subscribe: true })
50+
@state()
51+
baselines: Map<string, PreservedAttempt> | undefined = undefined
52+
4653
static styles = [
4754
...Element.styles,
4855
css`
@@ -215,6 +222,16 @@ export class DevtoolsWorkbench extends Element {
215222
>
216223
<wdio-devtools-network></wdio-devtools-network>
217224
</wdio-devtools-tab>
225+
${(this.baselines?.size || 0) > 0
226+
? html`
227+
<wdio-devtools-tab
228+
label="Compare"
229+
.badge="${this.baselines?.size || 0}"
230+
>
231+
<wdio-devtools-compare></wdio-devtools-compare>
232+
</wdio-devtools-tab>
233+
`
234+
: nothing}
218235
<nav class="ml-auto" slot="actions">
219236
<button
220237
@click="${() => this.#toggle('toolbar')}"

0 commit comments

Comments
 (0)