@rolepod/uiproof 0.4.1 → 0.5.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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +3 -3
- package/.cursor-plugin/plugin.json +2 -2
- package/CHANGELOG.md +99 -0
- package/README.md +11 -7
- package/dist/bin/rolepod-uiproof.js +1434 -32
- package/dist/bin/rolepod-uiproof.js.map +1 -1
- package/dist/index.d.ts +590 -2
- package/dist/index.js +1456 -32
- package/dist/index.js.map +1 -1
- package/dist/schemas/tools.json +34 -1
- package/package.json +1 -1
- package/skills/check-errors/SKILL.md +114 -0
- package/skills/scaffold-e2e/SKILL.md +14 -0
- package/skills/verify-ui/SKILL.md +137 -70
package/dist/schemas/tools.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
|
3
|
-
"rolepod_mcp_version": "0.
|
|
3
|
+
"rolepod_mcp_version": "0.5.0",
|
|
4
4
|
"tools": {
|
|
5
5
|
"rolepod_browser_open": {
|
|
6
6
|
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
@@ -32,6 +32,39 @@
|
|
|
32
32
|
"rolepod_browser_navigate": {
|
|
33
33
|
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
34
34
|
},
|
|
35
|
+
"rolepod_browser_hover": {
|
|
36
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
37
|
+
},
|
|
38
|
+
"rolepod_browser_drag": {
|
|
39
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
40
|
+
},
|
|
41
|
+
"rolepod_browser_fill_form": {
|
|
42
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
43
|
+
},
|
|
44
|
+
"rolepod_browser_upload_file": {
|
|
45
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
46
|
+
},
|
|
47
|
+
"rolepod_browser_handle_dialog": {
|
|
48
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
49
|
+
},
|
|
50
|
+
"rolepod_browser_console": {
|
|
51
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
52
|
+
},
|
|
53
|
+
"rolepod_browser_network": {
|
|
54
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
55
|
+
},
|
|
56
|
+
"rolepod_browser_set_env": {
|
|
57
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
58
|
+
},
|
|
59
|
+
"rolepod_browser_evaluate": {
|
|
60
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
61
|
+
},
|
|
62
|
+
"rolepod_browser_pages": {
|
|
63
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
64
|
+
},
|
|
65
|
+
"rolepod_browser_switch_page": {
|
|
66
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
67
|
+
},
|
|
35
68
|
"rolepod_verify_ui_flow": {
|
|
36
69
|
"$schema": "https://json-schema.org/draft/2019-09/schema#"
|
|
37
70
|
},
|
package/package.json
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: check-errors
|
|
3
|
+
description: Drive a flow and fail if any console error or failed network request occurs. Thin wrapper over verify_ui_flow with strict error-only assertions. Use to gate merges on "no regressions during this flow".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /check-errors
|
|
7
|
+
|
|
8
|
+
Thin wrapper over **`rolepod_verify_ui_flow`** focused on the question:
|
|
9
|
+
|
|
10
|
+
> Does this flow run cleanly — no console errors, no failed requests?
|
|
11
|
+
|
|
12
|
+
Use after `/verify-ui` confirms the feature works, OR as a fast smoke
|
|
13
|
+
check before merging.
|
|
14
|
+
|
|
15
|
+
## When to use
|
|
16
|
+
|
|
17
|
+
- After feature work, to gate "did I introduce a regression somewhere?"
|
|
18
|
+
- During PR review, to confirm the happy path doesn't spew errors.
|
|
19
|
+
- After dependency upgrades, to catch a quiet console break.
|
|
20
|
+
- After CSP / CORS / API auth changes — common cause of silent 4xx/5xx.
|
|
21
|
+
|
|
22
|
+
## When NOT to use
|
|
23
|
+
|
|
24
|
+
- You want to assert specific UI text — use `/verify-ui` instead.
|
|
25
|
+
- You only care about visual regression — use `/visual-diff`.
|
|
26
|
+
- You want a11y compliance — use `/audit-a11y`.
|
|
27
|
+
- Backend-only diff with no UI surface.
|
|
28
|
+
|
|
29
|
+
## Inputs
|
|
30
|
+
|
|
31
|
+
- `url` — entry point.
|
|
32
|
+
- `steps` *(optional)* — drive the flow. Same shape as `/verify-ui` steps.
|
|
33
|
+
- `exclude_console_patterns` *(optional)* — substrings; matching console
|
|
34
|
+
errors are ignored. Useful for third-party SDKs that always log
|
|
35
|
+
noise (e.g. `["facebook.com", "googletagmanager"]`).
|
|
36
|
+
- `exclude_request_patterns` *(optional)* — same idea for URLs.
|
|
37
|
+
- `allow_4xx` *(optional, default false)* — if true, only 5xx counts as
|
|
38
|
+
a failure. Useful when 4xx is part of the auth happy path.
|
|
39
|
+
|
|
40
|
+
## Process
|
|
41
|
+
|
|
42
|
+
Call `rolepod_verify_ui_flow` with:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mode": "assert",
|
|
47
|
+
"open": { "platform": "web", "url": "<url>" },
|
|
48
|
+
"steps": [ ...user-provided... ],
|
|
49
|
+
"expect": [
|
|
50
|
+
{ "kind": "no_console_errors", "exclude_patterns": [...] },
|
|
51
|
+
{ "kind": "no_failed_requests", "exclude_patterns": [...], "allow_4xx": false }
|
|
52
|
+
],
|
|
53
|
+
"capture": ["screenshot", "console", "har"]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Surface the result. On `passed: false`, point the user at `console.json`
|
|
58
|
+
and `network.har` in `evidence_paths` so they can drill in.
|
|
59
|
+
|
|
60
|
+
## Outputs
|
|
61
|
+
|
|
62
|
+
Same shape as `/verify-ui`:
|
|
63
|
+
|
|
64
|
+
- `passed: boolean`
|
|
65
|
+
- `failure_reason` — e.g. `Expectations failed: expect[0] no_console_errors`
|
|
66
|
+
- `evidence_paths.console` — JSON dump of console messages
|
|
67
|
+
- `evidence_paths.har` — full HAR file
|
|
68
|
+
|
|
69
|
+
## Examples
|
|
70
|
+
|
|
71
|
+
### Smoke check — landing page
|
|
72
|
+
|
|
73
|
+
User: "Open https://app.example.com and confirm no errors fire."
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"open": { "platform": "web", "url": "https://app.example.com" },
|
|
78
|
+
"steps": [],
|
|
79
|
+
"expect": [
|
|
80
|
+
{ "kind": "no_console_errors" },
|
|
81
|
+
{ "kind": "no_failed_requests" }
|
|
82
|
+
],
|
|
83
|
+
"capture": ["screenshot", "console", "har"]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Drive a flow then assert clean
|
|
88
|
+
|
|
89
|
+
User: "Sign in then dashboard — make sure no console errors."
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"open": { "platform": "web", "url": "https://app.example.com/login" },
|
|
94
|
+
"steps": [
|
|
95
|
+
{ "kind": "fill_form", "fields": [
|
|
96
|
+
{ "query": "Email", "value": "test@example.com" },
|
|
97
|
+
{ "query": "Password", "value": "..." }
|
|
98
|
+
]},
|
|
99
|
+
{ "kind": "click", "query": "Sign in" },
|
|
100
|
+
{ "kind": "wait_for", "condition": { "kind": "url_matches", "pattern": "dashboard" } }
|
|
101
|
+
],
|
|
102
|
+
"expect": [
|
|
103
|
+
{ "kind": "no_console_errors", "exclude_patterns": ["sentry.io"] },
|
|
104
|
+
{ "kind": "no_failed_requests", "exclude_patterns": ["/analytics"] }
|
|
105
|
+
],
|
|
106
|
+
"capture": ["screenshot", "console", "har"]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## If the tool is unavailable
|
|
111
|
+
|
|
112
|
+
> The `/check-errors` skill needs the **rolepod-uiproof** MCP server,
|
|
113
|
+
> which is not currently available. Confirm the plugin is installed and
|
|
114
|
+
> try again, or check that `npx -y rolepod-uiproof` is reachable.
|
|
@@ -22,6 +22,20 @@ MCP server. No fallback (D-024).
|
|
|
22
22
|
- The scenario is too vague to scaffold — ask the user to clarify before
|
|
23
23
|
calling.
|
|
24
24
|
|
|
25
|
+
## Coverage
|
|
26
|
+
|
|
27
|
+
The codegen handles every step kind and expect kind supported by
|
|
28
|
+
`/verify-ui` (click, type, key, navigate, wait_for, hover, drag,
|
|
29
|
+
fill_form, upload, dialog, set_env, switch_page, evaluate; text_visible,
|
|
30
|
+
text_absent, url_matches, ref_in_state, no_console_errors,
|
|
31
|
+
no_failed_requests, request_made, response_status).
|
|
32
|
+
|
|
33
|
+
Playwright-test gets first-class translation for everything that has a
|
|
34
|
+
direct Playwright API. Pytest+selenium covers the basics; expect kinds
|
|
35
|
+
that need network introspection (no_failed_requests, request_made,
|
|
36
|
+
response_status) emit a TODO referencing `selenium-wire` or BiDi, since
|
|
37
|
+
upstream Selenium has no network-capture primitive.
|
|
38
|
+
|
|
25
39
|
## Inputs
|
|
26
40
|
|
|
27
41
|
- `framework` — `playwright-test` | `vitest+playwright` | `pytest+selenium`.
|
|
@@ -1,83 +1,116 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: verify-ui
|
|
3
|
-
description: Drive a real browser session through steps and assert expected outcomes
|
|
3
|
+
description: Drive a real browser session through steps and assert expected outcomes — including console errors, network failures, and visual state. Save evidence under ./.rolepod-uiproof/artifacts/. Web only.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /verify-ui
|
|
7
7
|
|
|
8
8
|
Single-backend skill. Calls **`rolepod_verify_ui_flow`** on the rolepod-uiproof
|
|
9
9
|
MCP server and surfaces the structured result. No fallback (D-024) — if the
|
|
10
|
-
tool is unavailable, this skill fails with a clear diagnostic
|
|
11
|
-
(typically the user, or the parent `rolepod` plugin's `check-work` skill)
|
|
12
|
-
can decide what to do next.
|
|
10
|
+
tool is unavailable, this skill fails with a clear diagnostic.
|
|
13
11
|
|
|
14
12
|
## When to use
|
|
15
13
|
|
|
16
14
|
- A diff changes user-visible behavior on a web target.
|
|
17
|
-
- A URL is reachable (dev server is running, or the target is
|
|
18
|
-
-
|
|
19
|
-
|
|
15
|
+
- A URL is reachable (dev server is running, or the target is deployed).
|
|
16
|
+
- You want to prove the UI works AND has no console errors / failed
|
|
17
|
+
requests / regressed visuals — code-level tests can't do that.
|
|
20
18
|
|
|
21
19
|
## When NOT to use
|
|
22
20
|
|
|
23
21
|
- Backend-only diffs (no UI change).
|
|
24
22
|
- Doc, config, or build-tool changes with no behavior surface.
|
|
25
|
-
- No dev server / target available — ask the user to spin one up first
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
- No dev server / target available — ask the user to spin one up first.
|
|
24
|
+
- iOS / Android targets — mobile is partially supported (basic input);
|
|
25
|
+
console / network / set_env / evaluate are web-only.
|
|
28
26
|
|
|
29
27
|
## Modes
|
|
30
28
|
|
|
31
|
-
- `mode: 'assert'` (default) —
|
|
29
|
+
- `mode: 'assert'` (default) — assertions describe what the **feature
|
|
32
30
|
should do**; pass = feature works.
|
|
33
|
-
- `mode: 'reproduce'` —
|
|
31
|
+
- `mode: 'reproduce'` — assertions describe what the **bug looks like**;
|
|
34
32
|
pass = bug reproduces. When `minimize: true` (default) the tool then
|
|
35
33
|
removes steps one-by-one to find the shortest still-reproducing sequence
|
|
36
|
-
and writes
|
|
34
|
+
and writes `replay-minimized.json` next to `replay.json`.
|
|
37
35
|
|
|
38
36
|
## Inputs
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- `
|
|
38
|
+
### `open` — context setup
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{ "platform": "web", "url": "https://...", "browser": "chromium" }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Optional: `viewport`, `headless`, `user_agent`, `locale`. UA / locale /
|
|
45
|
+
timezone MUST be set here — they cannot change mid-session.
|
|
46
|
+
|
|
47
|
+
### `steps` — UI actions in order
|
|
48
|
+
|
|
49
|
+
Each step is one of:
|
|
50
|
+
|
|
51
|
+
- `{ "kind": "click", "query": "Submit" }`
|
|
52
|
+
- `{ "kind": "type", "query": "Email", "text": "x@y.com", "clear_first": true }`
|
|
53
|
+
- `{ "kind": "key", "key": "Enter" }`
|
|
54
|
+
- `{ "kind": "wait_for", "condition": { ... } }`
|
|
55
|
+
- `{ "kind": "navigate", "url": "https://..." }`
|
|
56
|
+
- `{ "kind": "hover", "query": "More" }`
|
|
57
|
+
- `{ "kind": "drag", "from_query": "Card A", "to_query": "Column 2" }`
|
|
58
|
+
- `{ "kind": "fill_form", "fields": [ { "query": "Name", "value": "Alice" }, { "query": "Subscribe", "value": true, "kind": "checkbox" } ] }`
|
|
59
|
+
- `{ "kind": "upload", "query": "Avatar", "file_path": "/abs/path/to/file.png" }`
|
|
60
|
+
- `{ "kind": "dialog", "action": "accept" }` — **place BEFORE the action that triggers the dialog**
|
|
61
|
+
- `{ "kind": "set_env", "viewport": { "width": 375, "height": 812 } }` — also accepts offline, geolocation, color_scheme, reduced_motion, extra_headers, network_throttle, cpu_throttle
|
|
62
|
+
- `{ "kind": "switch_page", "index": 1 }` — multi-page (popups, target=_blank)
|
|
63
|
+
- `{ "kind": "evaluate", "script": "return document.title" }` — gated by `ROLEPOD_ALLOW_EVAL=1`
|
|
64
|
+
|
|
65
|
+
### `expect` — assertions
|
|
66
|
+
|
|
67
|
+
- `{ "kind": "text_visible", "text": "..." }`
|
|
68
|
+
- `{ "kind": "text_absent", "text": "..." }`
|
|
69
|
+
- `{ "kind": "url_matches", "pattern": "regex" }`
|
|
70
|
+
- `{ "kind": "ref_in_state", "query": "Submit", "state": "enabled" }`
|
|
71
|
+
- `{ "kind": "no_console_errors", "exclude_patterns": ["3rd-party.com"] }`
|
|
72
|
+
- `{ "kind": "no_failed_requests", "exclude_patterns": ["/analytics"], "allow_4xx": false }`
|
|
73
|
+
- `{ "kind": "request_made", "url_pattern": "/api/checkout", "method": "POST", "min_count": 1 }`
|
|
74
|
+
- `{ "kind": "response_status", "url_pattern": "/api/me", "status": 200 }`
|
|
75
|
+
|
|
76
|
+
### `capture` — evidence
|
|
77
|
+
|
|
78
|
+
Default: `["screenshot"]`. Available:
|
|
79
|
+
|
|
80
|
+
- `screenshot` — `final.png`
|
|
81
|
+
- `console` — `console.json` (filtered errors+warnings, ring buffer up to 1000)
|
|
82
|
+
- `har` — `network.har` (full HAR)
|
|
83
|
+
- `video` — `videos/*.webm`
|
|
84
|
+
- `trace` — `trace.zip` (Playwright trace; view with `npx playwright show-trace`)
|
|
85
|
+
- `a11y_tree` — `a11y_tree.json` (final snapshot)
|
|
86
|
+
|
|
87
|
+
### Defaults
|
|
88
|
+
|
|
89
|
+
- `close_on_finish: true`
|
|
90
|
+
- `minimize: true` (only consulted when `mode: 'reproduce'`)
|
|
56
91
|
|
|
57
92
|
## Outputs
|
|
58
93
|
|
|
59
|
-
- `run_id`
|
|
60
|
-
|
|
61
|
-
- `
|
|
62
|
-
- `
|
|
63
|
-
- `evidence_paths` — `{ screenshots: string[], replay_bundle?: string }`.
|
|
64
|
-
- `final_url_or_screen` — page URL at the end of the run.
|
|
94
|
+
- `run_id`, `passed`, `failed_at_step`, `failure_reason`,
|
|
95
|
+
`final_url_or_screen`
|
|
96
|
+
- `evidence_paths: { screenshots, replay_bundle, console?, a11y_tree?, har?, trace?, video? }`
|
|
97
|
+
- `minimized` (only on `mode: 'reproduce'` + `passed: true` + `minimize: true`)
|
|
65
98
|
|
|
66
99
|
## Process
|
|
67
100
|
|
|
68
|
-
1.
|
|
69
|
-
- `mode: 'assert'`
|
|
70
|
-
- `open: { platform: 'web', url: <target> }`
|
|
71
|
-
- `steps`, `expect`, `capture`, `close_on_finish` per inputs above.
|
|
101
|
+
1. Build the `rolepod_verify_ui_flow` input.
|
|
72
102
|
2. Call the tool.
|
|
73
|
-
3. Report the structured result.
|
|
74
|
-
`
|
|
75
|
-
|
|
103
|
+
3. Report the structured result. On failure include `failed_at_step` +
|
|
104
|
+
`failure_reason` + relevant evidence paths (screenshot, console.json
|
|
105
|
+
if console errors caused the failure).
|
|
76
106
|
|
|
77
|
-
##
|
|
107
|
+
## Default suggestion
|
|
108
|
+
|
|
109
|
+
For ANY user-visible flow, default-include `no_console_errors` and
|
|
110
|
+
`no_failed_requests` in `expect`. Real UI bugs surface as console errors
|
|
111
|
+
or 5xx responses far more often than as wrong text.
|
|
78
112
|
|
|
79
|
-
|
|
80
|
-
this plainly:
|
|
113
|
+
## If the tool is unavailable
|
|
81
114
|
|
|
82
115
|
> The `/verify-ui` skill needs the **rolepod-uiproof** MCP server, which is
|
|
83
116
|
> not currently available. Confirm the plugin is installed and try again,
|
|
@@ -85,50 +118,84 @@ this plainly:
|
|
|
85
118
|
|
|
86
119
|
Do **not** attempt this work via Playwright MCP, Chrome DevTools MCP, or
|
|
87
120
|
any other backend from inside this skill. Multi-backend routing is the
|
|
88
|
-
job of the parent `rolepod` plugin's `check-work` / `debug-issue` skills
|
|
89
|
-
(D-024).
|
|
121
|
+
job of the parent `rolepod` plugin's `check-work` / `debug-issue` skills.
|
|
90
122
|
|
|
91
123
|
## Examples
|
|
92
124
|
|
|
93
|
-
### Success — verify
|
|
94
|
-
|
|
95
|
-
User: "Verify that opening https://example.com shows the heading 'Example
|
|
96
|
-
Domain' and links to iana.org."
|
|
125
|
+
### Success — verify checkout flow with no errors
|
|
97
126
|
|
|
98
|
-
|
|
127
|
+
User: "Verify https://shop.example.com/checkout works — fill the form,
|
|
128
|
+
submit, expect a success page and no errors."
|
|
99
129
|
|
|
100
130
|
```json
|
|
101
131
|
{
|
|
102
132
|
"mode": "assert",
|
|
103
|
-
"open": { "platform": "web", "url": "https://example.com" },
|
|
104
|
-
"steps": [
|
|
133
|
+
"open": { "platform": "web", "url": "https://shop.example.com/checkout" },
|
|
134
|
+
"steps": [
|
|
135
|
+
{ "kind": "fill_form", "fields": [
|
|
136
|
+
{ "query": "Name", "value": "Alice" },
|
|
137
|
+
{ "query": "Email", "value": "alice@example.com" },
|
|
138
|
+
{ "query": "Card", "value": "4242 4242 4242 4242" }
|
|
139
|
+
]},
|
|
140
|
+
{ "kind": "click", "query": "Pay" },
|
|
141
|
+
{ "kind": "wait_for", "condition": { "kind": "text_visible", "text": "Thank you" } }
|
|
142
|
+
],
|
|
105
143
|
"expect": [
|
|
106
|
-
{ "kind": "text_visible", "text": "
|
|
107
|
-
{ "kind": "
|
|
108
|
-
|
|
144
|
+
{ "kind": "text_visible", "text": "Thank you" },
|
|
145
|
+
{ "kind": "no_console_errors" },
|
|
146
|
+
{ "kind": "no_failed_requests", "exclude_patterns": ["/analytics"] },
|
|
147
|
+
{ "kind": "response_status", "url_pattern": "/api/checkout", "status": 200 }
|
|
148
|
+
],
|
|
149
|
+
"capture": ["screenshot", "console", "har"]
|
|
109
150
|
}
|
|
110
151
|
```
|
|
111
152
|
|
|
112
|
-
|
|
153
|
+
### Failure with evidence
|
|
154
|
+
|
|
155
|
+
When `no_console_errors` fails, the result surfaces:
|
|
113
156
|
|
|
114
157
|
```json
|
|
115
158
|
{
|
|
116
|
-
"
|
|
117
|
-
"
|
|
159
|
+
"passed": false,
|
|
160
|
+
"failure_reason": "Expectations failed: expect[1] no_console_errors",
|
|
118
161
|
"evidence_paths": {
|
|
119
|
-
"screenshots": ["
|
|
120
|
-
"
|
|
121
|
-
}
|
|
122
|
-
"final_url_or_screen": "https://example.com/"
|
|
162
|
+
"screenshots": ["…/final.png"],
|
|
163
|
+
"console": "…/console.json"
|
|
164
|
+
}
|
|
123
165
|
}
|
|
124
166
|
```
|
|
125
167
|
|
|
126
|
-
|
|
168
|
+
Open `console.json` to inspect the errors.
|
|
127
169
|
|
|
128
|
-
|
|
170
|
+
### Dialog handling
|
|
129
171
|
|
|
130
|
-
|
|
131
|
-
|
|
172
|
+
User: "When the user clicks Delete, a confirm dialog appears. Verify
|
|
173
|
+
that accepting it deletes the row."
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"steps": [
|
|
178
|
+
{ "kind": "dialog", "action": "accept" },
|
|
179
|
+
{ "kind": "click", "query": "Delete" },
|
|
180
|
+
{ "kind": "wait_for", "condition": { "kind": "text_absent", "text": "Row A" } }
|
|
181
|
+
],
|
|
182
|
+
"expect": [ { "kind": "text_absent", "text": "Row A" } ]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The `dialog` step arms a one-shot handler; the *next* trigger (the click)
|
|
187
|
+
fires it. Un-armed dialogs are auto-dismissed.
|
|
188
|
+
|
|
189
|
+
### Responsive + dark mode
|
|
190
|
+
|
|
191
|
+
User: "Verify mobile dark-mode layout."
|
|
132
192
|
|
|
133
|
-
|
|
134
|
-
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"steps": [
|
|
196
|
+
{ "kind": "set_env", "viewport": { "width": 375, "height": 812 }, "color_scheme": "dark" }
|
|
197
|
+
],
|
|
198
|
+
"expect": [ { "kind": "text_visible", "text": "Menu" } ],
|
|
199
|
+
"capture": ["screenshot"]
|
|
200
|
+
}
|
|
201
|
+
```
|