Skip to content

Commit 2d48726

Browse files
committed
Uniques test case re-runner
1 parent 1eb1a65 commit 2d48726

File tree

4 files changed

+282
-104
lines changed

4 files changed

+282
-104
lines changed

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

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ interface TestEntry {
3232
fullTitle?: string
3333
}
3434

35+
interface RunCapabilities {
36+
canRunSuites: boolean
37+
canRunTests: boolean
38+
}
39+
40+
type RunnerOptions = {
41+
framework?: string
42+
configFile?: string
43+
configFilePath?: string
44+
runCapabilities?: Partial<RunCapabilities>
45+
}
46+
47+
const DEFAULT_CAPABILITIES: RunCapabilities = {
48+
canRunSuites: true,
49+
canRunTests: true
50+
}
51+
52+
const FRAMEWORK_CAPABILITIES: Record<string, RunCapabilities> = {
53+
cucumber: { canRunSuites: true, canRunTests: false }
54+
}
55+
3556
@customElement(EXPLORER)
3657
export class DevtoolsSidebarExplorer extends CollapseableEntry {
3758
#testFilter: DevtoolsSidebarFilter | undefined
@@ -92,9 +113,13 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
92113
}
93114

94115
async #handleTestRun(event: Event) {
95-
console.log('handleTestRun', event)
96116
event.stopPropagation()
97117
const detail = (event as CustomEvent<TestRunDetail>).detail
118+
if (this.#isRunDisabledDetail(detail)) {
119+
this.#surfaceCapabilityWarning(detail)
120+
return
121+
}
122+
98123
await this.#postToBackend('/api/tests/run', {
99124
...detail,
100125
runAll: detail.uid === '*',
@@ -157,7 +182,14 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
157182
}
158183

159184
#runAllSuites() {
160-
console.log('runAllSuites')
185+
if (!this.#getRunCapabilities().canRunSuites) {
186+
this.#surfaceCapabilityWarning({
187+
entryType: 'suite',
188+
uid: '*'
189+
} as TestRunDetail)
190+
return
191+
}
192+
161193
void this.#postToBackend('/api/tests/run', {
162194
uid: '*',
163195
entryType: 'suite',
@@ -174,18 +206,70 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
174206
}
175207

176208
#getFramework(): string | undefined {
177-
const options = this.metadata?.options as { framework?: string } | undefined
178-
return options?.framework
209+
return this.#getRunnerOptions()?.framework
210+
}
211+
212+
#getRunnerOptions(): RunnerOptions | undefined {
213+
return this.metadata?.options as RunnerOptions | undefined
214+
}
215+
216+
#getRunCapabilities(): RunCapabilities {
217+
const options = this.#getRunnerOptions()
218+
if (options?.runCapabilities) {
219+
return {
220+
...DEFAULT_CAPABILITIES,
221+
...options.runCapabilities
222+
}
223+
}
224+
const framework = options?.framework?.toLowerCase() ?? ''
225+
return FRAMEWORK_CAPABILITIES[framework] || DEFAULT_CAPABILITIES
226+
}
227+
228+
#isRunDisabled(entry: TestEntry) {
229+
const caps = this.#getRunCapabilities()
230+
if (entry.type === 'test' && !caps.canRunTests) {
231+
return true
232+
}
233+
if (entry.type === 'suite' && !caps.canRunSuites) {
234+
return true
235+
}
236+
return false
237+
}
238+
239+
#isRunDisabledDetail(detail: TestRunDetail) {
240+
const caps = this.#getRunCapabilities()
241+
if (detail.entryType === 'test' && !caps.canRunTests) {
242+
return true
243+
}
244+
if (detail.entryType === 'suite' && !caps.canRunSuites) {
245+
return true
246+
}
247+
return false
248+
}
249+
250+
#surfaceCapabilityWarning(detail: TestRunDetail) {
251+
const message =
252+
detail.entryType === 'test'
253+
? 'Single-test execution is not supported by this framework.'
254+
: 'Suite execution is disabled by this framework.'
255+
window.dispatchEvent(
256+
new CustomEvent('app-logs', {
257+
detail: message
258+
})
259+
)
260+
}
261+
262+
#getRunDisabledReason(entry: TestEntry) {
263+
if (!this.#isRunDisabled(entry)) {
264+
return undefined
265+
}
266+
return entry.type === 'test'
267+
? 'Single-test execution is not supported by this framework.'
268+
: 'Suite execution is not supported by this framework.'
179269
}
180270

181271
#getConfigPath(): string | undefined {
182-
const options = this.metadata?.options as
183-
| {
184-
configFile?: string
185-
configFilePath?: string
186-
}
187-
| undefined
188-
console.log('getConfigPath', options?.configFilePath, options?.configFile)
272+
const options = this.#getRunnerOptions()
189273
return options?.configFilePath || options?.configFile
190274
}
191275

@@ -199,6 +283,8 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
199283
spec-file="${entry.specFile || ''}"
200284
full-title="${entry.fullTitle || ''}"
201285
label-text="${entry.label}"
286+
.runDisabled=${this.#isRunDisabled(entry)}
287+
.runDisabledReason=${this.#getRunDisabledReason(entry)}
202288
>
203289
<label slot="label">${entry.label}</label>
204290
${entry.children && entry.children.length
@@ -281,12 +367,10 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
281367
return
282368
}
283369

284-
// ✅ Only root suites (no parent = true top-level suite)
285370
const rootSuites = this.suites
286371
.flatMap((s) => Object.values(s))
287372
.filter((suite) => !suite.parent)
288373

289-
// Deduplicate by uid (in case some frameworks still push duplicates)
290374
const uniqueSuites = Array.from(
291375
new Map(rootSuites.map((suite) => [suite.uid, suite])).values()
292376
)

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

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ export class ExplorerTestEntry extends CollapseableEntry {
8080
@property({ type: String, attribute: 'label-text' })
8181
labelText?: string
8282

83+
@property({ type: Boolean, attribute: 'run-disabled' })
84+
runDisabled = false
85+
86+
@property({ type: String, attribute: 'run-disabled-reason' })
87+
runDisabledReason?: string
88+
8389
static styles = [
8490
...Element.styles,
8591
css`
@@ -96,7 +102,7 @@ export class ExplorerTestEntry extends CollapseableEntry {
96102
this.dispatchEvent(
97103
new CustomEvent('entry-collapse-change', {
98104
detail: {
99-
isCollapsed: isCollapsed,
105+
isCollapsed,
100106
entry: this
101107
},
102108
bubbles: true
@@ -120,9 +126,8 @@ export class ExplorerTestEntry extends CollapseableEntry {
120126
}
121127

122128
#runEntry(event: Event) {
123-
console.log('runEntry', this.uid)
124129
event.stopPropagation()
125-
if (!this.uid) {
130+
if (!this.uid || this.runDisabled) {
126131
return
127132
}
128133
const detail: TestRunDetail = {
@@ -144,7 +149,7 @@ export class ExplorerTestEntry extends CollapseableEntry {
144149

145150
#stopEntry(event: Event) {
146151
event.stopPropagation()
147-
if (!this.uid) {
152+
if (!this.uid || this.runDisabled) {
148153
return
149154
}
150155
const detail: TestRunDetail = {
@@ -207,6 +212,10 @@ export class ExplorerTestEntry extends CollapseableEntry {
207212
const hasNoChildren =
208213
this.querySelectorAll('[slot="children"]').length === 0
209214
const isCollapsed = this.isCollapsed === 'true'
215+
const runTooltip = this.runDisabled
216+
? this.runDisabledReason ||
217+
'Single-step execution is controlled by its scenario.'
218+
: 'Run this entry'
210219

211220
return html`
212221
<section class="block mt-2 text-sm flex w-full group/sidebar">
@@ -234,24 +243,33 @@ export class ExplorerTestEntry extends CollapseableEntry {
234243
${!this.isRunning
235244
? html`
236245
<button
237-
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group/button"
246+
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group/button ${this.runDisabled
247+
? 'opacity-60 cursor-not-allowed hover:bg-transparent'
248+
: ''}"
249+
title="${runTooltip}"
250+
?disabled=${this.runDisabled}
238251
@click="${(event: Event) => this.#runEntry(event)}"
239252
>
240253
<icon-mdi-play
241-
class="group-hover/button:text-chartsGreen"
254+
class="${this.runDisabled
255+
? ''
256+
: 'group-hover/button:text-chartsGreen'}"
242257
></icon-mdi-play>
243258
</button>
244259
`
245-
: html`
246-
<button
247-
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group/button"
248-
@click="${(event: Event) => this.#stopEntry(event)}"
249-
>
250-
<icon-mdi-stop
251-
class="group-hover/button:text-chartsRed"
252-
></icon-mdi-stop>
253-
</button>
254-
`}
260+
: !this.runDisabled
261+
? html`
262+
<button
263+
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group/button"
264+
title="Stop run"
265+
@click="${(event: Event) => this.#stopEntry(event)}"
266+
>
267+
<icon-mdi-stop
268+
class="group-hover/button:text-chartsRed"
269+
></icon-mdi-stop>
270+
</button>
271+
`
272+
: nothing}
255273
<button
256274
class="p-1 rounded hover:bg-toolbarHoverBackground my-1 group"
257275
@click="${() => this.#viewSource()}"

packages/backend/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export async function start(opts: DevtoolsBackendOptions = {}) {
3535
server.post(
3636
'/api/tests/run',
3737
async (request: FastifyRequest<{ Body: RunnerRequestBody }>, reply) => {
38-
console.log('request', request.body)
3938
const body = request.body
4039
if (!body?.uid || !body.entryType) {
4140
return reply.code(400).send({ error: 'Invalid run payload' })

0 commit comments

Comments
 (0)