ccqa 0.13.0 → 1.0.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/README.md +91 -140
- package/dist/bin/ccqa.mjs +7196 -3713
- package/dist/hub-client/index.d.mts +341 -6
- package/dist/hub-client/index.mjs +14 -0
- package/dist/package.json +1 -1
- package/dist/runtime/test-helpers.mjs +1 -1
- package/dist/{spawn-ab-Ja8NRRab.mjs → spawn-ab-Cr967J2N.mjs} +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
**Your Claude subscription already includes a QA engineer.**
|
|
4
4
|
|
|
5
|
-
ccqa turns Claude Code into a browser test recorder
|
|
5
|
+
ccqa turns Claude Code into a browser test recorder and runner:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
1. Write a test spec in YAML — plain steps and expected results.
|
|
8
|
+
2. Claude drives a real browser **once** to discover the route
|
|
9
|
+
(`ccqa record`).
|
|
10
|
+
3. ccqa compiles the recording into runnable test code for your `target:`
|
|
11
|
+
— vitest replay, plain Playwright, or a runn runbook.
|
|
12
|
+
4. `ccqa run` replays everything into one report you can push to a
|
|
13
|
+
shared hub.
|
|
9
14
|
|
|
10
15
|
No extra API key. Just `claude`.
|
|
11
16
|
|
|
@@ -13,15 +18,48 @@ No extra API key. Just `claude`.
|
|
|
13
18
|
|
|
14
19
|
## How it works
|
|
15
20
|
|
|
16
|
-
Each spec picks its own mode; `ccqa run` reads the field and dispatches. One project mixes both, and one report covers both.
|
|
17
|
-
|
|
18
|
-
```mermaid
|
|
19
|
-
flowchart LR
|
|
20
|
-
A["Write spec\n(spec.yaml + mode:)"] --> B{mode}
|
|
21
|
-
B -- deterministic --> C["ccqa record\n(Claude → test.spec.ts)"]
|
|
22
|
-
C --> D["ccqa run\n(vitest replay, no LLM)"]
|
|
23
|
-
B -- live --> E["ccqa run\n(Claude drives every time,\nper-step pass/fail)"]
|
|
24
21
|
```
|
|
22
|
+
spec.yaml ──► ccqa record ─────► ir.json ────► ccqa generate ──► test code
|
|
23
|
+
steps + Claude drives recorded per-target agent-browser
|
|
24
|
+
expected the browser and actions as emit / playwright
|
|
25
|
+
results discovers the tool-neutral (reuse-first) / runn
|
|
26
|
+
route IR
|
|
27
|
+
|
|
28
|
+
test code ──► ccqa run ────────► report.json ─► ccqa hub push /
|
|
29
|
+
vitest replay / + evidence --push-report
|
|
30
|
+
runCommand / + artifacts team dashboard,
|
|
31
|
+
live (Claude failure triage,
|
|
32
|
+
drives per step) grading & learning
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
A spec runs in one of two ways:
|
|
36
|
+
|
|
37
|
+
**Deterministic (the default).** Claude drives the browser once
|
|
38
|
+
(`ccqa record`), and the recording is compiled into plain test code. From
|
|
39
|
+
then on, CI just replays that code — no LLM at run time, cheapest and most
|
|
40
|
+
stable. The `target:` field picks only **what the recording compiles
|
|
41
|
+
into**; every target is the same deterministic replay:
|
|
42
|
+
|
|
43
|
+
| `target:` | Generated file | Replayed by |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `agent-browser` (default) | `test.spec.ts` (vitest + agent-browser) | vitest |
|
|
46
|
+
| `playwright` | `test.spec.ts` (plain `@playwright/test`) | your `runCommand` |
|
|
47
|
+
| `runn` | `runbook.yaml` (API scenario — compiled from the spec, no recording) | your `runCommand` |
|
|
48
|
+
|
|
49
|
+
`runCommand` is the one-line command your repo already uses to run that
|
|
50
|
+
tool, declared once in `.ccqa/config.yaml` — e.g.
|
|
51
|
+
`pnpm exec playwright test {files}`. ccqa substitutes the spec's generated
|
|
52
|
+
test files for `{files}` and a per-spec artifacts directory for
|
|
53
|
+
`{artifactsDir}`; see [Generation targets](./docs/targets.md) for the full
|
|
54
|
+
contract.
|
|
55
|
+
|
|
56
|
+
**Live (`mode: live`).** No codegen: Claude drives every run and judges
|
|
57
|
+
each step's `expected` — for fragile, timing-heavy UIs where a fixed
|
|
58
|
+
recording would break.
|
|
59
|
+
|
|
60
|
+
Either way, every failing spec gets a root-cause call (TEST_DRIFT /
|
|
61
|
+
SPEC_CHANGE / PRODUCT_BUG) you can grade on the hub — and the hub learns
|
|
62
|
+
from your grades.
|
|
25
63
|
|
|
26
64
|
## Install
|
|
27
65
|
|
|
@@ -29,16 +67,19 @@ flowchart LR
|
|
|
29
67
|
pnpm add -D ccqa vitest agent-browser
|
|
30
68
|
```
|
|
31
69
|
|
|
32
|
-
Requires Node.js **20+**.
|
|
70
|
+
Requires Node.js **20+**.
|
|
71
|
+
[agent-browser](https://github.com/vercel-labs/agent-browser) and
|
|
72
|
+
[vitest](https://vitest.dev) are peer dependencies.
|
|
33
73
|
|
|
34
74
|
## Quick start
|
|
35
75
|
|
|
36
|
-
**1. Write a spec** — by hand, or interactively with
|
|
76
|
+
**1. Write a spec** — by hand, or interactively with
|
|
77
|
+
[`ccqa draft`](./docs/draft.md). (`ccqa init` scaffolds the `.ccqa/`
|
|
78
|
+
skeleton.)
|
|
37
79
|
|
|
38
80
|
```yaml
|
|
39
81
|
# .ccqa/features/tasks/test-cases/create-and-complete/spec.yaml
|
|
40
82
|
title: Create a task and mark it complete
|
|
41
|
-
mode: deterministic # or: live. Omit for deterministic (the default).
|
|
42
83
|
|
|
43
84
|
steps:
|
|
44
85
|
- instruction: |
|
|
@@ -46,151 +87,61 @@ steps:
|
|
|
46
87
|
expected: Redirected to /dashboard, user avatar visible in the header
|
|
47
88
|
|
|
48
89
|
- instruction: |
|
|
49
|
-
Click "New Task", fill in the title "Fix login bug",
|
|
90
|
+
Click "New Task", fill in the title "Fix login bug", save.
|
|
50
91
|
expected: Task appears in the task list with status "Open"
|
|
51
92
|
```
|
|
52
93
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
**2a. For `mode: deterministic` — record once, then replay**
|
|
94
|
+
**2. Record once** — Claude drives the browser and generates the test:
|
|
56
95
|
|
|
57
96
|
```bash
|
|
58
|
-
ccqa record tasks/create-and-complete
|
|
59
|
-
ccqa run tasks/create-and-complete # vitest replays test.spec.ts; no LLM
|
|
97
|
+
ccqa record tasks/create-and-complete
|
|
60
98
|
```
|
|
61
99
|
|
|
62
|
-
**
|
|
100
|
+
**3. Run it** — vitest replays the recording; no LLM involved:
|
|
63
101
|
|
|
64
102
|
```bash
|
|
65
|
-
ccqa run tasks/create-and-complete
|
|
103
|
+
ccqa run tasks/create-and-complete
|
|
66
104
|
```
|
|
67
105
|
|
|
68
|
-
|
|
106
|
+
A `report.json` (+ step screenshots) is always written to `ccqa-report/`.
|
|
107
|
+
See [Running specs](./docs/running.md) for flags, CI recipes, and the
|
|
108
|
+
report format.
|
|
69
109
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
ccqa run tasks/create-and-complete --report --base origin/main
|
|
74
|
-
ccqa run --changed --report # only specs whose relatedPaths touch the diff
|
|
75
|
-
```
|
|
110
|
+
**4. Optional: share results on a hub** — `ccqa serve` starts a small
|
|
111
|
+
self-hosted server (or use the bundled `docker-compose.yaml`). Pushing
|
|
112
|
+
reports to it gives your team:
|
|
76
113
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| Run specs live (no codegen), with per-project guidance | [Live specs](./docs/live.md) |
|
|
83
|
-
| Restore a saved login to skip device-trust gates | [Saved sessions](./docs/sessions.md) |
|
|
84
|
-
| Reuse login and other shared step sequences | [Blocks](./docs/blocks.md) |
|
|
85
|
-
| Drive `<input type="file">` without an OS picker | [File upload](./docs/file-upload.md) |
|
|
86
|
-
| Assertion helper functions | [Assertions](./docs/assertions.md) |
|
|
87
|
-
| Auto-fix failing tests | [Auto-fix](./docs/auto-fix.md) |
|
|
88
|
-
| Detect spec/code drift in CI | [Drift](./docs/drift.md) |
|
|
89
|
-
| HTML run report with failure root-cause calls | [Run report](./docs/report.md) |
|
|
90
|
-
| Inventory existing test coverage | [Perspectives](./docs/perspectives.md) |
|
|
91
|
-
| Architecture decision records (why it is built this way) | [ADR](./docs/adr/README.md) |
|
|
92
|
-
| Aggregate CI run results, sessions, and variables on a shared server | [Hub](./docs/hub.md) |
|
|
93
|
-
|
|
94
|
-
## Commands
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
ccqa init Scaffold .ccqa/prompts/{live,record}.{user,agent}.md templates
|
|
98
|
-
ccqa draft [feature/spec] Co-author a test spec with Claude
|
|
99
|
-
ccqa perspectives Inventory existing test coverage into .ccqa/perspectives.yaml
|
|
100
|
-
ccqa record <feature/spec> (deterministic specs only) Trace browser actions + generate test.spec.ts
|
|
101
|
-
ccqa run [feature/spec...] Execute specs. Per spec, the spec.yaml `mode:` field selects deterministic
|
|
102
|
-
(vitest replay) or live (Claude drives every time). One run can mix both;
|
|
103
|
-
`--report` writes one unified HTML. Pass multiple targets space-separated.
|
|
104
|
-
ccqa drift [feature/spec] Standalone spec ↔ codebase static audit (for PR checks)
|
|
105
|
-
ccqa serve Start a hub: a control-plane HTTP server that aggregates run results,
|
|
106
|
-
sessions, and variables (it does not execute tests)
|
|
107
|
-
ccqa hub push Push a finished run's report to a hub
|
|
108
|
-
ccqa hub session|var <cmd> Manage sessions/variables stored on a hub
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Key `ccqa run` flags (see `ccqa run --help` for the rest):
|
|
112
|
-
|
|
113
|
-
- `--report [dir]` — write the run report (report.json + evidence PNGs) for `ccqa hub push` (default dir: `ccqa-report/`)
|
|
114
|
-
- `--profile <name>` — load `.ccqa/profiles/<name>.env` before resolving spec `${VAR}` references, so one spec targets dev/stg/prd. See [Profiles](#profiles---profile).
|
|
115
|
-
- `--changed` — restrict execution to specs whose `relatedPaths` intersect `git diff <base>...HEAD`
|
|
116
|
-
- `--concurrency <n>` — run up to N specs in parallel **within each mode** (deterministic phase, then live phase — parallelism is per-phase, not across phases). Default `1` (sequential, same behavior as before).
|
|
117
|
-
- `--no-failure-analysis` / `--no-drift-audit` — `--no-failure-analysis` skips failure classification (and its drift audit, since drift is the classification's evidence); `--no-drift-audit` keeps classification but skips just the audit.
|
|
118
|
-
- `--format <fmt>` — `text` (default), `json` (report.json), `github` (Actions annotations)
|
|
119
|
-
|
|
120
|
-
`<feature/spec>` is a 2-segment alias for `.ccqa/features/<feature>/test-cases/<spec>/`; `ccqa run` takes several space-separated targets (a `<feature>/<spec>`, a bare `<feature>`, or none for everything). Claude-driven commands accept `-m/--model`, `--language`, and `--cwd` (for monorepos); they use your local Claude login, and CI commands (`ccqa run --report`, `ccqa drift`) also honor `ANTHROPIC_API_KEY`.
|
|
121
|
-
|
|
122
|
-
## File structure
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
.ccqa/
|
|
126
|
-
perspectives.yaml # Inventory of existing coverage (canonical)
|
|
127
|
-
profiles/ # `--profile <name>` env files (stg.env, prd.env, ...)
|
|
128
|
-
prompts/ # `ccqa init` scaffolds these; *.user.md human-maintained, *.agent.md auto-updated
|
|
129
|
-
record.user.md record.agent.md live.user.md live.agent.md
|
|
130
|
-
blocks/
|
|
131
|
-
login/spec.yaml # Reusable block (params + steps)
|
|
132
|
-
features/
|
|
133
|
-
tasks/
|
|
134
|
-
test-cases/
|
|
135
|
-
create-and-complete/
|
|
136
|
-
spec.yaml # Test definition, with `mode: deterministic | live`
|
|
137
|
-
actions.json # (deterministic) recorded actions
|
|
138
|
-
test.spec.ts # (deterministic) generated vitest script
|
|
139
|
-
runs/<timestamp>/ # (live) one `ccqa run` — run.json/run.md + steps/*.png
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Gitignore the per-run artefacts: `.ccqa/features/*/test-cases/*/runs/` and `ccqa-report*/`.
|
|
143
|
-
|
|
144
|
-
## Profiles (`--profile`)
|
|
145
|
-
|
|
146
|
-
Keep environment-specific values out of specs as `${VAR}` references and supply them per environment from a **profile** — a `.env` under `.ccqa/profiles/<name>.env`. `ccqa run`/`record --profile <name>` merges it into the environment before resolving `${VAR}`, so one spec runs anywhere.
|
|
114
|
+
- a dashboard of runs, with per-step screenshots
|
|
115
|
+
- triage grading — mark each failure call right or wrong; the hub learns
|
|
116
|
+
from the grades
|
|
117
|
+
- one place for shared sessions, variables, and learned prompts — CI
|
|
118
|
+
needs a single secret
|
|
147
119
|
|
|
148
120
|
```bash
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
```bash
|
|
155
|
-
ccqa run auth/login --profile stg # same spec, stg values
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
- Format is a small `.env` subset (`KEY=value`, `#` comments, `export`, quotes); profile values **override** the inherited environment.
|
|
159
|
-
- Name is free-form (`stg`/`prd` by convention); path separators, `..`, and leading dots are rejected, and an unknown name exits 2. Only the name is logged, never values.
|
|
160
|
-
- Without `--profile`, ccqa auto-loads `<cwd>/.env` if present; with neither, `${VAR}` resolves against the existing `process.env`.
|
|
161
|
-
- **Secrets:** gitignore any profile holding plaintext secrets. To keep secrets off disk entirely, drop `--profile` and run ccqa under your secret manager (e.g. `op run --env-file=... -- ccqa run ...`), which injects resolved values into `process.env`.
|
|
162
|
-
|
|
163
|
-
## Live specs (`mode: live`)
|
|
164
|
-
|
|
165
|
-
For specs declared `mode: live` in their spec.yaml, `ccqa run` skips codegen entirely: Claude executes each spec step against `agent-browser` directly, judges whether the step's `expected` outcome holds, and saves a PNG screenshot before and after every step. Use this mode when:
|
|
166
|
-
|
|
167
|
-
- you want to validate a spec but don't yet need a replayable, recorded test
|
|
168
|
-
- the codegen output for a spec is fragile (heavily timing-dependent UIs, rich-text editors, dynamic selectors)
|
|
169
|
-
- you want a visual audit trail of what the page looked like at every step
|
|
170
|
-
|
|
171
|
-
Constraints on selectors / `agent-browser` subcommands that apply during `ccqa record` (no `eval`, no `@ref`, no bare-tag positional `find`, no chained agent-browser calls) are relaxed for live specs, since there is no replay contract to honour.
|
|
172
|
-
|
|
173
|
-
See [Live specs](./docs/live.md) for usage examples and per-project guidance.
|
|
174
|
-
|
|
175
|
-
### Saved sessions (`session:`)
|
|
176
|
-
|
|
177
|
-
Some providers gate every fresh browser with a device-trust check (an "unrecognized device" e-mail code, an MFA prompt) that a human has to clear by hand — impractical to repeat on every run, impossible in CI. `session:` restores a saved, signed-in browser state instead.
|
|
178
|
-
|
|
179
|
-
```yaml
|
|
180
|
-
title: Admin can open the settings page
|
|
181
|
-
mode: live
|
|
182
|
-
session: admin # restore the saved "admin" session before step 1
|
|
183
|
-
steps:
|
|
184
|
-
- ... # no login steps — the spec starts signed-in
|
|
121
|
+
export CCQA_HUB_TOKEN=$(openssl rand -hex 24)
|
|
122
|
+
ccqa serve # or: docker compose up -d
|
|
123
|
+
ccqa run tasks/create-and-complete --push-report \
|
|
124
|
+
--hub-url http://localhost:8787 --hub-token $CCQA_HUB_TOKEN
|
|
185
125
|
```
|
|
186
126
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
See [Saved sessions](./docs/sessions.md) for how to bootstrap a session and use it in CI.
|
|
127
|
+
See [Hub](./docs/hub.md) for the full setup (encryption, container
|
|
128
|
+
deployment, HTTP API).
|
|
190
129
|
|
|
191
|
-
##
|
|
130
|
+
## Documentation
|
|
192
131
|
|
|
193
|
-
|
|
132
|
+
| I want to… | Read |
|
|
133
|
+
|---|---|
|
|
134
|
+
| Write specs: fields, reusable blocks, file uploads, coverage inventory | [spec.yaml reference](./docs/spec.md) |
|
|
135
|
+
| Draft specs interactively with Claude | [Draft](./docs/draft.md) |
|
|
136
|
+
| Generate Playwright or runn tests that reuse my existing test code | [Generation targets](./docs/targets.md) |
|
|
137
|
+
| Run specs, read reports, triage failures, detect drift, wire up CI | [Running specs](./docs/running.md) |
|
|
138
|
+
| Run specs live (no codegen), with per-project guidance | [Live specs](./docs/live.md) |
|
|
139
|
+
| Start runs already signed in / skip device-trust gates | [Saved sessions](./docs/sessions.md) |
|
|
140
|
+
| See which assertions generated tests use | [Assertions](./docs/assertions.md) |
|
|
141
|
+
| Auto-fix failing recorded tests | [Auto-fix](./docs/auto-fix.md) |
|
|
142
|
+
| Aggregate results, sessions, and variables on a team server | [Hub](./docs/hub.md) |
|
|
143
|
+
| Script the hub over HTTP | [Hub API](./docs/hub-api.md) |
|
|
144
|
+
| Understand why ccqa is built this way | [ADR](./docs/adr/README.md) |
|
|
194
145
|
|
|
195
146
|
## License
|
|
196
147
|
|