Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const config: Options.Testrunner = {
capabilities: [
{
browserName: 'chrome',
browserVersion: '144.0.7559.60', // specify chromium browser version for testing
browserVersion: '145.0.7632.160', // specify chromium browser version for testing
'goog:chromeOptions': {
args: [
'--headless',
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"scripts": {
"build": "pnpm --parallel build",
"demo": "wdio run ./example/wdio.conf.ts",
"demo:nightwatch": "pnpm --filter @wdio/nightwatch-devtools example",
"dev": "pnpm --parallel dev",
"preview": "pnpm --parallel preview",
"test": "vitest run",
Expand All @@ -17,7 +18,10 @@
"pnpm": {
"overrides": {
"vite": "^7.3.0"
}
},
"ignoredBuiltDependencies": [
"chromedriver"
]
},
"devDependencies": {
"@types/node": "^25.0.3",
Expand Down
8 changes: 8 additions & 0 deletions packages/app/src/components/sidebar/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import { TestState } from './types.js'

export const STATE_MAP: Record<string, TestState> = {
running: TestState.RUNNING,
failed: TestState.FAILED,
passed: TestState.PASSED,
skipped: TestState.SKIPPED
}
import type { RunCapabilities } from './types.js'

export const DEFAULT_CAPABILITIES: RunCapabilities = {
Expand Down
92 changes: 77 additions & 15 deletions packages/app/src/components/sidebar/explorer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Element } from '@core/element'
import { html, css, nothing, type TemplateResult } from 'lit'
import { customElement } from 'lit/decorators.js'
import { customElement, property } from 'lit/decorators.js'
import { consume } from '@lit/context'
import type { TestStats, SuiteStats } from '@wdio/reporter'
import type { Metadata } from '@wdio/devtools-service/types'
Expand All @@ -17,7 +17,11 @@ import type {
TestRunDetail
} from './types.js'
import { TestState } from './types.js'
import { DEFAULT_CAPABILITIES, FRAMEWORK_CAPABILITIES } from './constants.js'
import {
DEFAULT_CAPABILITIES,
FRAMEWORK_CAPABILITIES,
STATE_MAP
} from './constants.js'

import '~icons/mdi/play.js'
import '~icons/mdi/stop.js'
Expand Down Expand Up @@ -63,6 +67,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
]

@consume({ context: suiteContext, subscribe: true })
@property({ type: Array })
suites: Record<string, SuiteStats>[] | undefined = undefined

@consume({ context: metadataContext, subscribe: true })
Expand All @@ -71,6 +76,10 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
@consume({ context: isTestRunningContext, subscribe: true })
isTestRunning = false

updated(changedProperties: Map<string | number | symbol, unknown>) {
super.updated(changedProperties)
}

connectedCallback(): void {
super.connectedCallback()
window.addEventListener('app-test-filter', this.#filterListener)
Expand Down Expand Up @@ -285,6 +294,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
feature-file="${entry.featureFile || ''}"
feature-line="${entry.featureLine ?? ''}"
suite-type="${entry.suiteType || ''}"
?has-children="${entry.children && entry.children.length > 0}"
.runDisabled=${this.#isRunDisabled(entry)}
.runDisabledReason=${this.#getRunDisabledReason(entry)}
>
Expand Down Expand Up @@ -326,18 +336,70 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
)
}

#isRunning(entry: TestStats | SuiteStats): boolean {
if ('tests' in entry) {
// Check if any immediate test is running
if (entry.tests.some((t) => !t.end)) {
return true
}
// Check if any nested suite is running
if (entry.suites.some((s) => this.#isRunning(s))) {
return true
}
return false
}
// For individual tests, check if end is not set
return !entry.end
}

#hasFailed(entry: TestStats | SuiteStats): boolean {
if ('tests' in entry) {
// Check if any immediate test failed
if (entry.tests.find((t) => t.state === 'failed')) {
return true
}
// Check if any nested suite has failures
if (entry.suites.some((s) => this.#hasFailed(s))) {
return true
}
return false
}
// For individual tests
return entry.state === 'failed'
}

#computeEntryState(entry: TestStats | SuiteStats): TestState {
const state = (entry as any).state

// Check explicit state first
const mappedState = STATE_MAP[state]
if (mappedState) {
return mappedState
}

// For suites, compute state from children
if ('tests' in entry) {
if (this.#isRunning(entry)) {
return TestState.RUNNING
}
if (this.#hasFailed(entry)) {
return TestState.FAILED
}
return TestState.PASSED
}

// For individual tests, check if still running
return !entry.end ? TestState.RUNNING : TestState.PASSED
}

#getTestEntry(entry: TestStats | SuiteStats): TestEntry {
if ('tests' in entry) {
const entries = [...entry.tests, ...entry.suites]
return {
uid: entry.uid,
label: entry.title,
type: 'suite',
state: entry.tests.some((t) => !t.end)
? TestState.RUNNING
: entry.tests.find((t) => t.state === 'failed')
? TestState.FAILED
: TestState.PASSED,
state: this.#computeEntryState(entry),
callSource: (entry as any).callSource,
specFile: (entry as any).file,
fullTitle: entry.title,
Expand All @@ -353,11 +415,7 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
uid: entry.uid,
label: entry.title,
type: 'test',
state: !entry.end
? TestState.RUNNING
: entry.state === 'failed'
? TestState.FAILED
: TestState.PASSED,
state: this.#computeEntryState(entry),
callSource: (entry as any).callSource,
specFile: (entry as any).file,
fullTitle: (entry as any).fullTitle || entry.title,
Expand Down Expand Up @@ -421,9 +479,13 @@ export class DevtoolsSidebarExplorer extends CollapseableEntry {
(suite) => suite.uid,
(suite) => this.#renderEntry(suite)
)
: html`<p class="text-disabledForeground text-sm px-4 py-2">
No tests found
</p>`}
: html`<div class="text-sm px-4 py-2">
<p class="text-disabledForeground">No tests to display</p>
<p class="text-xs text-disabledForeground mt-2">
Debug: suites=${this.suites?.length || 0},
rootSuites=${uniqueSuites.length}, filtered=${suites.length}
</p>
</div>`}
</wdio-test-suite>
`
}
Expand Down
6 changes: 4 additions & 2 deletions packages/app/src/components/sidebar/test-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export class ExplorerTestEntry extends CollapseableEntry {
@property({ type: String, attribute: 'suite-type' })
suiteType?: string

@property({ type: Boolean, attribute: 'has-children' })
hasChildren = false

static styles = [
...Element.styles,
css`
Expand Down Expand Up @@ -206,8 +209,7 @@ export class ExplorerTestEntry extends CollapseableEntry {
}

render() {
const hasNoChildren =
this.querySelectorAll('[slot="children"]').length === 0
const hasNoChildren = !this.hasChildren
const isCollapsed = this.isCollapsed === 'true'
const runTooltip = this.runDisabled
? this.runDisabledReason ||
Expand Down
16 changes: 9 additions & 7 deletions packages/app/src/components/workbench/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,15 @@ export class DevtoolsSource extends Element {
{} as Record<string, unknown>
)}"
></wdio-devtools-list>
<wdio-devtools-list
label="Result"
class="text-xs"
.list="${typeof this.command.result === 'object'
? this.command.result
: [this.command.result]}"
></wdio-devtools-list>
${this.command.result !== null && this.command.result !== undefined
? html`<wdio-devtools-list
label="Result"
class="text-xs"
.list="${typeof this.command.result === 'object'
? this.command.result
: [this.command.result]}"
></wdio-devtools-list>`
: ''}
`
}
}
Expand Down
50 changes: 40 additions & 10 deletions packages/app/src/components/workbench/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,50 @@ export class DevtoolsMetadata extends Element {
return html`<wdio-devtools-placeholder></wdio-devtools-placeholder>`
}

const { url } = this.metadata
const m = this.metadata as any
const sessionInfo: Record<string, unknown> = {}
if (m.sessionId) {
sessionInfo['Session ID'] = m.sessionId
}
if (m.testEnv) {
sessionInfo.Environment = m.testEnv
}
if (m.host) {
sessionInfo['WebDriver Host'] = m.host
}
if (m.modulePath) {
sessionInfo['Test File'] = m.modulePath
}
if (m.url) {
sessionInfo.URL = m.url
}

const caps = m.capabilities || {}
const desiredCaps = m.desiredCapabilities || {}

return html`
<wdio-devtools-list
label="Metadata"
.list="${{ url }}"
></wdio-devtools-list>
${Object.keys(sessionInfo).length
? html`<wdio-devtools-list
label="Session"
.list="${sessionInfo}"
></wdio-devtools-list>`
: ''}
<wdio-devtools-list
label="Capabilities"
.list="${this.metadata.capabilities}"
></wdio-devtools-list>
<wdio-devtools-list
label="Options"
.list="${this.metadata.options}"
.list="${caps}"
></wdio-devtools-list>
${Object.keys(desiredCaps).length
? html`<wdio-devtools-list
label="Desired Capabilities"
.list="${desiredCaps}"
></wdio-devtools-list>`
: ''}
${m.options && Object.keys(m.options).length
? html`<wdio-devtools-list
label="Options"
.list="${m.options}"
></wdio-devtools-list>`
: ''}
`
}
}
Expand Down
Loading
Loading