Skip to content

Commit 1181e0c

Browse files
committed
Playwright E2E: stamp running test name into window title
beforeEach sets the main window's OS title to `<base> (Running: <test>)` and afterEach appends `(FINISHED)`, so the dock / Cmd-Tab / Linux title bar tells you which spec is in flight without tailing the log. Base title is captured once per worker so suffixes don't accumulate across tests. Uses the standard `plugin:window|set_title` Tauri command; permissions are added only to the feature-gated `playwright.json` capability that `build.rs` generates when `playwright-e2e` is on, so release builds are unaffected.
1 parent 9211946 commit 1181e0c

3 files changed

Lines changed: 65 additions & 1 deletion

File tree

apps/desktop/src-tauri/build.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ fn main() {
2424
"identifier": "playwright",
2525
"description": "Playwright E2E testing plugin permissions (auto-generated by build.rs)",
2626
"windows": ["main", "settings", "viewer-*"],
27-
"permissions": ["playwright:default"]
27+
"permissions": [
28+
"playwright:default",
29+
"core:window:allow-title",
30+
"core:window:allow-set-title"
31+
]
2832
}
2933
"#,
3034
)

apps/desktop/test/e2e-playwright/CLAUDE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ Playwright (Node.js) --Unix socket--> tauri-plugin-playwright (Rust)
1616
Same tests run on macOS and Linux. Platform differences (Ctrl vs Meta) are handled by a single `CTRL_OR_META` constant
1717
in `helpers.ts`.
1818

19+
## Window-title decoration
20+
21+
`fixtures.ts` wraps each test in `beforeEach`/`afterEach` hooks that update the main window's OS title via the standard
22+
Tauri window plugin (`plugin:window|set_title`). While a test runs the title becomes `<base> (Running: <name>)`; after
23+
it returns, `(FINISHED)` is appended. The base title is captured once per worker on the first hook call so suffixes
24+
don't accumulate. The required permissions (`core:window:allow-title`, `core:window:allow-set-title`) are added to the
25+
feature-gated `playwright.json` capability generated by `build.rs`, so they're absent from release builds. Use this in
26+
Cmd-Tab / Mission Control / Linux title bars to spot which spec is in flight or stuck without tailing the log.
27+
1928
## Running on macOS
2029

2130
**Via the checker (recommended):** The checker handles the full lifecycle automatically: build, fixture creation, app

apps/desktop/test/e2e-playwright/fixtures.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@
99
* - globalSetup: creates the fixture directory tree (~170 MB)
1010
* - beforeEach: recreates small text files (keeps bulk .dat files)
1111
* - globalTeardown: deletes the fixture directory
12+
*
13+
* Window-title decoration:
14+
* - `beforeEach` sets the main window's OS title to "<base> (Running: <test>)"
15+
* - `afterEach` updates it to "<base> (Running: <test>) (FINISHED)"
16+
* so you can glance at the dock / Cmd-Tab / Linux title bar to see which
17+
* spec is in flight (or stuck) without tailing the log.
1218
*/
1319

1420
import { createTauriTest } from '@srsholmes/tauri-playwright'
21+
import type { TestInfo } from '@playwright/test'
1522

1623
// Each parallel E2E shard spawns its own Tauri instance bound to a distinct
1724
// Unix socket. The Go check runner sets CMDR_PLAYWRIGHT_SOCKET per shard.
@@ -26,3 +33,47 @@ export const { test, expect } = createTauriTest({
2633
// Tauri mode config
2734
mcpSocket: socketPath,
2835
})
36+
37+
// Captured once per worker on the first beforeEach so suffixes don't accumulate
38+
// across tests. Each shard owns its own Tauri instance + its own worker process,
39+
// so this lives correctly per-shard.
40+
let baseTitle: string | null = null
41+
42+
type EvaluatablePage = { evaluate: (js: string) => Promise<unknown> }
43+
44+
/** Joins describe blocks + test title into "Section > test name" style. */
45+
function formatTestName(info: TestInfo): string {
46+
const parts = info.titlePath
47+
const fileIdx = parts.findIndex((p) => /\.spec\.[tj]s$/.test(p))
48+
const tail = fileIdx >= 0 ? parts.slice(fileIdx + 1) : [info.title]
49+
return tail.filter((p) => p.length > 0).join(' › ')
50+
}
51+
52+
async function readMainTitle(tauriPage: EvaluatablePage): Promise<string> {
53+
const result = await tauriPage.evaluate(`window.__TAURI_INTERNALS__.invoke('plugin:window|title', { label: 'main' })`)
54+
return typeof result === 'string' ? result : ''
55+
}
56+
57+
async function setMainTitle(tauriPage: EvaluatablePage, title: string): Promise<void> {
58+
await tauriPage.evaluate(
59+
`window.__TAURI_INTERNALS__.invoke('plugin:window|set_title', { label: 'main', value: ${JSON.stringify(title)} })`,
60+
)
61+
}
62+
63+
test.beforeEach(async ({ tauriPage }, testInfo) => {
64+
try {
65+
if (baseTitle === null) baseTitle = await readMainTitle(tauriPage)
66+
await setMainTitle(tauriPage, `${baseTitle} (Running: ${formatTestName(testInfo)})`)
67+
} catch {
68+
// Title decoration is purely for human eyeballs — never block a test on it.
69+
}
70+
})
71+
72+
test.afterEach(async ({ tauriPage }, testInfo) => {
73+
try {
74+
if (baseTitle === null) baseTitle = await readMainTitle(tauriPage)
75+
await setMainTitle(tauriPage, `${baseTitle} (Running: ${formatTestName(testInfo)}) (FINISHED)`)
76+
} catch {
77+
// See beforeEach.
78+
}
79+
})

0 commit comments

Comments
 (0)