Skip to content

Commit 4432c56

Browse files
merge upstream/main into feat/failure-triage; resolve conflicts
2 parents cd755ad + b9e9601 commit 4432c56

66 files changed

Lines changed: 7298 additions & 386 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,18 @@ jobs:
4848
- run: npm run typecheck
4949

5050
test:
51-
name: Unit Tests
51+
name: Unit Tests (Node ${{ matrix.node-version }})
5252
runs-on: ubuntu-latest
53+
strategy:
54+
matrix:
55+
node-version: [20, 22]
5356
steps:
5457
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
5558

5659
- name: Setup Node.js
5760
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
5861
with:
59-
node-version: 22
62+
node-version: ${{ matrix.node-version }}
6063
cache: 'npm'
6164

6265
- run: npm ci
@@ -66,15 +69,18 @@ jobs:
6669
CI: true
6770

6871
build:
69-
name: Build
72+
name: Build (Node ${{ matrix.node-version }})
7073
runs-on: ubuntu-latest
74+
strategy:
75+
matrix:
76+
node-version: [20, 22]
7177
steps:
7278
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
7379

7480
- name: Setup Node.js
7581
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
7682
with:
77-
node-version: 22
83+
node-version: ${{ matrix.node-version }}
7884
cache: 'npm'
7985

8086
- run: npm ci

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ All notable changes to `@testsprite/testsprite-cli` are documented here. The for
77
### Added
88

99
- **`test failure triage --project <id>`** — groups all failed tests in a project into root-cause clusters using existing M2.1 analysis fields (`failureKind`, `recommendedFixTarget.reference`, `rootCauseHypothesis`). Returns a representative test per cluster, affected test ids, confidence score, and fix priority — without downloading failure bundles. Supports `--type`, `--filter`, and `--max-concurrency`. Client-side Phase-0 triage until native backend clustering ships.
10+
- **JUnit XML report export for batch `--wait` runs.** `test run --all` and batch `test rerun` (`--all` or multiple test ids) accept `--report junit --report-file <path>` to write a CI-friendly XML sidecar after polling completes. `--output json` is unchanged; the report is written even when the batch exits non-zero. `--dry-run` writes a canned sample without network calls.
11+
- **`testsprite test flaky <test-id>`** — repeat-run flaky-test detector. Replays a test N times (`--runs <n>`, default 5), aggregates the outcomes, and reports a stability verdict (`stable` / `flaky` / `failing`) plus the `runId` and `failureKind` of every attempt that did not pass. Replays run with auto-heal OFF (strict verbatim) so a healed drift can't mask a nondeterministic pass/fail. Exit code is 0 only when every attempt passed, so CI can gate a merge on flakiness (`testsprite test flaky <id> --runs 5 || exit 1`). Flags: `--runs <n>` (1–10), `--until-fail` (stop at the first non-passing attempt), `--timeout <s>` (per-attempt), and `--output json` for a machine-readable stability report. Frontend replays are free verbatim script replays; a one-line advisory is printed for backend tests, whose closure reruns may cost credits.
1012

1113
## [0.2.0] - 2026-06-29
1214

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ the thread or in Discord is welcome.
3434

3535
## Prerequisites
3636

37-
- Node 20 or newer (development happens on Node 22).
37+
- Node 20.19+, Node 22.13+, or Node 24+ (development happens on Node 22).
3838

3939
## Build from source
4040

DOCUMENTATION.md

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Or run it without installing:
3535
npx @testsprite/testsprite-cli --version
3636
```
3737

38-
Requires **Node.js ≥ 20**.
38+
Requires **Node.js 20.19+**, **22.13+**, or **24+**.
3939

4040
Confirm the binary works **without** configuring an API key:
4141

@@ -112,15 +112,17 @@ testsprite agent install claude # install the skill for Claude Code
112112
testsprite agent install codex # install into AGENTS.md for Codex (managed-section)
113113
testsprite agent install cursor # .cursor/rules/testsprite-verify.mdc
114114
testsprite agent install cline # .clinerules/testsprite-verify.md
115+
testsprite agent install windsurf # .windsurf/rules/testsprite-verify.md
115116
testsprite agent install antigravity # .agents/skills/testsprite-verify/SKILL.md
116-
testsprite agent list # list all 5 targets with status + mode + path
117+
testsprite agent install kiro # .kiro/skills/testsprite-verify/SKILL.md
118+
testsprite agent list # list all 7 targets with status + mode + path
117119
```
118120

119-
Supported targets: `claude` (GA), `codex` (experimental), `cursor` (experimental), `cline` (experimental), `antigravity` (experimental).
121+
Supported targets: `claude` (GA), `codex` (experimental), `cursor` (experimental), `cline` (experimental), `antigravity` (experimental), `kiro` (experimental), `windsurf` (experimental).
120122

121123
The `codex` target uses **managed-section mode** — it writes only a sentinel-delimited section inside your existing `AGENTS.md`, so your project instructions are never clobbered. Re-running without `--force` replaces the section in-place; user content outside the sentinels is always preserved.
122124

123-
Re-running with `--force` on **own-file targets** (claude, cursor, cline, antigravity) backs up the existing file to `<path>.bak` first.
125+
Re-running with `--force` on **own-file targets** (claude, cursor, cline, antigravity, kiro, windsurf) backs up the existing file to `<path>.bak` first.
124126

125127
## Command reference
126128

@@ -344,10 +346,10 @@ testsprite test plan put test_xxxxxxxx --steps ./refined.plan.json --dry-run --o
344346

345347
#### `testsprite project create` / `project update`
346348

347-
Manage projects from the CLI. Both pre-flight `--target-url` against local addresses for fast feedback.
349+
Manage projects from the CLI. Both pre-flight `--url` against local addresses for fast feedback.
348350

349351
```bash
350-
testsprite project create --name "Checkout" --target-url https://staging.example.com
352+
testsprite project create --type frontend --name "Checkout" --url https://staging.example.com
351353
testsprite project update proj_xxxxxxxx --name "Checkout v2"
352354
```
353355

@@ -369,9 +371,19 @@ testsprite test run test_xxxxxxxx --target-url https://staging.example.com \
369371

370372
# Dry-run prints a canned queued response (no network, no credentials)
371373
testsprite test run test_xxxxxxxx --dry-run --output json
374+
375+
# Batch BE run with JUnit XML for CI (sidecar; --output json unchanged)
376+
testsprite test run --all --project proj_xxxxxxxx --wait \
377+
--report junit --report-file ./results.xml --output json
378+
379+
# Optional custom suite name (default: testsprite:<projectId>)
380+
testsprite test run --all --project proj_xxxxxxxx --wait \
381+
--report junit --report-file ./results.xml --report-suite-name my-ci-suite --output json
372382
```
373383

374-
`--target-url` must be a publicly reachable URL — the CLI pre-flights it against local addresses (`localhost`, `127.x`, `::1`, `0.0.0.0`, `169.254.x`, RFC1918) and the backend resolves it via DNS. For testing against localhost, use the [TestSprite MCP plugin](https://www.testsprite.com/docs), which handles the local tunnel. The CLI auto-mints an idempotency key (printed to stderr at `--verbose`); pass `--idempotency-key <uuid>` to control it explicitly.
384+
Batch `--report` flags apply only to `test run --all --wait` (and batch `test rerun --wait`). `--report junit --report-file <path>` writes a JUnit XML sidecar after polling completes (atomic write); `--output json` is unchanged. Optional `--report-suite-name <name>` overrides the default `testsprite:<projectId>` suite name.
385+
386+
`--target-url` must be a publicly reachable URL — the CLI pre-flights it against local addresses (`localhost`, `127.x`, `::1`, `0.0.0.0`, `169.254.x`, RFC1918) and the backend resolves it via DNS. For testing against localhost, use the [TestSprite MCP plugin](https://www.testsprite.com/docs), which handles the local tunnel. The CLI auto-mints an idempotency key (printed to stderr under `--output json`, `--verbose`, or `--debug`); pass `--idempotency-key <uuid>` to control it explicitly.
375387

376388
#### `testsprite test rerun [test-id...]`
377389

@@ -390,21 +402,55 @@ testsprite test rerun test_be_xxxx --skip-dependencies --output json
390402
# Rerun every test in a project (batch)
391403
testsprite test rerun --all --project proj_xxxxxxxx --wait --max-concurrency 4 --output json
392404

405+
# Batch rerun with JUnit XML for CI
406+
testsprite test rerun --all --project proj_xxxxxxxx --wait \
407+
--report junit --report-file ./results.xml --output json
408+
409+
# Optional custom suite name (default: testsprite:<projectId>)
410+
testsprite test rerun --all --project proj_xxxxxxxx --wait \
411+
--report junit --report-file ./results.xml --report-suite-name my-ci-suite --output json
412+
393413
# Several specific tests
394414
testsprite test rerun test_aaaa test_bbbb --wait --output json
395415
```
396416

417+
Batch `--report` flags apply only to batch `--wait` reruns (`--all` or multiple test ids). `--report junit --report-file <path>` writes a JUnit XML sidecar after polling completes (atomic write); `--output json` is unchanged. When `--project` is omitted, the CLI infers `projectId` from polled run rows for classname / default suite naming; if inference fails, pass `--project <id>` explicitly (required under `--dry-run`).
418+
397419
Flags:
398420

399421
- `--all` — rerun every test in the resolved project; requires `--project <id>`.
400422
- `--wait`, `--timeout <s>` — block until terminal; same exit matrix as `test run --wait`.
401423
- `--auto-heal` / `--no-auto-heal` — frontend AI heal-on-drift, **on by default** for FE reruns; opt out with `--no-auto-heal`. Verbatim-replay passes are free; a heal engage costs a small amount of credit. Ignored for backend tests.
402424
- `--skip-dependencies` — backend only: rerun just the named test without expanding the producer/teardown closure.
403425
- `--max-concurrency <n>` — with `--wait`, cap on in-flight polls during a batch rerun.
404-
- `--idempotency-key <key>` — auto-minted when omitted.
426+
- `--idempotency-key <key>` — auto-minted when omitted (the minted key is printed to stderr under `--output json`, `--verbose`, or `--debug`).
427+
- `--report junit --report-file <path>` — with batch `--wait`, write a JUnit XML sidecar after polling (atomic write). Optional `--report-suite-name <name>` overrides the default `testsprite:<projectId>` suite name. Requires `--wait`; not available on single-test reruns.
405428

406429
A batch rerun returns `accepted[]` (one `runId` per dispatched test) plus `deferred[]` for any test shed by the per-key run-rate limit; under `--wait`, a non-empty `deferred[]` exits 7 with a `nextAction` you can retry with a fresh idempotency key.
407430

431+
#### `testsprite test flaky <test-id>`
432+
433+
Detect a **flaky** test by replaying it several times and reporting how often it passes. Each attempt is a rerun with auto-heal **off** (a strict verbatim replay), so healed drift can't disguise a nondeterministic pass/fail — this measures the replay stability of the saved script against the configured URL. Frontend replays are free verbatim script replays; backend tests re-run their dependency closure and may cost credits (a one-line stderr advisory is printed before the run).
434+
435+
```bash
436+
# Replay 10 times and print a stability score
437+
testsprite test flaky test_xxxxxxxx --runs 10
438+
439+
# Fast "is it flaky at all?" — stop at the first non-passing attempt
440+
testsprite test flaky test_xxxxxxxx --runs 10 --until-fail
441+
442+
# Machine-readable stability report for CI
443+
testsprite test flaky test_xxxxxxxx --runs 10 --output json
444+
```
445+
446+
Flags:
447+
448+
- `--runs <n>` — number of replays (1–10, default 5).
449+
- `--until-fail` — stop at the first attempt that does not pass.
450+
- `--timeout <s>` — per-attempt polling deadline (same semantics as `test wait`).
451+
452+
`--output json` emits `{ testId, runs, passed, failed, stableRatio, verdict, failures: [{ attempt, runId, outcome, failureKind }] }`. Exit codes: **0** when every observed attempt passed (`stable`); **1** when any attempt did not pass (`flaky` or `failing`); **4** when the test has no replayable run (trigger `testsprite test run <id>` first); **5** on a validation error.
453+
408454
#### `testsprite test wait <run-id>`
409455

410456
Block until a run reaches a terminal status. Same exit-code matrix as `test run --wait`. Used to resume polling after a timed-out `test run --wait`, or when an agent already has a `runId` from a previous invocation.
@@ -451,12 +497,25 @@ These apply to every command:
451497

452498
### Environment variables
453499

454-
| Variable | Purpose |
455-
| ------------------------------- | --------------------------------------------------------------------------------- |
456-
| `TESTSPRITE_API_KEY` | API key — overrides the credentials file |
457-
| `TESTSPRITE_API_URL` | API endpoint — overrides the credentials file |
458-
| `TESTSPRITE_PROFILE` | Active profile (below `--profile`, above `default`) |
459-
| `TESTSPRITE_REQUEST_TIMEOUT_MS` | Per-request timeout in **milliseconds** (default `120000`, range `1000``600000`) |
500+
| Variable | Purpose |
501+
| ------------------------------- | --------------------------------------------------------------------------------------- |
502+
| `TESTSPRITE_API_KEY` | API key — overrides the credentials file |
503+
| `TESTSPRITE_API_URL` | API endpoint — overrides the credentials file |
504+
| `TESTSPRITE_PROFILE` | Active profile (below `--profile`, above `default`) |
505+
| `TESTSPRITE_REQUEST_TIMEOUT_MS` | Per-request timeout in **milliseconds** (default `120000`, range `1000``600000`) |
506+
| `TESTSPRITE_NO_UPDATE_NOTIFIER` | Any non-empty value disables the once-per-24h "new version available" notice |
507+
| `NO_COLOR` | Suppress ANSI escape sequences in ticker output ([no-color.org](https://no-color.org/)) |
508+
509+
### Update notice
510+
511+
Interactive runs print a one-line "new version available" notice on stderr when
512+
a newer release exists. To learn this, the CLI contacts the public npm registry
513+
(`registry.npmjs.org`) at most once per 24 hours; the request carries the
514+
package name only — never your API key, project data, or command line. The
515+
check is skipped in CI, when stderr is not a TTY, under `--output json` /
516+
`--dry-run`, and entirely when `TESTSPRITE_NO_UPDATE_NOTIFIER` is set. Any
517+
failure is silent: the notice can never break or delay a command. This is the
518+
only outbound call the CLI makes besides your configured API endpoint.
460519

461520
### Scopes
462521

0 commit comments

Comments
 (0)