Skip to content

Commit eb2bd3e

Browse files
authored
Merge branch 'TestSprite:main' into chore/security-ci-pipeline
2 parents 7d4cf44 + 3305dfa commit eb2bd3e

27 files changed

Lines changed: 1988 additions & 858 deletions

.github/workflows/test-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
fi
7474
7575
- name: Add Coverage PR Comment
76-
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
76+
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
7777
if: github.event_name == 'pull_request' && steps.coverage-summary.outputs.coverage_generated == 'true'
7878
with:
7979
recreate: true

DOCUMENTATION.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,15 @@ testsprite agent install cline # .clinerules/testsprite-verify.md
115115
testsprite agent install windsurf # .windsurf/rules/testsprite-verify.md
116116
testsprite agent install antigravity # .agents/skills/testsprite-verify/SKILL.md
117117
testsprite agent install kiro # .kiro/skills/testsprite-verify/SKILL.md
118-
testsprite agent list # list all 7 targets with status + mode + path
118+
testsprite agent install copilot # .github/instructions/testsprite-verify.instructions.md
119+
testsprite agent list # list all 8 targets with status + mode + path
119120
```
120121

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

123124
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.
124125

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

127128
## Command reference
128129

README.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,28 +89,28 @@ Prefer to configure each step by hand (or learn the surface offline with `--dry-
8989

9090
## Commands
9191

92-
| Group | Command | What it does |
93-
| --------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
94-
| **Setup** | `setup` | **Start here** — one command: configure your API key, verify it, and install the agent verification skill |
95-
| **Auth** | `auth status` | Resolve the active profile to its user, key, env, and scopes |
96-
| | `auth remove` | Remove the active profile from the credentials file |
97-
| **Read** | `project list` / `project get` | List projects / fetch one by id |
98-
| | `test list` / `test get` | List tests under a project / fetch one by id |
99-
| | `test code get` | Print (or write) the generated test source |
100-
| | `test steps` | List the latest run's steps with screenshot / DOM pointers |
101-
| | `test result` | Latest result; `--history` lists a test's prior runs |
102-
| | `test failure get` | The agent entry point: one self-contained latest-failure bundle |
103-
| | `test failure summary` | One-screen triage card (no media download) |
104-
| **Write** | `test create` / `test create-batch` | Create a test (or bulk-create from a plan file); `--produces` / `--needs` / `--category` wire BE dependency metadata |
105-
| | `test update` / `test delete` / `test delete-batch` | Edit metadata / soft-delete |
106-
| | `test code put` | Replace generated code (etag-guarded) |
107-
| | `test plan put` | Replace a frontend test's plan-steps |
108-
| | `project create` / `project update` | Manage projects |
109-
| **Run** | `test run` | Trigger a fresh run; `--wait` blocks until terminal; `--all --project <id>` runs all tests in a project in wave order |
110-
| | `test rerun` | Cheap replay of one/many tests (FE verbatim; BE with deps); `--all --project <id>` reruns all tests |
111-
| | `test wait` | Block on a `runId` until terminal |
112-
| | `test artifact get` | Download the failure bundle for a specific `runId` |
113-
| **Agent** | `agent install` / `agent list` | Add or list coding-agent targets (pure-local): `claude`, `codex`, `cursor`, `cline`, `antigravity`, `kiro`, `windsurf` |
92+
| Group | Command | What it does |
93+
| --------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
94+
| **Setup** | `setup` | **Start here** — one command: configure your API key, verify it, and install the agent verification skill |
95+
| **Auth** | `auth status` | Resolve the active profile to its user, key, env, and scopes |
96+
| | `auth remove` | Remove the active profile from the credentials file |
97+
| **Read** | `project list` / `project get` | List projects / fetch one by id |
98+
| | `test list` / `test get` | List tests under a project / fetch one by id |
99+
| | `test code get` | Print (or write) the generated test source |
100+
| | `test steps` | List the latest run's steps with screenshot / DOM pointers |
101+
| | `test result` | Latest result; `--history` lists a test's prior runs |
102+
| | `test failure get` | The agent entry point: one self-contained latest-failure bundle |
103+
| | `test failure summary` | One-screen triage card (no media download) |
104+
| **Write** | `test create` / `test create-batch` | Create a test (or bulk-create from a plan file); `--produces` / `--needs` / `--category` wire BE dependency metadata |
105+
| | `test update` / `test delete` / `test delete-batch` | Edit metadata / soft-delete |
106+
| | `test code put` | Replace generated code (etag-guarded) |
107+
| | `test plan put` | Replace a frontend test's plan-steps |
108+
| | `project create` / `project update` | Manage projects |
109+
| **Run** | `test run` | Trigger a fresh run; `--wait` blocks until terminal; `--all --project <id>` runs all tests in a project in wave order |
110+
| | `test rerun` | Cheap replay of one/many tests (FE verbatim; BE with deps); `--all --project <id>` reruns all tests |
111+
| | `test wait` | Block on a `runId` until terminal |
112+
| | `test artifact get` | Download the failure bundle for a specific `runId` |
113+
| **Agent** | `agent install` / `agent list` | Add or list coding-agent targets (pure-local): `claude`, `codex`, `cursor`, `cline`, `antigravity`, `kiro`, `windsurf`, `copilot` |
114114

115115
> The earlier command names — `init`, `auth configure`, `auth whoami`, `auth logout` — still work as hidden, deprecated aliases (each prints a one-line notice pointing at the new name), so existing scripts keep running. `auth configure` now runs the full `setup` (it also installs the skill).
116116

src/commands/agent.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -769,13 +769,14 @@ describe('runList', () => {
769769

770770
const json = JSON.parse(capture.stdout.join('\n')) as ListResult[];
771771
expect(Array.isArray(json)).toBe(true);
772-
// 7 targets × 2 default skills = 14 rows
773-
expect(json).toHaveLength(14);
772+
// 8 targets × 2 default skills = 16 rows
773+
expect(json).toHaveLength(16);
774774
const targets = json.map(r => r.target);
775775
expect(targets).toContain('claude');
776776
expect(targets).toContain('cursor');
777777
expect(targets).toContain('cline');
778778
expect(targets).toContain('windsurf');
779+
expect(targets).toContain('copilot');
779780
expect(targets).toContain('antigravity');
780781
expect(targets).toContain('kiro');
781782
expect(targets).toContain('codex');
@@ -949,11 +950,11 @@ describe('runInstall — all own-file targets', () => {
949950
});
950951

951952
// ---------------------------------------------------------------------------
952-
// Dry-run for all six own-file targets
953+
// Dry-run for all seven own-file targets
953954
// ---------------------------------------------------------------------------
954955

955956
describe('runInstall — dry-run all own-file targets', () => {
956-
it('writes nothing for any of the six own-file targets (default 2 skills = 12 would-write lines)', async () => {
957+
it('writes nothing for any of the seven own-file targets (default 2 skills = 14 would-write lines)', async () => {
957958
const { store, fs: agentFs } = makeMemFs();
958959
const { capture, deps } = makeCapture();
959960

@@ -963,7 +964,7 @@ describe('runInstall — dry-run all own-file targets', () => {
963964
output: 'text',
964965
debug: false,
965966
dryRun: true,
966-
target: ['claude', 'cursor', 'cline', 'antigravity', 'kiro', 'windsurf'],
967+
target: ['claude', 'cursor', 'cline', 'antigravity', 'kiro', 'windsurf', 'copilot'],
967968
force: false,
968969
},
969970
{ cwd: CWD, fs: agentFs, ...deps },
@@ -973,9 +974,9 @@ describe('runInstall — dry-run all own-file targets', () => {
973974
const stderrOut = capture.stderr.join('\n');
974975
// Banner appears once
975976
expect(stderrOut).toContain('[dry-run] no files written');
976-
// 6 targets × 2 default skills = 12 would-write lines
977+
// 7 targets × 2 default skills = 14 would-write lines
977978
const wouldWriteLines = stderrOut.split('\n').filter(l => l.includes('would write'));
978-
expect(wouldWriteLines.length).toBe(12);
979+
expect(wouldWriteLines.length).toBe(14);
979980
});
980981
});
981982

src/commands/agent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ function collect(v: string, prev: string[]): string[] {
10611061

10621062
export function createAgentCommand(deps: AgentDeps = {}): Command {
10631063
const agent = new Command('agent').description(
1064-
'Install TestSprite guidance into coding-agent config (Claude Code, Cursor, Cline, Windsurf, Antigravity, Codex)',
1064+
'Install TestSprite guidance into coding-agent config (Claude Code, Cursor, Cline, Antigravity, Kiro, Windsurf, Copilot, Codex)',
10651065
);
10661066

10671067
agent
@@ -1071,7 +1071,7 @@ export function createAgentCommand(deps: AgentDeps = {}): Command {
10711071
)
10721072
.option(
10731073
'--target <t>',
1074-
'Agent target(s): claude, cursor, cline, antigravity, kiro, windsurf, codex (comma-separated or repeated)',
1074+
'Agent target(s): claude, cursor, cline, antigravity, kiro, windsurf, copilot, codex (comma-separated or repeated)',
10751075
collect,
10761076
[],
10771077
)

src/commands/auth.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,20 @@ describe('runWhoami', () => {
850850
expect(printed).toEqual(sampleMe);
851851
});
852852

853+
it('dry-run: whitespace-only TESTSPRITE_API_URL falls through to prod default endpoint', async () => {
854+
const { capture, deps } = makeCapture();
855+
await runWhoami(
856+
{ profile: 'default', output: 'text', debug: false, dryRun: true },
857+
{
858+
...deps,
859+
env: { TESTSPRITE_API_URL: ' ' },
860+
credentialsPath,
861+
},
862+
);
863+
const out = capture.stdout.join('\n');
864+
expect(out).toContain('endpoint: https://api.testsprite.com');
865+
});
866+
853867
it('L1788: text output includes the resolved endpoint URL', async () => {
854868
writeProfile(
855869
'default',

src/commands/auth.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
readProfile,
1818
writeProfile,
1919
} from '../lib/credentials.js';
20-
import { loadConfig } from '../lib/config.js';
20+
import { loadConfig, normalizeEnvVar } from '../lib/config.js';
2121
import { emitDeprecationNotice } from '../lib/deprecate.js';
2222
import type { OutputMode } from '../lib/output.js';
2323
import { GLOBAL_OPTS_HINT, Output, resolveOutputMode } from '../lib/output.js';
@@ -85,7 +85,7 @@ export async function runConfigure(opts: ConfigureOptions, deps: AuthDeps = {}):
8585
// treated as unset. Without this, `''` (e.g. `export TESTSPRITE_API_URL=` in a
8686
// shell profile) is non-nullish and would short-circuit the `??` chains below to
8787
// an empty endpoint instead of falling through to the profile / prod default.
88-
const envApiUrl = env.TESTSPRITE_API_URL?.trim() || undefined;
88+
const envApiUrl = normalizeEnvVar(env.TESTSPRITE_API_URL);
8989

9090
// Dry-run: do not prompt, do not read env, do not write credentials.
9191
// Print the canned success shape so an agent sees exactly the JSON it
@@ -208,7 +208,8 @@ export async function runWhoami(opts: CommonOptions, deps: AuthDeps = {}): Promi
208208
// displayed URL always matches where requests actually go (dogfood L1788).
209209
let resolvedEndpoint: string;
210210
if (opts.dryRun) {
211-
resolvedEndpoint = opts.endpointUrl ?? env.TESTSPRITE_API_URL ?? 'https://api.testsprite.com';
211+
resolvedEndpoint =
212+
opts.endpointUrl ?? normalizeEnvVar(env.TESTSPRITE_API_URL) ?? 'https://api.testsprite.com';
212213
} else {
213214
const credentialsPath = deps.credentialsPath ?? defaultCredentialsPath();
214215
const config = loadConfig({

0 commit comments

Comments
 (0)