Adapted from the Fission test-writing conventions, keeping only what applies to this Go CLI and reconciling with the conventions already in the tree. When a rule below disagrees with an existing test, follow the existing pattern in that package — consistency wins — and raise the discrepancy rather than silently rewriting.
- Table-driven with a
map[...]or[]structof cases; uset.Run(name, …)with descriptive case names for anything with more than a couple of cases (seeinternal/result/result_test.go). t.Parallel()on independent tests and non-state-sharing subtests. Do not parallelize the live-Chrome tests — they share a spawned browser.t.TempDir()for any filesystem fixture; never write into the repo or a hardcoded path.t.Cleanup()for teardown instead of baredeferwhen the resource is set up mid-test.- Name tests
TestXxxand test through the exported API of the package (the envelope, thechrome.Browserinterface,target.Resolve) — not unexported internals, unless the internal is the unit.
- Unit-test CLI and daemon behavior against
chrometest.StubBrowser, not a real browser. Embed it and override only the methods the test asserts on. - When you add a method to the
chrome.Browserinterface, give it a permissive default inchrometest.StubBrowser— that's the single place a new method gets its test default. - Assert on the envelope and exit code (the contract), not on incidental human-rendered text. A test that pins
error.code→ exit code is more valuable than one that pins a✗ …string.
- Guard every test that drives a real Chrome with
if testing.Short() { t.Skip(...) }, and skip gracefully when no Chrome binary is found. This project usestesting.Short()for this, not//go:build integrationtags. - These tests legitimately use
context.Background()(the driver context is tied to the browser lifecycle, not the test's). Elsewhere, prefer a scoped context. - Keep them hermetic: spawn the browser the test needs, drive a
data:/local fixture page where possible, and tear it down int.Cleanup.
Use net/http/httptest (NewRecorder / NewServer) for any HTTP-facing code rather than a real network listener.
- The parser-shaped surfaces — the
targetgrammar and the--byselector syntax — are good fuzz/property targets: round-trip stability, and "only exactly-valid input parses". Preferpgregory.net/rapidover the frozentesting/quickif you add property tests; directgo test -fuzzat the parser boundary and check the corpus intotestdata/. - Good properties here:
Resolveis deterministic for a fixed tab list; a selector that round-trips through parse→format is unchanged; unknownerror.codealways maps toExitGeneric.
The existing suite uses the standard library (t.Errorf / t.Fatalf), not testify.
Fission mandates testify require/assert; this repo does not depend on it.
Match the standard-library style in existing files; do not introduce testify as a new dependency for a single test without agreement.
These Fission rules target infrastructure this project doesn't have — ignore them: Kubernetes fake clientsets / envtest, go-snaps snapshots, porcupine/TLA+ linearizability, framework.Connect(t) integration harness, SPDX-header make license, and the Fission-specific builders.