Skip to content

Add AI Test Authoring commands and run kind - #1105

Open
slvinittomar wants to merge 6 commits into
mainfrom
feat/ai-test-authoring
Open

slvinittomar wants to merge 6 commits into
mainfrom
feat/ai-test-authoring

Conversation

@slvinittomar

Copy link
Copy Markdown
Contributor

Summary

Adds Sauce Labs AI Test Authoring to saucectl, and corrects the region list the CLI advertises.

Supersedes #1100, which carried the same feature alongside the Spec Kit toolchain and the specification documents; those are now in #1104. Rebuilt on current main as six commits, each of which builds and tests on its own.

saucectl authoring — new command group

31 commands over the AI Authoring API, every one supporting -o text|json:

Group Commands
testcases generate (with --wait, --intent-file, --target/--target-json, --max-steps, --generation-timeout), generate-status to reattach to a running task, list, get (--show-steps, --revision), rename, delete, run, list-runs, get-run, list-tags, code and list-code-targets to export a case as Playwright/Selenium/WebdriverIO source
testsuites create, list, get, update (incremental --add-test-case/--remove-test-case), run, delete
schedules create, list, get, update (partial, with --unset), enable, disable, delete
variables create (--value-from-env, --value-from-file, masked prompt), list, get, update, delete, at org/team/suite/case scope
download-artifact fetch a screenshot or other job artifact by id or URL

Behaviour worth knowing:

  • Authoring streams progress as the agent works — reasoning titles and each recorded action — and Ctrl-C stops waiting locally while the task continues on Sauce Labs, printing the command to reattach.
  • Deleting a test case, suite, schedule or variable prompts first, listing what else is affected. --yes bypasses it; a non-interactive run without --yes refuses rather than hangs.
  • Secrets are never printed. variables get shows <secret>, and the JSON output omits the value entirely.
  • Listing supports --limit/--skip/--all, and --limit 0 returns a count only.
  • Variable updates take an optional --expected-last-update token and fail if the variable changed since it was read.

kind: authoring — new run configuration

Authored suites now run through saucectl run, so they get the existing reporters, artifact download, concurrency limit and CI exit codes:

apiVersion: v1alpha
kind: authoring
sauce:
  region: us-west-1
  concurrency: 2
suites:
  - name: login
    testSuiteName: checkout-suite   # or testSuiteId, or testCases: [...]
    targets:
      - capabilities: {browserName: chrome, browserVersion: latest, platformName: "Windows 11"}
  • One result row per test case per target; a failing run exits 1.
  • --async starts the runs and returns; --dry-run resolves and prints what would run without starting anything.
  • defaults.timeout stops waiting and stops the jobs on Sauce Labs, so a timed-out run no longer leaves a VM busy. Ctrl-C does the same.
  • Settings that do not apply to this kind (retries, env, launchOrder, --fail-fast, --live-logs, showConsoleLog, metadata tags) produce a warning each and are ignored, never silently dropped.
  • Suites referenced by testSuiteName match exactly and case-sensitively; an ambiguous name reports the candidate IDs.

Region help, in every command group

--region help and the invalid-region error advertised us-west-1, eu-central-1, omitting us-east-4 and asia-south-2. Both are now built from the region table itself, so authoring, storage, builds, devices, jobs, artifacts, apit, init and run list every supported region and cannot drift again.

Two repository fixes

  • The CI build job stamped -X against cli/version.*, a package that does not exist, so released binaries reported no version. It now targets internal/version, matching .goreleaser.yml.
  • make schema used pushd/popd, which are bash builtins and fail under make's /bin/sh. It now uses cd.

How the client handles the live service

Several observed behaviours contradict the published API specification; each is handled here and carries a code comment:

Observed What this PR does
Auth is HTTP Basic, not bearer JWT one auth helper, platform convention
GET /testcases/{id}/runs ignores its path parameter testCaseId always sent as a query parameter; without it the whole org's runs come back
Runs have no status field; success appears ~19 s in, before the Sauce job completes completion inferred from per-job *bool, run resource polled every 5 s
Some stored cases carry scTunnelName: "", which fails runs with SC_TUNNEL_NOT_FOUND the run request always sends explicit null when no tunnel is configured
Authored jobs publish video/logs/screenshots but no junit.xml JUnit content synthesised per job, so reporters.junit is not a set of empty containers
The error envelope carries an undocumented error.data[] with the actionable message decoded and rendered
404 is an ordinary answer here the shared 404-retry is disabled for this client; mutations never retry
Schedule updates require the complete object; omitted fields are kept, explicit null clears read-modify-write; --unset sends null; UTC is rejected, so --timezone is required
Entitlement lives in a platform API outside the authoring spec fail-closed gate that distinguishes "not in your plan" from "could not verify"

Testing

  • make lint, make test, make build and a Windows cross-build pass. The schema bundle is byte-identical to a fresh regeneration, verified on Node 24 to match the pinned CI runtime.
  • Each of the six commits builds and tests on its own, so the branch stays bisectable.
  • Unit tests cover the client (auth, envelope, error decoding, single-request 404, no-retry mutations, query filter, explicit-null tunnel), the runner (synchronous start, polling, multi-target, timeout, start failure, async, concurrency ceiling, cancellation, JUnit synthesis, resolution by suite name/ID/cases, dry run) and the command helpers.
  • Against the live service in three data centres: every read-only command; create, update and delete for all four asset types including the confirmation refusal paths; passing and failing pipeline runs with JUnit and artifact download; interrupt and reattach during authoring; timeout and concurrency behaviour. No blockers. All verification assets were deleted afterwards.

Notes for reviewers

  • config.ValidateSchema validates against the bundle on main, so kind: authoring prints an advisory schema error locally until this merges. It fails soft, like every other new kind before it.
  • Confirming before delete departs from storage delete because these are shared org-level assets with no undo.
  • Generics (List[T], ListAll) are new to this repository.
  • Known gap: interrupting saucectl run during the entitlement check reports a raw transport error instead of Run was not started: interrupted., because that message lives in Runner.logResult, which an interrupt at the gate never reaches.
  • The feature specification and the manual test plan are in Add Spec Kit toolchain and Claude Code skills #1104. Documentation for the new commands belongs in saucelabs/sauce-docs and is not yet drafted.

🤖 Generated with Claude Code

slvinittomar and others added 6 commits September 17, 2026 18:59
The build job passed -X ldflags for
github.com/saucelabs/saucectl/cli/version.*, a package that does not
exist. Go ignores -X for symbols it cannot find, so CI binaries were
never stamped. Point it at internal/version, as .goreleaser.yml does.

The schema target used pushd/popd, which are bash builtins and fail
under make's /bin/sh. A plain cd in the recipe's subshell is equivalent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
region.Options() builds the list from sauceRegionMetas so help text and
error messages cannot fall behind the table, which is what happened when
asia-south-2 was added. None and the internal staging region are not
advertised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every group advertised "us-west-1, eu-central-1", omitting us-east-4 and
asia-south-2. Each now builds the list with region.Options(). Note that
internal/cmd/run/run.go carries the same change, but it lands with the
authoring dispatch it also contains.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The spec lives in a separate PR, so the pointer would dangle here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@slvinittomar
slvinittomar requested a review from a team as a code owner September 17, 2026 13:55
@slvinittomar slvinittomar added enhancement New feature or request go Pull requests that update Go code claude-code-assisted labels Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-code-assisted enhancement New feature or request go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant