Skip to content

Commit 31199bd

Browse files
committed
Code refactor
1 parent 5116677 commit 31199bd

31 files changed

Lines changed: 310 additions & 299 deletions

File tree

eslint.config.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ module.exports = [
7777
rules: {
7878
'@typescript-eslint/no-unused-vars': [
7979
'error',
80-
{ argsIgnorePattern: '^_' }
80+
{ argsIgnorePattern: '^_', ignoreRestSiblings: true }
8181
],
8282
'@typescript-eslint/consistent-type-imports': 'error',
8383
'no-unused-vars': 'off',

packages/app/src/app.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import { TraceType, type TraceLog } from '@wdio/devtools-service/types'
66
import { Element } from '@core/element'
77
import { DataManagerController } from './controller/DataManager.js'
88
import { DragController, Direction } from './utils/DragController.js'
9+
import { SIDEBAR_MIN_WIDTH } from './controller/constants.js'
910

1011
import './components/header.js'
1112
import './components/sidebar.js'
1213
import './components/workbench.js'
1314
import './components/onboarding/start.js'
1415

15-
const SIDEBAR_MIN_WIDTH = 250
16-
1716
@customElement('wdio-devtools')
1817
export class WebdriverIODevtoolsApplication extends Element {
1918
dataManager = new DataManagerController(this)

packages/app/src/components/header.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import '~icons/mdi/moon-waning-crescent.js'
88
import '~icons/mdi/file-upload-outline.js'
99

1010
import './inputs/traceLoader.js'
11+
import { DARK_MODE_KEY } from '../controller/constants.js'
1112

12-
const DARK_MODE_KEY = 'darkMode'
1313
const darkModeInitValue = localStorage.getItem(DARK_MODE_KEY)
1414

1515
@customElement('wdio-devtools-header')

packages/app/src/components/onboarding/start.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Element } from '@core/element'
22
import { html, css } from 'lit'
3-
import { customElement, property } from 'lit/decorators.js'
3+
import { customElement } from 'lit/decorators.js'
44

55
import '../inputs/traceLoader.js'
66

@@ -23,9 +23,6 @@ export class DevtoolsStart extends Element {
2323
`
2424
]
2525

26-
@property()
27-
onLoad = (content: any) => content
28-
2926
render() {
3027
return html`
3128
<div class="h-full flex-1 flex justify-center items-center bg-sideBarBackground">

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

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import { Element } from '@core/element'
22
import { html, css, nothing, type TemplateResult } from 'lit'
33
import { customElement, property } from 'lit/decorators.js'
44
import { consume } from '@lit/context'
5-
import type { TestStats, SuiteStats } from '@wdio/reporter'
65
import type { Metadata } from '@wdio/devtools-service/types'
76
import { repeat } from 'lit/directives/repeat.js'
87
import { suiteContext, metadataContext } from '../../controller/context.js'
8+
import type {
9+
SuiteStatsFragment,
10+
TestStatsFragment
11+
} from '../../controller/types.js'
912
import type {
1013
TestEntry,
1114
RunCapabilities,
@@ -64,7 +67,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
6467

6568
@consume({ context: suiteContext, subscribe: true })
6669
@property({ type: Array })
67-
suites: Record<string, SuiteStats>[] | undefined = undefined
70+
suites: Record<string, SuiteStatsFragment>[] | undefined = undefined
6871

6972
@consume({ context: metadataContext, subscribe: true })
7073
metadata: Metadata | undefined = undefined
@@ -278,7 +281,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
278281
return html`
279282
<wdio-test-entry
280283
uid="${entry.uid}"
281-
state="${entry.state as any}"
284+
state="${entry.state ?? ''}"
282285
call-source="${entry.callSource || ''}"
283286
entry-type="${entry.type}"
284287
spec-file="${entry.specFile || ''}"
@@ -329,21 +332,23 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
329332
)
330333
}
331334

332-
#isRunning(entry: TestStats | SuiteStats): boolean {
335+
#isRunning(entry: TestStatsFragment | SuiteStatsFragment): boolean {
333336
if ('tests' in entry) {
334337
// Fastest path: any explicitly running descendant
335338
if (
336-
entry.tests.some((t) => (t as any).state === 'running') ||
337-
entry.suites.some((s) => this.#isRunning(s))
339+
(entry.tests ?? []).some((t) => t.state === 'running') ||
340+
(entry.suites ?? []).some((s) => this.#isRunning(s))
338341
) {
339342
return true
340343
}
341344

342-
const hasPendingTests = entry.tests.some(
343-
(t) => (t as any).state === 'pending'
345+
const hasPendingTests = (entry.tests ?? []).some(
346+
(t) => t.state === 'pending'
347+
)
348+
const hasPendingSuites = (entry.suites ?? []).some((s) =>
349+
this.#hasPending(s)
344350
)
345-
const hasPendingSuites = entry.suites.some((s) => this.#hasPending(s))
346-
const suiteState = (entry as any).state
351+
const suiteState = entry.state
347352

348353
// If the suite was explicitly marked 'running' (e.g. by markTestAsRunning)
349354
// and still has pending children, it's actively executing.
@@ -354,12 +359,10 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
354359
// Mixed terminal + pending children = run is in progress regardless of
355360
// explicit suite state (handles Nightwatch Cucumber where the feature
356361
// suite state may be undefined in the JSON payload).
357-
const allDescendants = [...entry.tests, ...entry.suites]
362+
const allDescendants = [...(entry.tests ?? []), ...(entry.suites ?? [])]
358363
const hasSomeTerminal = allDescendants.some(
359364
(t) =>
360-
(t as any).state === 'passed' ||
361-
(t as any).state === 'failed' ||
362-
(t as any).state === 'skipped'
365+
t.state === 'passed' || t.state === 'failed' || t.state === 'skipped'
363366
)
364367
if ((hasPendingTests || hasPendingSuites) && hasSomeTerminal) {
365368
return true
@@ -368,33 +371,33 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
368371
return false
369372
}
370373
// For individual tests rely on explicit state only.
371-
return (entry as any).state === 'running'
374+
return entry.state === 'running'
372375
}
373376

374-
#hasPending(entry: TestStats | SuiteStats): boolean {
377+
#hasPending(entry: TestStatsFragment | SuiteStatsFragment): boolean {
375378
if ('tests' in entry) {
376-
if ((entry as any).state === 'pending') {
379+
if (entry.state === 'pending') {
377380
return true
378381
}
379-
if (entry.tests.some((t) => (t as any).state === 'pending')) {
382+
if ((entry.tests ?? []).some((t) => t.state === 'pending')) {
380383
return true
381384
}
382-
if (entry.suites.some((s) => this.#hasPending(s))) {
385+
if ((entry.suites ?? []).some((s) => this.#hasPending(s))) {
383386
return true
384387
}
385388
return false
386389
}
387-
return (entry as any).state === 'pending'
390+
return entry.state === 'pending'
388391
}
389392

390-
#hasFailed(entry: TestStats | SuiteStats): boolean {
393+
#hasFailed(entry: TestStatsFragment | SuiteStatsFragment): boolean {
391394
if ('tests' in entry) {
392395
// Check if any immediate test failed
393-
if (entry.tests.find((t) => t.state === 'failed')) {
396+
if ((entry.tests ?? []).find((t) => t.state === 'failed')) {
394397
return true
395398
}
396399
// Check if any nested suite has failures
397-
if (entry.suites.some((s) => this.#hasFailed(s))) {
400+
if ((entry.suites ?? []).some((s) => this.#hasFailed(s))) {
398401
return true
399402
}
400403
return false
@@ -403,30 +406,37 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
403406
return entry.state === 'failed'
404407
}
405408

406-
#computeEntryState(entry: TestStats | SuiteStats): TestState | 'pending' {
409+
#computeEntryState(
410+
entry: TestStatsFragment | SuiteStatsFragment
411+
): TestState | 'pending' {
407412
// For suites, check running state from children FIRST — this ensures that
408413
// a rerun (which clears end times) shows the spinner immediately, even if
409414
// the suite still has a cached 'passed'/'failed' state from the previous run.
410415
if ('tests' in entry && this.#isRunning(entry)) {
411416
return TestState.RUNNING
412417
}
413418

414-
const state = (entry as any).state
419+
const state = entry.state
420+
421+
// A suite with an explicit 'pending' state is always in-progress from the
422+
// UI's perspective — the backend uses 'pending' to signal a new run is
423+
// starting. Skip the children check: stale terminal children from the
424+
// previous run must not cause the suite to appear as passed.
425+
if ('tests' in entry && state === 'pending') {
426+
return TestState.RUNNING
427+
}
415428

416429
// For suites with no explicit terminal state, derive from children.
417-
// A suite with state=undefined or state=pending that has no terminal
430+
// A suite with state=undefined or state=running that has no terminal
418431
// children yet is still in-progress — don't show PASSED prematurely.
419-
if (
420-
'tests' in entry &&
421-
(state === null || state === 'pending' || state === 'running')
422-
) {
423-
const allDescendants = [...entry.tests, ...entry.suites]
432+
if ('tests' in entry && (state === null || state === 'running')) {
433+
const allDescendants = [...(entry.tests ?? []), ...(entry.suites ?? [])]
424434
if (allDescendants.length > 0) {
425435
const allTerminal = allDescendants.every(
426436
(t) =>
427-
(t as any).state === 'passed' ||
428-
(t as any).state === 'failed' ||
429-
(t as any).state === 'skipped'
437+
t.state === 'passed' ||
438+
t.state === 'failed' ||
439+
t.state === 'skipped'
430440
)
431441
if (!allTerminal) {
432442
// Still has non-terminal children — treat as running/loading
@@ -436,7 +446,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
436446
}
437447

438448
// Check explicit terminal state
439-
const mappedState = STATE_MAP[state]
449+
const mappedState = state ? STATE_MAP[state] : undefined
440450
if (mappedState) {
441451
return mappedState
442452
}
@@ -458,27 +468,25 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
458468
return entry.end ? TestState.PASSED : 'pending'
459469
}
460470

461-
#getTestEntry(entry: TestStats | SuiteStats): TestEntry {
471+
#getTestEntry(entry: TestStatsFragment | SuiteStatsFragment): TestEntry {
462472
if ('tests' in entry) {
463-
const entries = [...entry.tests, ...entry.suites]
473+
const entries = [...(entry.tests ?? []), ...(entry.suites ?? [])]
464474
// A suite whose children are themselves suites is a feature/file-level
465475
// container (Cucumber feature or test file). Tag it as 'feature' so the
466476
// backend runner can distinguish it from a scenario/spec-level suite and
467477
// avoid applying a --name filter that would match no scenarios.
468478
const hasChildSuites = entry.suites && entry.suites.length > 0
469-
const derivedType = hasChildSuites
470-
? 'feature'
471-
: (entry as any).type || 'suite'
479+
const derivedType = hasChildSuites ? 'feature' : entry.type || 'suite'
472480
return {
473481
uid: entry.uid,
474-
label: entry.title,
482+
label: entry.title ?? '',
475483
type: 'suite',
476484
state: this.#computeEntryState(entry),
477-
callSource: (entry as any).callSource,
478-
specFile: (entry as any).file,
479-
fullTitle: entry.title,
480-
featureFile: (entry as any).featureFile,
481-
featureLine: (entry as any).featureLine,
485+
callSource: entry.callSource,
486+
specFile: entry.file,
487+
fullTitle: entry.title ?? '',
488+
featureFile: entry.featureFile,
489+
featureLine: entry.featureLine,
482490
suiteType: derivedType,
483491
children: Object.values(entries)
484492
.map(this.#getTestEntry.bind(this))
@@ -487,14 +495,14 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
487495
}
488496
return {
489497
uid: entry.uid,
490-
label: entry.title,
498+
label: entry.title ?? '',
491499
type: 'test',
492500
state: this.#computeEntryState(entry),
493-
callSource: (entry as any).callSource,
494-
specFile: (entry as any).file,
495-
fullTitle: (entry as any).fullTitle || entry.title,
496-
featureFile: (entry as any).featureFile,
497-
featureLine: (entry as any).featureLine,
501+
callSource: entry.callSource,
502+
specFile: entry.file,
503+
fullTitle: entry.fullTitle || entry.title,
504+
featureFile: entry.featureFile,
505+
featureLine: entry.featureLine,
498506
children: []
499507
}
500508
}

packages/app/src/components/workbench.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import './workbench/console.js'
2222
import './workbench/metadata.js'
2323
import './workbench/network.js'
2424
import './browser/snapshot.js'
25-
26-
const MIN_WORKBENCH_HEIGHT = Math.min(300, window.innerHeight * 0.3)
27-
const MIN_METATAB_WIDTH = 260
28-
const RERENDER_TIMEOUT = 10
25+
import {
26+
MIN_WORKBENCH_HEIGHT,
27+
MIN_METATAB_WIDTH,
28+
RERENDER_TIMEOUT
29+
} from '../controller/constants.js'
2930

3031
const COMPONENT = 'wdio-devtools-workbench'
3132
@customElement(COMPONENT)

packages/app/src/components/workbench/actionItems/command.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { customElement, property } from 'lit/decorators.js'
44
import type { CommandLog } from '@wdio/devtools-service/types'
55

66
import { ActionItem, ICON_CLASS } from './item.js'
7+
import '~icons/mdi/arrow-right.js'
78

89
const SOURCE_COMPONENT = 'wdio-devtools-command-item'
910

packages/app/src/components/workbench/actionItems/mutation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { customElement, property } from 'lit/decorators.js'
33

44
import { ActionItem, ICON_CLASS } from './item.js'
55
import type { SimplifiedVNode } from '../../../../../script/types'
6+
import '~icons/mdi/document.js'
7+
import '~icons/mdi/pencil.js'
8+
import '~icons/mdi/family-tree.js'
69

710
const SOURCE_COMPONENT = 'wdio-devtools-mutation-item'
811

packages/app/src/components/workbench/actions.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ import { consume } from '@lit/context'
66
import type { CommandLog } from '@wdio/devtools-service/types'
77
import { mutationContext, commandContext } from '../../controller/context.js'
88

9-
import '~icons/mdi/pencil.js'
10-
import '~icons/mdi/family-tree.js'
11-
import '~icons/mdi/alert.js'
12-
import '~icons/mdi/document.js'
13-
import '~icons/mdi/arrow-right.js'
14-
159
import '../placeholder.js'
1610
import './actionItems/command.js'
1711
import './actionItems/mutation.js'

packages/app/src/components/workbench/console.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ import { customElement } from 'lit/decorators.js'
44
import { consume } from '@lit/context'
55

66
import { consoleLogContext } from '../../controller/context.js'
7-
8-
const LOG_ICONS: Record<ConsoleLogs['type'], string> = {
9-
log: '📄',
10-
info: 'ℹ️',
11-
warn: '⚠️',
12-
error: '❌'
13-
}
7+
import { LOG_ICONS } from '../../controller/constants.js'
148

159
const SOURCE_COMPONENT = 'wdio-devtools-console-logs'
1610
@customElement(SOURCE_COMPONENT)

0 commit comments

Comments
 (0)