electron-dev-bridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +555 -0
  3. package/dist/cdp-tools/dom-query.d.ts +2 -0
  4. package/dist/cdp-tools/dom-query.js +307 -0
  5. package/dist/cdp-tools/helpers.d.ts +17 -0
  6. package/dist/cdp-tools/helpers.js +48 -0
  7. package/dist/cdp-tools/index.d.ts +5 -0
  8. package/dist/cdp-tools/index.js +26 -0
  9. package/dist/cdp-tools/interaction.d.ts +2 -0
  10. package/dist/cdp-tools/interaction.js +195 -0
  11. package/dist/cdp-tools/lifecycle.d.ts +2 -0
  12. package/dist/cdp-tools/lifecycle.js +78 -0
  13. package/dist/cdp-tools/navigation.d.ts +2 -0
  14. package/dist/cdp-tools/navigation.js +128 -0
  15. package/dist/cdp-tools/state.d.ts +2 -0
  16. package/dist/cdp-tools/state.js +109 -0
  17. package/dist/cdp-tools/types.d.ts +22 -0
  18. package/dist/cdp-tools/types.js +1 -0
  19. package/dist/cdp-tools/visual.d.ts +2 -0
  20. package/dist/cdp-tools/visual.js +130 -0
  21. package/dist/cli/index.d.ts +2 -0
  22. package/dist/cli/index.js +50 -0
  23. package/dist/cli/init.d.ts +1 -0
  24. package/dist/cli/init.js +146 -0
  25. package/dist/cli/register.d.ts +1 -0
  26. package/dist/cli/register.js +40 -0
  27. package/dist/cli/serve.d.ts +1 -0
  28. package/dist/cli/serve.js +34 -0
  29. package/dist/cli/validate.d.ts +1 -0
  30. package/dist/cli/validate.js +65 -0
  31. package/dist/index.d.ts +30 -0
  32. package/dist/index.js +3 -0
  33. package/dist/scanner/ipc-scanner.d.ts +6 -0
  34. package/dist/scanner/ipc-scanner.js +14 -0
  35. package/dist/scanner/schema-scanner.d.ts +6 -0
  36. package/dist/scanner/schema-scanner.js +14 -0
  37. package/dist/server/cdp-bridge.d.ts +12 -0
  38. package/dist/server/cdp-bridge.js +72 -0
  39. package/dist/server/mcp-server.d.ts +2 -0
  40. package/dist/server/mcp-server.js +126 -0
  41. package/dist/server/resource-builder.d.ts +9 -0
  42. package/dist/server/resource-builder.js +15 -0
  43. package/dist/server/tool-builder.d.ts +9 -0
  44. package/dist/server/tool-builder.js +39 -0
  45. package/dist/utils/load-config.d.ts +5 -0
  46. package/dist/utils/load-config.js +17 -0
  47. package/package.json +75 -0
  48. package/skills/electron-app-dev/SKILL.md +140 -0
  49. package/skills/electron-debugging/SKILL.md +203 -0
  50. package/skills/electron-e2e-testing/SKILL.md +181 -0
@@ -0,0 +1,17 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ /**
3
+ * Load an electron-mcp config file, with TypeScript support via tsx.
4
+ */
5
+ export async function loadConfig(configPath) {
6
+ let mod;
7
+ if (configPath.endsWith('.ts')) {
8
+ // Use tsx's tsImport for TypeScript configs
9
+ const { tsImport } = await import('tsx/esm/api');
10
+ mod = await tsImport(configPath, import.meta.url);
11
+ }
12
+ else {
13
+ // Standard import for .js/.mjs configs
14
+ mod = await import(pathToFileURL(configPath).href);
15
+ }
16
+ return mod.default;
17
+ }
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "electron-dev-bridge",
3
+ "version": "0.1.0",
4
+ "description": "Expose Electron IPC handlers as MCP tools for Claude Code, with 22 built-in CDP tools for DOM automation",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "electron-mcp": "dist/cli/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "test": "node --test dist/**/*.test.js",
21
+ "lint": "tsc --noEmit"
22
+ },
23
+ "keywords": [
24
+ "electron",
25
+ "mcp",
26
+ "model-context-protocol",
27
+ "claude",
28
+ "claude-code",
29
+ "cdp",
30
+ "chrome-devtools-protocol",
31
+ "ipc",
32
+ "testing",
33
+ "automation",
34
+ "desktop-app"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/nicholasgriffintn/electron-dev-bridge.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/nicholasgriffintn/electron-dev-bridge/issues"
42
+ },
43
+ "homepage": "https://github.com/nicholasgriffintn/electron-dev-bridge#readme",
44
+ "author": "",
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.12.1",
47
+ "chrome-remote-interface": "^0.33.2",
48
+ "tsx": "^4.19.0",
49
+ "zod-to-json-schema": "^3.24.5"
50
+ },
51
+ "peerDependencies": {
52
+ "zod": "^3.0.0"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "zod": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "engines": {
60
+ "node": ">=18"
61
+ },
62
+ "files": [
63
+ "dist",
64
+ "skills",
65
+ "LICENSE",
66
+ "!dist/**/*.test.js",
67
+ "!dist/**/*.test.d.ts"
68
+ ],
69
+ "license": "MIT",
70
+ "devDependencies": {
71
+ "@types/chrome-remote-interface": "^0.33.0",
72
+ "@types/node": "^25.3.2",
73
+ "typescript": "^5.9.3"
74
+ }
75
+ }
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: electron-app-dev
3
+ description: >
4
+ Develop and automate Electron apps using the electron-dev-bridge bridge.
5
+ Trigger on: Electron app, desktop app, UI automation, DOM inspection,
6
+ IPC handler, screenshot, BrowserWindow, webContents, CDP tools,
7
+ electron-mcp, preload script, contextBridge.
8
+ ---
9
+
10
+ # Electron App Development with electron-dev-bridge
11
+
12
+ Use the MCP bridge to connect, inspect, interact with, and screenshot your Electron app directly from Claude Code.
13
+
14
+ ## Prerequisites
15
+
16
+ 1. Install: `npm install electron-dev-bridge`
17
+ 2. Generate config: `npx electron-mcp init`
18
+ 3. Register: `npx electron-mcp register`
19
+ 4. Start your app with `--remote-debugging-port=9229`
20
+
21
+ ## Connecting
22
+
23
+ ```
24
+ # Launch and connect in one step
25
+ electron_launch appPath="/path/to/{YOUR_APP}"
26
+
27
+ # Or connect to an already-running app (uses the port from your config)
28
+ electron_connect
29
+ ```
30
+
31
+ Always connect before using any other tools.
32
+
33
+ ## Tool Reference
34
+
35
+ ### Connection
36
+ | Tool | Use for |
37
+ |------|---------|
38
+ | `electron_launch` | Launch app with debug port and connect |
39
+ | `electron_connect` | Connect to running app |
40
+
41
+ ### DOM Queries
42
+ | Tool | Use for |
43
+ |------|---------|
44
+ | `electron_query_selector` | Find one element by CSS selector |
45
+ | `electron_query_selector_all` | Find all matching elements (max 50) |
46
+ | `electron_find_by_text` | Find elements by visible text content |
47
+ | `electron_find_by_role` | Find elements by ARIA role |
48
+ | `electron_get_accessibility_tree` | Full a11y tree with roles and names |
49
+
50
+ ### Interaction
51
+ | Tool | Use for |
52
+ |------|---------|
53
+ | `electron_click` | Click by selector or coordinates |
54
+ | `electron_type_text` | Type into input (provide `selector` to auto-focus) |
55
+ | `electron_press_key` | Press Enter, Tab, Escape, arrows, etc. |
56
+ | `electron_select_option` | Select dropdown option by value or text |
57
+
58
+ ### State Reading
59
+ | Tool | Use for |
60
+ |------|---------|
61
+ | `electron_get_text` | Get innerText of element |
62
+ | `electron_get_value` | Get input/textarea/select value |
63
+ | `electron_get_attribute` | Get specific attribute |
64
+ | `electron_get_bounding_box` | Get element position and size |
65
+ | `electron_get_url` | Get current page URL |
66
+
67
+ ### Navigation & Viewport
68
+ | Tool | Use for |
69
+ |------|---------|
70
+ | `electron_wait_for_selector` | Wait for element to appear (default 5s) |
71
+ | `electron_set_viewport` | Override viewport metrics for responsive testing (`width`, `height` required) |
72
+ | `electron_scroll` | Scroll page or element (`direction`: up/down/left/right, `amount`: pixels, `selector`: optional) |
73
+
74
+ ### Screenshots & Visual
75
+ | Tool | Use for |
76
+ |------|---------|
77
+ | `electron_screenshot` | Capture full page or element |
78
+ | `electron_compare_screenshots` | Byte-level diff of two screenshots (returns `diffPercent`) |
79
+ | `electron_highlight_element` | Outline element in red for 3 seconds |
80
+
81
+ ## Selector Strategy (priority order)
82
+
83
+ 1. `[data-testid="..."]` -- most stable
84
+ 2. `[role="..."]`, `[aria-label="..."]` -- semantic
85
+ 3. `.bem-class-name` -- reasonably stable
86
+ 4. Element hierarchy -- last resort
87
+
88
+ ## Waiting Pattern
89
+
90
+ Always wait before interacting or capturing:
91
+
92
+ ```
93
+ electron_wait_for_selector selector=".content-loaded" timeout=10000
94
+ electron_screenshot
95
+ ```
96
+
97
+ Never use arbitrary sleep/delays.
98
+
99
+ ## IPC Tools
100
+
101
+ If the app uses electron-dev-bridge with configured IPC handlers, tools are named by replacing colons with underscores:
102
+
103
+ | IPC channel | MCP tool name | Preload path |
104
+ |-------------|---------------|--------------|
105
+ | `{domain}:{action}` | `{domain}_{action}` | `window.electronAPI.{domain}.{action}` |
106
+
107
+ Call IPC tools directly by name once the server is registered. Tool names depend on your app's config — e.g., `profiles_query`, `settings_get`.
108
+
109
+ ## Playbook: Build & Verify
110
+
111
+ 1. Make code changes
112
+ 2. `electron_launch` (or restart the app)
113
+ 3. `electron_wait_for_selector` on the changed element
114
+ 4. `electron_screenshot` to capture current state
115
+ 5. Evaluate the screenshot visually
116
+ 6. If issues: fix code, restart, re-verify
117
+
118
+ ## Playbook: Explore App Structure
119
+
120
+ 1. `electron_connect`
121
+ 2. `electron_get_accessibility_tree maxDepth=5` to see the component hierarchy
122
+ 3. `electron_query_selector_all selector="[data-testid]"` to find test hooks
123
+ 4. `electron_screenshot` for visual context
124
+ 5. Use findings to plan automation or testing
125
+
126
+ ## Playbook: Call IPC Handlers
127
+
128
+ 1. `electron_connect`
129
+ 2. Call the IPC tool directly, e.g. `profiles_query query="test"`
130
+ 3. Inspect the returned JSON
131
+ 4. Use `electron_screenshot` to verify UI updated
132
+
133
+ ## Screenshot Evaluation Checklist
134
+
135
+ When reviewing a screenshot, check:
136
+ - Layout: positioning, overlaps, overflow, alignment
137
+ - Text: visibility, truncation, correct content
138
+ - Colors: contrast, theme consistency
139
+ - States: hover, focus, disabled, loading, error, empty
140
+ - Responsiveness: behavior at current viewport size
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: electron-debugging
3
+ description: >
4
+ Debug and troubleshoot Electron apps via electron-dev-bridge bridge tools.
5
+ Trigger on: debug, bug, broken, not working, UI issue, element not found,
6
+ blank screen, can't connect, crash, stale, timeout, click not working,
7
+ missing element, wrong text, layout broken.
8
+ ---
9
+
10
+ # Electron App Debugging with electron-dev-bridge
11
+
12
+ Systematic debugging workflows for Electron apps using the MCP bridge.
13
+
14
+ ## Diagnostic Flowchart
15
+
16
+ ```
17
+ Problem reported
18
+ |
19
+ +-- Can you connect?
20
+ | NO --> See "Connection Troubleshooting"
21
+ | YES
22
+ |
23
+ +-- Take screenshot. Is the UI visible?
24
+ | NO --> See "Blank Screen / Loading Issues"
25
+ | YES
26
+ |
27
+ +-- Is the expected element present?
28
+ | NO --> See "Element Not Found"
29
+ | YES
30
+ |
31
+ +-- Does interaction work?
32
+ | NO --> See "Interaction Failures"
33
+ | YES
34
+ |
35
+ +-- Is the displayed content correct?
36
+ NO --> See "Wrong Content / State"
37
+ YES --> Issue may be intermittent. Add waits and retry.
38
+ ```
39
+
40
+ ## Connection Troubleshooting
41
+
42
+ **Symptom:** `electron_connect` or `electron_launch` fails.
43
+
44
+ ```
45
+ # Step 1: Verify the app is running with debug port
46
+ # (run in terminal)
47
+ lsof -i :9229
48
+
49
+ # Step 2: If no process on port, launch with debug flag
50
+ electron_launch appPath="/path/to/{YOUR_APP}"
51
+
52
+ # Step 3: If port is in use by another process, use a different port
53
+ electron_connect port=9230
54
+ ```
55
+
56
+ | Error | Cause | Fix |
57
+ |-------|-------|-----|
58
+ | Connection refused | App not running or no debug port | Start app with `--remote-debugging-port=9229` |
59
+ | Port already in use | Another process on 9229 | Kill the process or use `electron_connect port=9230` |
60
+ | Target not found | App has no renderer window | Ensure a BrowserWindow is created |
61
+ | Connection lost mid-session | App crashed or reloaded | `electron_connect` to reconnect |
62
+
63
+ ## Blank Screen / Loading Issues
64
+
65
+ **Symptom:** Screenshot shows blank or loading state.
66
+
67
+ ```
68
+ # 1. Screenshot to confirm state
69
+ electron_screenshot
70
+
71
+ # 2. Check the URL -- is the app loading the right page?
72
+ electron_get_url
73
+
74
+ # 3. Wait for a known root element
75
+ electron_wait_for_selector selector="{YOUR_APP_ROOT}" timeout=15000
76
+
77
+ # 4. If timeout: check the accessibility tree for any content
78
+ electron_get_accessibility_tree maxDepth=3
79
+
80
+ # 5. Re-screenshot after waiting
81
+ electron_screenshot
82
+ ```
83
+
84
+ **Common causes:**
85
+ - App still loading (increase timeout)
86
+ - Wrong URL loaded (check `electron_get_url`)
87
+ - JavaScript error blocking render (check app console logs)
88
+ - Missing preload script (app can't access IPC)
89
+
90
+ ## Element Not Found
91
+
92
+ **Symptom:** `electron_query_selector` returns no match.
93
+
94
+ ```
95
+ # 1. Verify what IS on the page
96
+ electron_get_accessibility_tree maxDepth=5
97
+
98
+ # 2. Search by text instead of selector
99
+ electron_find_by_text text="Submit"
100
+
101
+ # 3. Search by role
102
+ electron_find_by_role role="button"
103
+
104
+ # 4. Try a broader selector
105
+ electron_query_selector_all selector="button"
106
+
107
+ # 5. Check if element is in a different part of the tree
108
+ electron_query_selector_all selector="iframe"
109
+ # If iframes exist, the element may be inside one
110
+
111
+ # 6. Highlight a similar element to verify targeting
112
+ electron_highlight_element selector=".some-visible-element"
113
+ electron_screenshot
114
+ ```
115
+
116
+ **Common causes:**
117
+ - Selector typo or stale selector (class names changed)
118
+ - Element not yet rendered (add `electron_wait_for_selector`)
119
+ - Element inside shadow DOM or iframe
120
+ - Element conditionally rendered (check app state)
121
+
122
+ ## Interaction Failures
123
+
124
+ **Symptom:** `electron_click` or `electron_type_text` has no visible effect.
125
+
126
+ ```
127
+ # 1. Verify the element exists and is visible
128
+ electron_get_bounding_box selector="{TARGET_SELECTOR}"
129
+ # Check: width/height > 0, coordinates are within viewport
130
+
131
+ # 2. Check if element is obscured by an overlay
132
+ electron_screenshot
133
+ # Look for modals, tooltips, or overlapping elements
134
+
135
+ # 3. Check element attributes
136
+ electron_get_attribute selector="{TARGET_SELECTOR}" attribute="disabled"
137
+ electron_get_attribute selector="{TARGET_SELECTOR}" attribute="readonly"
138
+
139
+ # 4. Try clicking by coordinates instead
140
+ electron_get_bounding_box selector="{TARGET_SELECTOR}"
141
+ # Use returned x + width/2, y + height/2 as click coordinates
142
+ electron_click x=150 y=200
143
+
144
+ # 5. For type_text: ensure element is focused
145
+ electron_click selector="{TARGET_SELECTOR}"
146
+ electron_type_text text="test input"
147
+ ```
148
+
149
+ | Problem | Cause | Fix |
150
+ |---------|-------|-----|
151
+ | Click no effect | Overlay blocking | Dismiss the overlay first |
152
+ | Click no effect | Element disabled | Check and resolve disabled state |
153
+ | Click no effect | Wrong coordinates | Use `electron_get_bounding_box` to verify |
154
+ | Type not appearing | Element not focused | Click element first, then type |
155
+ | Type not appearing | Input is readonly | Check `readonly`/`disabled` attributes |
156
+ | Key press ignored | Wrong key name | Supported: `Enter`, `Tab`, `Escape`, `Backspace`, `Delete`, `ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight`, `Home`, `End`, `Space` |
157
+
158
+ ## Wrong Content / State
159
+
160
+ **Symptom:** UI shows incorrect text, values, or layout.
161
+
162
+ ```
163
+ # 1. Read the actual content
164
+ electron_get_text selector="{TARGET_SELECTOR}"
165
+ electron_get_value selector="{INPUT_SELECTOR}"
166
+
167
+ # 2. Screenshot for visual comparison
168
+ electron_screenshot
169
+
170
+ # 3. Check the accessibility tree for the full component context
171
+ electron_get_accessibility_tree maxDepth=5
172
+
173
+ # 4. Highlight the problematic element
174
+ electron_highlight_element selector="{TARGET_SELECTOR}"
175
+ electron_screenshot
176
+ ```
177
+
178
+ ## Recovery Steps
179
+
180
+ ```
181
+ # 1. Screenshot current state
182
+ electron_screenshot
183
+
184
+ # 2. Reconnect if stale
185
+ electron_connect
186
+
187
+ # 3. Check URL
188
+ electron_get_url
189
+
190
+ # 4. If app is in bad state, restart
191
+ electron_launch appPath="/path/to/{YOUR_APP}"
192
+ electron_wait_for_selector selector="{YOUR_APP_ROOT}" timeout=15000
193
+ ```
194
+
195
+ ## Common Error Patterns
196
+
197
+ | Error | Cause | Fix |
198
+ |-------|-------|-----|
199
+ | "No target found" | No renderer connected | `electron_connect` |
200
+ | "Selector not found" | Bad CSS selector | Use `electron_get_accessibility_tree` |
201
+ | "Timeout waiting" | Element didn't appear | Increase timeout or check conditional rendering |
202
+ | "Cannot find context" | CDP session expired | `electron_connect` again |
203
+ | "Execution context destroyed" | Page navigated | Wait for new page, retry |
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: electron-e2e-testing
3
+ description: >
4
+ End-to-end testing workflows for Electron apps via electron-dev-bridge.
5
+ Trigger on: test, e2e, end-to-end, regression, form testing,
6
+ UI verification, test flow, smoke test, integration test,
7
+ visual regression, form fill, submit, assertion.
8
+ ---
9
+
10
+ # Electron E2E Testing with electron-dev-bridge
11
+
12
+ Structured test patterns for verifying Electron app behavior using the MCP bridge tools.
13
+
14
+ ## Test Pattern: Launch, Wait, Act, Assert, Screenshot
15
+
16
+ Every test follows this structure:
17
+
18
+ ```
19
+ 1. electron_launch / electron_connect -- establish connection
20
+ 2. electron_wait_for_selector -- wait for ready state
21
+ 3. electron_click / electron_type_text -- perform actions
22
+ 4. electron_wait_for_selector -- wait for result
23
+ 5. electron_get_text / electron_get_value -- assert expected state
24
+ 6. electron_screenshot -- capture evidence
25
+ ```
26
+
27
+ ## Playbook: Basic Interaction Test
28
+
29
+ **Goal:** Verify a button click produces the expected result.
30
+
31
+ ```
32
+ # 1. Connect
33
+ electron_connect
34
+
35
+ # 2. Wait for the target element
36
+ electron_wait_for_selector selector="[data-testid='submit-btn']" timeout=5000
37
+
38
+ # 3. Click
39
+ electron_click selector="[data-testid='submit-btn']"
40
+
41
+ # 4. Wait for the result
42
+ electron_wait_for_selector selector="[data-testid='result-message']" timeout=5000
43
+
44
+ # 5. Assert
45
+ electron_get_text selector="[data-testid='result-message']"
46
+ # Expected: "Success" or similar
47
+
48
+ # 6. Evidence
49
+ electron_screenshot
50
+ ```
51
+
52
+ **Pass criteria:** `electron_get_text` returns the expected string. Screenshot shows correct UI state.
53
+
54
+ ## Playbook: Form Fill & Submit
55
+
56
+ **Goal:** Complete a form and verify submission.
57
+
58
+ ```
59
+ # 1. Connect and wait for form
60
+ electron_connect
61
+ electron_wait_for_selector selector="form"
62
+
63
+ # 2. Discover fields
64
+ electron_get_accessibility_tree maxDepth=5
65
+
66
+ # 3. Fill text inputs
67
+ electron_type_text selector="#name" text="Jane Doe"
68
+ electron_type_text selector="#email" text="jane@example.com"
69
+
70
+ # 4. Fill dropdown
71
+ electron_select_option selector="#role" value="admin"
72
+
73
+ # 5. Screenshot before submit (evidence of filled state)
74
+ electron_screenshot
75
+
76
+ # 6. Submit
77
+ electron_click selector="[type='submit']"
78
+
79
+ # 7. Wait for result
80
+ electron_wait_for_selector selector=".success-message" timeout=10000
81
+
82
+ # 8. Assert
83
+ electron_get_text selector=".success-message"
84
+ # Expected: contains "submitted" or "saved"
85
+
86
+ # 9. Screenshot after submit
87
+ electron_screenshot
88
+ ```
89
+
90
+ **Pass criteria:** Success message appears. Both before/after screenshots look correct.
91
+
92
+ ## Playbook: Visual Regression
93
+
94
+ **Goal:** Detect unintended UI changes after a code modification.
95
+
96
+ ```
97
+ # Phase 1: Capture baseline (before changes)
98
+ electron_connect
99
+ electron_wait_for_selector selector="{YOUR_APP_ROOT}"
100
+ electron_screenshot
101
+ # Save as baseline -- note the returned file path
102
+
103
+ # Phase 2: After making code changes, restart app
104
+ electron_launch appPath="/path/to/{YOUR_APP}"
105
+ electron_wait_for_selector selector="{YOUR_APP_ROOT}"
106
+ electron_screenshot
107
+ # Save as current -- note the returned file path
108
+
109
+ # Phase 3: Compare
110
+ electron_compare_screenshots pathA="baseline.png" pathB="current.png"
111
+ # Returns: { identical: false, diffPercent: 0.5, totalBytes: 120000, diffBytes: 600 }
112
+ ```
113
+
114
+ **Thresholds** (note: this is a byte-level diff, not pixel-aware):
115
+ - `< 1%` diff: likely acceptable (compression variance, anti-aliasing)
116
+ - `1-5%` diff: review the screenshot -- may be intentional
117
+ - `> 5%` diff: likely a regression, investigate
118
+
119
+ ## Playbook: Multi-Page Flow
120
+
121
+ **Goal:** Test a workflow spanning multiple views/pages.
122
+
123
+ ```
124
+ # Step 1: Login page
125
+ electron_connect
126
+ electron_wait_for_selector selector="#login-form"
127
+ electron_type_text selector="#username" text="testuser"
128
+ electron_type_text selector="#password" text="testpass"
129
+ electron_click selector="[data-testid='login-btn']"
130
+ electron_screenshot
131
+
132
+ # Step 2: Dashboard (after login)
133
+ electron_wait_for_selector selector="[data-testid='dashboard']" timeout=10000
134
+ electron_get_text selector="[data-testid='welcome-msg']"
135
+ # Assert: contains "testuser"
136
+ electron_screenshot
137
+
138
+ # Step 3: Navigate to settings
139
+ electron_click selector="[data-testid='settings-link']"
140
+ electron_wait_for_selector selector="[data-testid='settings-page']"
141
+ electron_screenshot
142
+
143
+ # Step 4: Verify and return
144
+ electron_get_url
145
+ # Assert: URL contains "/settings"
146
+ ```
147
+
148
+ **Pass criteria:** Each step transitions correctly. No errors. URLs and text match expectations.
149
+
150
+ ## Key Practices
151
+
152
+ ### Always wait, never sleep
153
+ Use `electron_wait_for_selector` between every action that changes the UI. This eliminates race conditions and makes tests deterministic.
154
+
155
+ ### Screenshot at checkpoints
156
+ Capture screenshots at key moments: before actions, after actions, on errors. These serve as test evidence.
157
+
158
+ ### Use data-testid selectors
159
+ Prefer `[data-testid="..."]` selectors for test stability. They survive refactors and style changes.
160
+
161
+ ### Assert with get_text / get_value
162
+ Use `electron_get_text` and `electron_get_value` to verify expected content, not just visual inspection.
163
+
164
+ ### Handle timeouts as failures
165
+ If `electron_wait_for_selector` times out, the element didn't appear. This is a test failure -- report it with the last screenshot for debugging context.
166
+
167
+ ## IPC-Based Assertions
168
+
169
+ When the app has IPC tools configured, use them for deeper assertions. Tool names depend on your app's config — these are examples:
170
+
171
+ ```
172
+ # After a form submit, verify via IPC (example tool names)
173
+ profiles_query query="Jane Doe"
174
+ # Assert: returned array contains the submitted profile
175
+
176
+ # Check app state directly (example tool name)
177
+ session_getStatus
178
+ # Assert: status is "authenticated"
179
+ ```
180
+
181
+ IPC tools give you backend verification alongside UI assertions.