The first real safety net for "works once" — so the next AI change can't silently break the last one.
Module 6 · Turn acceptance criteria into automated tests.
Intermediate Testing Includes Lab ~50 minPrerequisites: Module 5 — a working snippet vault (create, list, search, delete).
Failure mode #1 from Module 1 was "works once": the demo runs, but the next change silently breaks something and nobody notices. When an AI is rewriting your code many times a day, that risk multiplies. Automated tests are the fix — they re-check your acceptance criteria in seconds, every time.
| Without tests | With tests |
|---|---|
| You click through the app hoping nothing broke | One command confirms every feature still works |
| Regressions ship silently | A broken feature fails the build loudly |
| "Done" is a vibe | "Done" = the acceptance-criteria tests pass |
Remember the acceptance criteria you wrote in Module 3? "Empty title is rejected", "search is case-insensitive"… each one is a test waiting to be written. Tests are just your spec, made executable.
Don't drown in test theory. For a small app, two kinds carry the weight:
| Type | Checks | Example for the vault |
|---|---|---|
| Unit | One small function in isolation | The search filter returns matches case-insensitively |
| API integration | An endpoint end to end | POST /snippets creates and returns a snippet; empty title is rejected |
You'll hear about unit vs integration vs end-to-end ratios. For now: write a test for every acceptance criterion at the level that's cheapest to check. Mostly that's API integration tests for the endpoints and a couple of unit tests for tricky logic.
Test-Driven Development pairs beautifully with an assistant: write the test first (from an acceptance criterion), watch it fail, then have the AI make it pass. The failing test is a crystal-clear target the assistant can't wander away from.
Prefer test-after? That's fine too — just don't skip it. The rule is simply: every acceptance criterion ends up with a test, whether you write it before or after the code.
"Write API integration tests for the acceptance criteria of stories M1–M3 in SPEC.md. One test per criterion, clear names. Don't change app code — just the tests." Then you review them, run them, and only then let it fix failures.
AI-written tests have a trap: an assistant can write a test that always passes, or that tests the wrong thing, and proudly report "all green." Green is only meaningful if the tests are real.
| Trap | Guard |
|---|---|
| Test asserts nothing meaningful | Read each test — does it actually check the behavior? |
| 100% coverage, 0% confidence | Coverage measures lines run, not correctness. Don't chase the number. |
| Tests pass because they mock everything | Keep at least some tests hitting the real endpoint. |
The only way to trust a test is to see it fail for the right reason. Temporarily introduce a bug (e.g. accept an empty title) and confirm a test goes red. If nothing fails, your test wasn't testing anything.
You'll add a test runner, turn your acceptance criteria into automated tests, and prove they work by catching a deliberate bug.
Your snippet-vault repo from Module 5 with M1–M3 working.
Ask the assistant to set up a test runner in api/ (Jest or Vitest with Supertest for HTTP). Review the config diff; commit it.
Read every test. Does each assert the real behavior?
If any fail, decide: is the test wrong, or the code? Fix the right one. Commit when green.
Temporarily let the create endpoint accept an empty title. Run the tests — the "empty title rejected" test should go red. If it doesn't, your test is fake; fix it. Then revert the bug.
In REFLECTION.md: which test caught the deliberate bug, and did any AI-written test turn out to assert nothing? Commit it.
Your snippet-vault repo. Self-check:
npm test runs and passes in api/REFLECTION.md notes the bug a test caught| Term | Plain meaning |
|---|---|
| Unit test | Checks one small function in isolation. |
| Integration test | Checks parts working together — e.g. a whole API endpoint. |
| TDD | Write the failing test first, then code until it passes. |
| Regression | A previously working feature that a new change broke. |
| Coverage | The % of code lines your tests run — useful, but not proof of correctness. |
A test suite that turns your acceptance criteria into an executable safety net — run in one command, proven to catch a real bug. "Works once" is now "keeps working."
Next up: Module 7 — Quality Gates & Security. Tests catch broken behavior; now we add the gates that catch bad style and dangerous security holes — linting, secret scanning, and validation — before they reach main.