Skip to content

Commit 1c72547

Browse files
committed
Test console logging
1 parent ee89b4b commit 1c72547

8 files changed

Lines changed: 279 additions & 42 deletions

File tree

example/features/step-definitions/steps.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@ After(async () => {
1313
})
1414

1515
Given(/^I am on the (\w+) page$/, async (page: keyof typeof pages) => {
16+
console.log(`[TEST] Navigating to ${page} page`)
1617
await pages[page].open()
18+
console.log(`[TEST] Successfully opened ${page} page`)
1719
})
1820

1921
When(/^I login with (\w+) and (.+)$/, async (username, password) => {
22+
console.log(`[TEST] Attempting login with username: ${username}`)
2023
await LoginPage.login(username, password)
24+
console.info(`[TEST] Login submitted for user: ${username}`)
2125
})
2226

2327
Then(/^I should see a flash message saying (.*)$/, async (message) => {
28+
console.log(`[TEST] Verifying flash message: ${message}`)
2429
const el = await SecurePage.flashAlert
2530
await expect(el).toBeExisting()
2631
await expect(el).toHaveText(expect.stringContaining(message))
32+
console.log(`[TEST] Flash message verified successfully`)
2733
// await browser.pause(15000)
2834
})

packages/app/src/components/tabs.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const TABS_COMPONENT = 'wdio-devtools-tabs'
77
export class DevtoolsTabs extends Element {
88
#activeTab: string | undefined
99
#tabList: string[] = []
10+
#badgeCheckInterval?: number
1011

1112
@property({ type: String })
1213
cacheId?: string
@@ -27,15 +28,20 @@ export class DevtoolsTabs extends Element {
2728
]
2829

2930
#getTabButton(tabId: string) {
31+
const tabElement = this.tabs.find((el) => el.getAttribute('label') === tabId)
32+
const badge = (tabElement as any)?.badge
33+
const showBadge = badge && badge > 0
34+
3035
return html`
3136
<button
3237
@click="${() => this.activateTab(tabId)}"
3338
class="transition-colors px-4 py-2 hover:bg-toolbarHoverBackground ${this
3439
.#activeTab === tabId
3540
? 'bg-toolbarHoverBackground'
36-
: ''}"
41+
: ''} flex items-center gap-2"
3742
>
38-
${tabId}
43+
<span>${tabId}</span>
44+
${showBadge ? html`<span class="inline-flex items-center justify-center min-w-[20px] px-1.5 py-0.5 text-xs font-semibold rounded-full" style="background-color: #5a5a5a; color: #ffffff;">${badge}</span>` : nothing}
3945
</button>
4046
`
4147
}
@@ -112,9 +118,21 @@ export class DevtoolsTabs extends Element {
112118
}
113119

114120
this.requestUpdate()
121+
122+
// Check for badge changes periodically
123+
this.#badgeCheckInterval = window.setInterval(() => {
124+
this.requestUpdate()
125+
}, 250)
115126
})
116127
}
117128

129+
disconnectedCallback() {
130+
super.disconnectedCallback()
131+
if (this.#badgeCheckInterval) {
132+
clearInterval(this.#badgeCheckInterval)
133+
}
134+
}
135+
118136
render() {
119137
return html`
120138
${this.#tabList.length
@@ -133,6 +151,9 @@ export class DevtoolsTabs extends Element {
133151
const TAB_COMPONENT = 'wdio-devtools-tab'
134152
@customElement(TAB_COMPONENT)
135153
export class DevtoolsTab extends Element {
154+
@property({ type: Number })
155+
badge?: number
156+
136157
static styles = [
137158
...Element.styles,
138159
css`

packages/app/src/components/workbench.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Element } from '@core/element'
22
import { html, css, nothing } from 'lit'
3-
import { customElement, query } from 'lit/decorators.js'
3+
import { customElement, query, state } from 'lit/decorators.js'
4+
import { consume } from '@lit/context'
45

56
import { DragController, Direction } from '../utils/DragController.js'
7+
import { consoleLogContext } from '../controller/DataManager.js'
68

79
import '~icons/mdi/arrow-collapse-down.js'
810
import '~icons/mdi/arrow-collapse-up.js'
@@ -28,6 +30,10 @@ export class DevtoolsWorkbench extends Element {
2830
#workbenchSidebarCollapsed =
2931
localStorage.getItem('workbenchSidebar') === 'true'
3032

33+
@consume({ context: consoleLogContext, subscribe: true })
34+
@state()
35+
consoleLogs: ConsoleLogs[] | undefined = undefined
36+
3137
static styles = [
3238
...Element.styles,
3339
css`
@@ -186,8 +192,8 @@ export class DevtoolsWorkbench extends Element {
186192
<wdio-devtools-tab label="Log">
187193
<wdio-devtools-logs></wdio-devtools-logs>
188194
</wdio-devtools-tab>
189-
<wdio-devtools-tab label="Console">
190-
<wdio-devtools-console-logs></wdio-devtools-console-logs>
195+
<wdio-devtools-tab label="Console" .badge="${this.consoleLogs?.length || 0}">
196+
<wdio-devtools-console-logs id="console-logs-tab"></wdio-devtools-console-logs>
191197
</wdio-devtools-tab>
192198
<wdio-devtools-tab label="Network">
193199
<section

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

Lines changed: 177 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ import { consume } from '@lit/context'
55

66
import { consoleLogContext } from '../../controller/DataManager.js'
77

8-
import '~icons/mdi/chevron-right.js'
9-
import '../placeholder.js'
10-
11-
const BG: Record<ConsoleLogs['type'], string> = {
12-
warn: 'editorOverviewRulerWarningForeground',
13-
info: 'editorOverviewRulerInfoForeground',
14-
error: 'editorOverviewRulerErrorForeground',
15-
log: 'panelBorder'
8+
const LOG_ICONS: Record<ConsoleLogs['type'], string> = {
9+
log: '📄',
10+
info: 'ℹ️',
11+
warn: '⚠️',
12+
error: '❌'
1613
}
1714

1815
const SOURCE_COMPONENT = 'wdio-devtools-console-logs'
@@ -23,46 +20,192 @@ export class DevtoolsConsoleLogs extends Element {
2320
css`
2421
:host {
2522
display: flex;
26-
width: 100%;
27-
height: 100%;
23+
flex: 1;
2824
flex-direction: column;
29-
padding: 5px;
30-
min-height: 200px;
25+
background-color: var(--vscode-editor-background);
26+
min-height: 0;
27+
position: relative;
28+
}
29+
30+
.console-container {
31+
flex: 1;
32+
overflow-y: auto;
33+
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
34+
font-size: 13px;
35+
line-height: 1.6;
36+
}
37+
38+
.log-entry {
39+
display: flex;
40+
align-items: flex-start;
41+
padding: 2px 8px;
42+
border-bottom: 1px solid rgba(128, 128, 128, 0.05);
43+
min-height: 22px;
44+
}
45+
46+
.log-entry:hover {
47+
background-color: rgba(255, 255, 255, 0.02);
48+
}
49+
50+
.log-entry.log-type-error {
51+
background-color: rgba(244, 135, 113, 0.03);
52+
}
53+
54+
.log-entry.log-type-warn {
55+
background-color: rgba(205, 151, 49, 0.03);
56+
}
57+
58+
.log-entry.log-type-info {
59+
background-color: rgba(14, 99, 156, 0.03);
60+
}
61+
62+
.log-time,
63+
.log-icon {
64+
flex-shrink: 0;
65+
}
66+
67+
.log-time {
68+
width: 45px;
69+
text-align: right;
70+
margin-right: 12px;
71+
font-size: 11px;
72+
opacity: 0.5;
73+
user-select: none;
74+
color: var(--vscode-editorLineNumber-foreground);
75+
line-height: 18px;
76+
}
77+
78+
.log-icon {
79+
margin-right: 8px;
80+
font-size: 14px;
81+
line-height: 18px;
82+
}
83+
84+
.log-prefix {
85+
flex-shrink: 0;
86+
color: var(--vscode-foreground);
87+
opacity: 0.8;
88+
margin-right: 4px;
89+
}
90+
91+
.log-content {
92+
flex: 1;
93+
min-width: 0;
94+
word-break: break-word;
95+
line-height: 18px;
96+
display: flex;
97+
align-items: baseline;
98+
}
99+
100+
.log-message {
101+
color: var(--vscode-foreground);
102+
white-space: pre-wrap;
103+
word-break: break-word;
104+
}
105+
106+
.log-entry.log-type-error .log-message {
107+
color: #f48771;
108+
}
109+
110+
.log-entry.log-type-warn .log-message {
111+
color: #cd9731;
112+
}
113+
114+
.log-entry.log-type-info .log-message {
115+
color: #75beff;
116+
}
117+
118+
.empty-state {
119+
position: absolute;
120+
inset: 0;
121+
display: flex;
122+
flex-direction: column;
123+
align-items: center;
124+
justify-content: center;
125+
gap: 12px;
126+
color: var(--vscode-descriptionForeground);
127+
}
128+
129+
.empty-state-icon {
130+
font-size: 48px;
131+
opacity: 0.3;
132+
}
133+
134+
.empty-state-text {
135+
font-size: 14px;
136+
opacity: 0.6;
31137
}
32138
`
33139
]
34140

35141
@consume({ context: consoleLogContext, subscribe: true })
36142
logs: ConsoleLogs[] | undefined = undefined
37143

144+
get logCount(): number {
145+
return this.logs?.length || 0
146+
}
147+
148+
#startTime?: number
149+
150+
#formatElapsedTime(timestamp: number): string {
151+
if (this.#startTime === undefined) {
152+
this.#startTime = this.logs?.[0]?.timestamp ?? timestamp
153+
}
154+
const elapsed = (timestamp - this.#startTime!) / 1000
155+
return `${elapsed.toFixed(1)}s`
156+
}
157+
158+
#formatArgs(args: any[]): string {
159+
if (Array.isArray(args)) {
160+
return args.map(arg => {
161+
if (typeof arg === 'string') return arg
162+
try {
163+
return JSON.stringify(arg, null, 2)
164+
} catch {
165+
return String(arg)
166+
}
167+
}).join(' ')
168+
}
169+
return String(args)
170+
}
171+
38172
render() {
39-
if (!this.logs) {
40-
return html`<wdio-devtools-placeholder></wdio-devtools-placeholder>`
173+
if (!this.logs || this.logs.length === 0) {
174+
return html`
175+
<div class="empty-state">
176+
<div class="empty-state-icon">📋</div>
177+
<div class="empty-state-text">No console logs captured yet</div>
178+
</div>
179+
`
41180
}
42181

43-
const logs = this.logs.length === 0 ? [{ args: '' }] : this.logs
182+
if (this.logs.length === 0) {
183+
return html`
184+
<div class="empty-state">
185+
<div class="empty-state-icon">📋</div>
186+
<div class="empty-state-text">No console logs captured yet</div>
187+
</div>
188+
`
189+
}
44190

45191
return html`
46-
${Object.values(logs).map(
47-
(log: any) => html`
48-
<dl class="w-full flex grow-0">
49-
<dt class="flex">
50-
<icon-mdi-chevron-right
51-
class="text-base transition-transform block"
52-
></icon-mdi-chevron-right>
53-
${log.type
54-
? html`<span
55-
class="block bg-${BG[
56-
log.type
57-
]} rounded text-sm py-[1px] px-[5px] my-1"
58-
>${log.type}</span
59-
>`
192+
<div class="console-container">
193+
${this.logs.map((log: any) => {
194+
const icon = LOG_ICONS[log.type] || LOG_ICONS.log
195+
return html`
196+
<div class="log-entry log-type-${log.type || 'log'}">
197+
${log.timestamp
198+
? html`<div class="log-time">${this.#formatElapsedTime(log.timestamp)}</div>`
60199
: nothing}
61-
</dt>
62-
<dd class="flex justify-center items-center mx-2">${log.args}</dd>
63-
</dl>
64-
`
65-
)}
200+
<div class="log-icon">${icon}</div>
201+
<div class="log-content">
202+
${log.source === 'test' ? html`<span class="log-prefix">>>></span>` : nothing}
203+
<span class="log-message">${this.#formatArgs(log.args)}</span>
204+
</div>
205+
</div>
206+
`
207+
})}
208+
</div>
66209
`
67210
}
68211
}

packages/script/src/collectors/consoleLogs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface ConsoleLogs {
55
type: 'log' | 'info' | 'warn' | 'error'
66
args: any[]
77
timestamp: number
8+
source?: 'browser' | 'test'
89
}
910

1011
export class ConsoleLogCollector implements Collector<ConsoleLogs> {

packages/service/src/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
export const PAGE_TRANSITION_COMMANDS: string[] = [
22
'url',
33
'navigateTo',
4-
'elementClick'
4+
'elementClick',
5+
'click'
56
]
67

78
export const DEFAULT_LAUNCH_CAPS: WebdriverIO.Capabilities = {

packages/service/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ export default class DevToolsHookService implements Services.ServiceInstance {
333333
)
334334
await fs.writeFile(traceFilePath, JSON.stringify(traceLog))
335335
log.info(`DevTools trace saved to ${traceFilePath}`)
336+
337+
// Clean up console patching
338+
this.#sessionCapturer.cleanup()
336339
}
337340

338341
/**

0 commit comments

Comments
 (0)