Testing Bindery
SkillDev toolsUse when writing or running Bindery tests, before pushing, or before opening a PR — covers the full pre-PR matrix (lint, vet, govulncheck, test, frontend), pinned tool versions, the project's test patterns (db.OpenMemory, httptest, vitest), and common failure modes.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Testing Bindery skill
What this skill tells your AI
The instructions your AI receives, as published by vavallee/bindery in .claude/skills/testing/SKILL.md and read by ahel’s review.
CI runs every check below on every push and PR. Mirror it locally before pushing — failing CI is slower than failing locally.
Pre-PR matrix
# Go
gofmt -l . | tee /dev/stderr | (! read) # exits non-zero if any file is unformatted
go vet ./...
golangci-lint run --timeout=5m # pinned to v2.11.4 — see below
govulncheck ./...
go test -race -coverprofile=coverage.out -covermode=atomic ./cmd/... ./internal/...
# Frontend (skip if web/ untouched)
cd web && npm ci && npm run lint && npm run typecheck && npm run build && npm test
Make wrappers for convenience:
make lint— Go + frontend lintersmake test— Go tests + coverage, no race, same as the CI gatemake test-race— the race detector in CI's six shards (#2293)make test-web—vitest+ coverage
For wiring-level changes (handlers, scheduler jobs, downloader integrations, import flows), unit tests aren't enough. Escalate to make smoke — see the smoke-testing skill for the decision tree.
Pinned tool versions
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4
go install golang.org/x/vuln/cmd/govulncheck@latest
CI uses golangci-lint v2.11.4 exactly. @latest locally can disagree with CI and waste a round-trip.
Test patterns
Backend (Go)
- One
_test.gofile per source file, sibling location (internal/api/books.go→internal/api/books_test.go). - DB-backed tests use
db.OpenMemory()frominternal/db. Never use temp files; never mock the DB. Mocked DB tests pass when migrations are broken. - HTTP handlers:
httptest.NewRecorder+httptest.NewRequest, exercise routes through the same setup as production. - Assertions on wrapped errors:
errors.Is/errors.As(errorlint rejects==). - Always check
rows.Err()after iterating SQL rows (rowserrcheck enforces it). - Outbound HTTP in tests: stub via
httptest.NewServer, never live network.
Frontend (React + TS)
- Pages:
web/src/pages/<Name>Page.tsxwith sibling<Name>Page.test.tsx. vitest+@testing-library/react+jsdom; setup inweb/src/test-setup.ts.- Mock the API client (
web/src/api/) — never hit the network. - Prefer
userEventoverfireEventfor interactions. - Run a single page test fast:
npm test -- BooksPage.test.tsx(no watch).
When new code requires new tests
| Change | Tests required? |
|---|---|
New HTTP handler in internal/api/ | Yes — sibling _test.go covering the success path and at least one error path |
| New exported function with branching | Yes |
New domain logic in internal/{indexer,downloader,importer,...} | Yes |
| New React component with state, effects, or event handlers | Yes |
| Pure rendering / styled markup | Optional but appreciated |
| Pure refactor, no behaviour change | Existing tests must still pass; new tests not required |
Common failure modes
| Symptom | Likely cause |
|---|---|
gofmt flags a file you didn't touch | Merge-base drift; run gofmt -w <path> |
govulncheck fails with a CVE you didn't introduce | New advisory in a transitive dep. Bump the offender; call out the bump in the PR body |
| Every test in a package fails | A migration regression. Each package opens a fresh in-memory DB and runs all migrations — one broken migration takes the whole package down |
vitest passes, vite build fails | Missing static asset import or type error tsc --noEmit didn't catch. Run typecheck + build together |
Test passes locally, fails on CI with -race | A goroutine leak or unsynchronized map access. Run locally with -race -count=10 to reproduce |
| Smoke suite hangs at startup | Binary panicking before binding. Run ./bindery directly, read stderr |
Don't
- Don't
t.Skip()a flaky test to make CI green — investigate or revert the change that introduced flake. - Don't mock
internal/db. Use the in-memory DB. - Don't add new build tags (
//go:build foo) — the project doesn't use them. - Don't add
//nolintwithout a reason on the same line; readers and CI both expect a justification. - Don't commit
coverage.outorweb/coverage/— they're build artifacts.
Signals
- GitHub stars
- 456
- Forks
- 57
- Last commit
- Sep 2026
- Hacker News mentions
- 20
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
testing-vavallee- Source
- github.com/vavallee/bindery