testing-and-quality
Skill9 starsChanged 18 days agoApache-2.0View on GitHub
ShipIt testing conventions and quality checklist: Vitest config (server vs client), server test patterns (temp dirs), integration tests (buildApp, TestClient, test-helpers.ts), client tests (render, renderHook, FakeWebSocket), mocking patterns, and the pre-completion quality checklist (input validation, component tests, integration tests). Load when writing tests, reviewing coverage, or completing a feature.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- dynamics365ninja/d365fo-clitheir own version, first seen Oct 29, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- dynamics365ninja/d365fo-cli★ 45same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository15 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- add-endpointSkill
- android-buildSkill
- client-architectureSkill
- deployment-architectureSkill
- design-languageSkill
- docs-navigatorSkill
- dogfooding-shipitSkill
- frontend-design:frontend-designSkill
- git-architectureSkill
- prompt-architectureSkill
- server-architectureSkill
- session-containersSkill
- session-lifecycleSkill
- session-processesSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 36
Use temp directories (fs.mkdtempSync) cleaned up in afterEach with fs.rmSync(tmpDir, { recursive: true, force: true }).
- Very specific: line 58
When adding a new integration test, create a new file in this directory (or add to an existing one if the feature area matches) and import …
- Very specific: line 85
Use render() from @testing-library/react with cleanup in afterEach.
- Very specific: line 99
Use renderHook() with FakeWebSocket (stubbed via vi.stubGlobal) and vi.useFakeTimers().
- Distinctive: line 116
Every new feature must satisfy these before it's considered complete:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Testing Conventions & Quality Checklist
Progressive Testing
During development, use npm run test:dev instead of npm test. This runs:
- Affected tests — tests co-located with files you've changed (uncommitted, staged, and untracked)
- Smoke tests — a small set of critical-path tests that always run
The full suite (npm test) runs in CI on every PR. Only run it locally if you suspect wide-reaching breakage.
| Command | When to use |
npm run test:dev | Default for development — fast, targeted |
npm run test:dev -- --list | Dry run — see which files would run |
npm run test:smoke | Smoke tests only |
npm test | Full suite — CI runs this, rarely needed locally |
npx vitest run path/to/file.test.ts | Run a single specific test file |
Smoke tests are defined in scripts/test-dev.ts (the SMOKE_TESTS array). Keep the list small (~4-6 files).
Test Configuration
Tests use Vitest with three project configs in vitest.config.ts:
- Server tests (
src/server/**/*.test.ts) — Node environment - Tooling tests (
scripts/**/*.test.ts) — Node environment - Client tests (
src/client/**/*.test.{ts,tsx}) — jsdom environment with React Testing Library
Server Tests
- Use temp directories (
fs.mkdtempSync) cleaned up inafterEachwithfs.rmSync(tmpDir, { recursive: true, force: true }). - A server test starts with no credential configured.
server-test-setup.tsstrips every cataloguestorageEnvname and everySHIPIT_CREDENTIAL_*variable — eagerly, and again before every test. That covers both sources: the ambient environment (a session container exports the user's real keys into the test process, a CI runner has none — the divergence is invisible in CI, which is whytest-env-hermeticity.test.tspins it against an injected sentinel), and the suite's own writes (storing a credential through the API assigns its mode's variable in-process, so it would otherwise leak into the next test in the file). A test that wants a credential sets it per test or withvi.stubEnv— not inbeforeAll, which the strip runs after. - A
shipit.yamlfixture that does not parse fails the test that wrote it.server-test-setup.tsinstalls a write hook (shared/shipit-config-test-guard.ts) that validates any file namedshipit.yamlwith the product's own parser. The reason is that every opportunistic reader —classifyEmptyDepDirs,staleDepDirs,computeDepsHash,warnOnSkippedInstallOutput— deliberately catches aShipitConfigErrorand returns a conservative empty result, so a malformed fixture makes the check under test evaluate nothing while the assertion still passes. Three dep-dir tests were green that way (planning#480). The classic trap: YAML parses a baretrueas a BOOLEAN, so an install command must be quoted —- "true", never- true. A test that writes an invalid config on purpose wraps the write inexpectInvalidShipitConfig(() => ...), which is also the readable marker that the invalidity is the point. - Testability is built in. Store-backed managers take a
DatabaseManager—SessionManager(dbManager),UsageManager(dbManager),RepoStore(dbManager)— so a test passes an isolated database rather than a temp file path. Filesystem-backed ones still take a directory:GitManager(workspaceDir?). (The oldersessionsFile?/usageFile?/ThreadManager/DeploymentStoresignatures are gone — persistence moved to SQLite.)
Integration Tests
Live in src/server/orchestrator/integration_tests/ — one file per feature area.
Shared stubs live in src/server/orchestrator/integration_tests/, split across files — grep for the class rather than assuming test-helpers.ts:
test-helpers.ts—TestClient,StubAuthManager,StubGitHubAuthManagercontainer-test-helpers.ts—StubTerminal,StubWatcher- Some fakes are local to the test that uses them (e.g.
FakeCodexProcessincodex-agent.test.ts)
There is no StubViteManager — dev servers moved to Docker Compose via ServiceManager.
Each test file:
- Uses
buildApp()with injected stubs - Listens on port 0 (ephemeral)
- Connects via the
TestClientmessage-buffering WebSocket wrapper
When adding a new integration test, create a new file in this directory (or add to an existing one if the feature area matches) and import helpers from ./test-helpers.js.
HTTP endpoint tests
Use app.inject():
const res = await app.inject({
method: "GET",
url: `/api/sessions/${sessionId}/files`,
});
expect(res.statusCode).toBe(200);WebSocket message tests
Use TestClient:
const client = new TestClient(wsUrl);
await client.connected;
client.send({ type: "send_message", text: "hello", sessionId });
const msg = await client.waitFor("agent_event");Client Tests
Component tests
Use render() from @testing-library/react with cleanup in afterEach.
import { render, screen, cleanup } from "@testing-library/react";
afterEach(cleanup);
it("renders the component", () => {
render(<MyComponent />);
expect(screen.getByText("Hello")).toBeInTheDocument();
});Hook tests
Use renderHook() with FakeWebSocket (stubbed via vi.stubGlobal) and vi.useFakeTimers().
Mocking Patterns
vi.mock()for module mocksvi.fn()for function spies- Manual stub/fake classes for complex dependencies
- ESLint allows
anyin test files
Assertion Patterns
toMatchObject()for partial WS message matchingtoEqual()for exact structure@testing-library/jest-dommatchers for DOM assertions
Quality Checklist (run before marking a task done)
Every new feature must satisfy these before it's considered complete:
- Input validation at system boundaries — WebSocket handlers must validate user-supplied strings (empty, whitespace-only, too long) and return
{ type: "error" }. Never trust client input. - Component tests for new UI — every new React component (or significant UI addition to an existing component) needs a
*.test.tsxfile with@testing-library/react. Cover the happy path, edge cases (empty input, escape/cancel), and callback wiring. - Blur/focus edge cases — inline editors that save on blur must handle the case where blur is triggered by a parent element (e.g. backdrop dismiss) that cancels the edit. Use a ref guard to prevent double-fire.
- Integration tests for new endpoints — every new HTTP endpoint or WS message type needs at least one happy-path and one error-path integration test in
src/server/orchestrator/integration_tests/. HTTP tests useapp.inject(). WS tests use theTestClienthelper. Add to an existing file if the feature area matches, or create a new<feature>.test.tsfile and import shared helpers from./test-helpers.js. - Split slow test files — if a single test file takes more than ~10 seconds to run, split it into smaller files by feature area so Vitest can parallelize them.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

