Documentation
¶
Overview ¶
Package payloadtest is PayCLI's hermetic test harness: a fixture-backed Payload server, a golden-file comparator and a deterministic clock.
It is imported only by _test.go files. Fixtures are plain, pretty-printed, key-sorted JSON that a human or an agent can `cat` and diff — go-vcr's cassettes were rejected precisely because they are not (§17.2).
Index ¶
- Constants
- Variables
- func FixtureDir(t testing.TB) string
- func FixturePath(t testing.TB, name string) string
- func Golden(t testing.TB, name string, res Result)
- func GoldenDir(t testing.TB) string
- func Has(t testing.TB, name string) bool
- func Load(t testing.TB, name string) []byte
- func LoadJSON(t testing.TB, name string, v any)
- func Normalize(b []byte) []byte
- func Updating() bool
- type Clock
- type Index
- type Option
- type Recorded
- type Result
- type Route
- type Server
Constants ¶
const ( FixtureDirName = "fixtures" GoldenDirName = "golden" // IndexName is the routing index NewServer reads. // // §17.2 calls it "manifest.json", but testdata/fixtures/manifest.json is // itself a fixture — a recorded discovery manifest (§3's fixture list). Two // different documents cannot share one name, so the router's index is // _index.json and manifest.json stays what §3 says it is. IndexName = "_index.json" )
FixtureDirName and GoldenDirName are the two directories under testdata/.
const UpdateEnv = "UPDATE_GOLDEN"
UpdateEnv is the environment variable that rewrites golden files instead of comparing against them (`make golden`).
Variables ¶
var Epoch = time.Date(2026, 9, 16, 12, 0, 0, 0, time.UTC)
Epoch is the instant every test clock starts at. A fixed, obviously synthetic timestamp keeps golden files stable and makes an accidental time.Now() leak visible at a glance.
Functions ¶
func FixtureDir ¶
FixtureDir is the absolute path of testdata/fixtures.
func FixturePath ¶
FixturePath resolves one fixture by name, with or without the .json suffix.
func Golden ¶
Golden compares a whole-command result against testdata/golden/<name>.{out,err,exit}, or rewrites them under UPDATE_GOLDEN=1.
Because cli.Run takes injected IO and returns the exit code (§17.3), this runs in-process: no subprocess, so coverage works and Windows is free.
func Has ¶
Has reports whether a fixture exists, for tests that adapt to what was recorded rather than failing on an optional one.
func Load ¶
Load reads one fixture's bytes. A missing fixture is a test failure naming the command that re-records them.
func Updating ¶
func Updating() bool
Updating reports whether golden files are being rewritten.
os.LookupEnv rather than os.Getenv: it distinguishes "set to empty" from "unset", and it keeps this package clear of the identifier §3.1's arch-lint reserves for internal/cli/app.go. This package is imported only by _test.go files, so it is test tooling rather than program code either way.
Types ¶
type Clock ¶
type Clock struct {
// contains filtered or unexported fields
}
Clock is a deterministic, monotonically advancing clock.
Every call to Now advances it by Step, so a command that measures its own duration produces the same number on every run instead of a flaky 0-3 ms.
func Frozen ¶
func Frozen() *Clock
Frozen is the clock every golden test uses: it never moves, so meta.duration_ms is always 0.
func NewClock ¶
NewClock returns a clock at Epoch advancing by step on each read. A zero step makes the clock frozen.
type Index ¶
type Index struct {
PayloadVersion string `json:"payload_version"`
RecordedAt string `json:"recorded_at"`
BaseURL string `json:"base_url"`
Requests []Route `json:"requests"`
}
Index is testdata/fixtures/_index.json.
type Option ¶
type Option func(*Server)
Option configures NewServer.
func Strict ¶
func Strict() Option
Strict makes an unmatched request fail the test immediately. The default is to answer 404 with Payload's own "Route not found" body and record the miss, because discovery legitimately probes routes that do not exist.
func WithHandler ¶
func WithHandler(method, path string, h http.HandlerFunc) Option
WithHandler overrides one route with a live handler — for a 429 with a Retry-After, a truncated body, or anything else no fixture can express.
type Recorded ¶
Recorded is one request the harness actually received, so a test can assert on what PayCLI sent — the bulk-write "no limit= parameter" rule (§12.3) is exactly this kind of assertion.
type Route ¶
type Route struct {
Name string `json:"name"`
Method string `json:"method"`
Path string `json:"path"`
Query string `json:"query,omitempty"`
Status int `json:"status"`
ContentType string `json:"content_type"`
File string `json:"file"`
// Headers are extra response headers to replay, e.g. Retry-After.
Headers map[string]string `json:"headers,omitempty"`
// The three matchers below disambiguate fixtures that share a method and
// path. Payload's GraphQL endpoint is one URL for every query, /me answers
// differently with and without a credential, and a German validation error
// is the same request with one extra header (§17.1's regression guard).
MatchBody string `json:"match_body,omitempty"`
MatchHeader map[string]string `json:"match_header,omitempty"`
MatchAnonymous bool `json:"match_anonymous,omitempty"`
}
Route is one recorded request/response pair.
type Server ¶
Server is a fixture-backed Payload instance.
func NewServer ¶
NewServer starts a server that answers from testdata/fixtures. It is closed automatically when the test ends.
func (*Server) PayloadVersion ¶
PayloadVersion is the version the fixtures were recorded from.