integration-test-writer · diff
git:20260930.17fecc4 to git:20261012.213de19
85 added, 47 removed. Audit A to A.
---
name: integration-test-writer
- description: Plans and implements comprehensive integration tests for the PABX backend (apps/backend/__tests__/integration/) using Jest + supertest against a real test database. Runs interactively (3 phases with an approval checkpoint) when a user calls directly, or autonomously (no pause) when dispatched by implement-feature/evaluator. Also runs in correction mode to fix a specific failing integration test flagged by the evaluator. Enforces PABX rules (setupTestDatabase, try-finally cleanup, foreign-key order, English-only, NODE_ENV=testing, batches). Never modifies production code.
+ description: "Use when an endpoint or module needs integration tests in any project — requests through the real stack against a real test environment — when implement-feature dispatches a phase's tests, when the evaluator or qa-preflight dispatch the correction of a failing integration test or a missing query-growth test, or when a user asks to plan or write integration tests. Generic — the environment, the helpers, the data policy and the commands come from the test profile in the project's GATES.md, never from another project. Never modifies production code."
---
- # Integration Test Writer (PABX)
+ # Integration Test Writer
- Plan and implement high-quality **integration tests** that validate real API behavior against a
- real test database (full request→response lifecycle: middleware, controller, model, DB).
- **Never modifies production code** — if a test fails, only the test is adjusted.
+ Plan and implement **integration tests** that validate real behavior against a real test
+ environment: the full request→response lifecycle, and what it changed. **Never modifies
+ production code** — if a test fails, only the test is adjusted.
- > **Project scope:** PABX backend. All hard rules (file structure, `setupTestDatabase`,
- > try-finally cleanup, foreign-key order, coverage minimums, execution commands) are in
- > **`references/pabx-rules.md`** — read it before writing.
- > Generic SDD flow docs: `https://github.com/dayvisonassis/sdd-skills/blob/main/docs/GUIA_DO_WORKFLOW.md`.
+ > **The project defines the facts; this skill defines the discipline.** All hard rules (project
+ > profile, boundary, structure, data, authentication, assertions, query growth, the checklist,
+ > execution) are in **`references/integration-rules.md`** — read it before writing. Its first
+ > section tells you what to read from the project's `GATES.md`: suites, entry point,
+ > environment, authentication, data policy, query counter, and the path of the project's own
+ > rules, which are binding.
+ > **The suite's language has its own file,** `references/languages/<language>.md`: the same
+ > rules in that language's idiom, its anti-patterns, and a worked query-growth test. Read the
+ > one that applies, and only that one (`integration-rules.md`, "Language").
+ > Background on the SDD flow, not needed to run this skill: `https://github.com/dayvisonassis/sdd-skills/blob/main/docs/GUIA_DO_WORKFLOW.md`.
- **Scope:** `apps/backend/__tests__/integration/`.
+ **Scope:** the integration suites the project profile names.
## INPUT
- - `target_file_or_endpoint` (required) — controller, route, or endpoint (e.g. `POST /v2/calltype`).
- - `mode` (optional) — `interactive` (default when a user calls) or `autonomous` (set by implement-feature/evaluator).
- - `test_file_path` / `focus_areas` / `batch_size` (optional).
- - `test_catalog_path` (optional) — Test Catalog entry to accelerate Phase 1.
- - `evaluation_report` (optional) — when present, run in **correction mode** (fix only the flagged test).
+ - `target_file_or_endpoint` (required) — a handler, a route, or an endpoint (`POST /orders`).
+ - `feature` (optional) — the feature folder's id (`F14`); decides where the checklist goes, and which endpoints the query-growth table covers. That folder's `spec.md` and `contract.md`, when it has them, are "the spec" the rules refer to.
+ - `mode` (optional) — `interactive` (default when a user calls) or `autonomous` (set by implement-feature/evaluator/qa-preflight).
+ - `language` (optional) — the suite's language (`javascript`, `python`, …). When given, it wins over what the profile and the repository say.
+ - `test_file_path` / `focus_areas` / `batch_size` (optional; default 8, from 5 to 10; a remainder smaller than 5 joins the last batch).
+ - `evaluation_report` (optional) — its `kind: test` entry selects the mode: an existing `testFile` → **correction mode**; none → write only what its `message` names (a missing query-growth test, or coverage for one rule).
## OUTPUT
- - New/expanded integration tests in `apps/backend/__tests__/integration/`, following PABX rules.
- - A `.test.md` checklist (planning may be Portuguese; **all test code is English**).
- - Per-batch execution confirmation and a final coverage summary. Production code untouched.
+ - New or expanded integration tests where the profile says the suite's tests live.
+ - The checklist `integration-rules.md` describes ("The checklist"), with its query-growth table when the profile declares a query counter.
+ - Per-batch execution result, in the checklist's Execution part: how many tests ran, and the red run that proved the batch can fail.
+ - **One signal to the caller**, always one of: **"done — <test file paths>; checklist <path>"**, with paths relative to the repository root, followed by one line for each thing only the caller can act on — **"red growth test: <title> — <the statement that repeats>"** for every growth test left red on the feature's own code, and **"spec mismatch: <behavior> — spec: <x>; code: <y>"** for every test written as the code behaves against the spec (rule F1); **"not resolved — environment: <which>"** (the integration harness is not declared and the repository does not reveal it, or the test environment cannot be reached). A "not resolved" run writes nothing.
+ - Production code untouched; the environment the same as before the run; nothing committed — the caller decides when the tests are committed.
---
## Invocation Modes
**Interactive (default):** full 3-phase process, **stop at the Phase 2 checkpoint** for explicit approval.
**Autonomous (dispatched):** same phases, **skip the checkpoint** — auto-accept the checklist and implement. Never pause.
- **Correction mode (evaluator, `kind:test`):** an `evaluation_report` is provided. Fix **only** the
- flagged failing test (smallest footprint) so it conforms to the PABX rules and passes; do not
- touch production code or unrelated tests. When the report names a **missing query-growth test**
- (an endpoint, no failing test), write that one test, or record the outcome that applies, in the
- checklist; touch nothing else. Return control to the evaluator.
+ **Correction mode (evaluator, `kind: test`, existing `testFile`):** fix **only** the flagged test
+ so it conforms to `integration-rules.md` and passes. Leave unrelated tests and production code
+ alone. When the report names a **missing query-growth test** (an endpoint, no failing test),
+ write that one test, or record the outcome that applies, in the checklist; touch nothing else.
---
## EXECUTION STEPS (3 Phases)
### Phase 1 — Analysis & Planning
- 1. If `test_catalog_path` given, read the entry and validate against source.
- 2. Study existing `apps/backend/__tests__/integration/` for patterns/helpers/utilities.
- 3. Read the target controller/model/route fully; map code paths.
- 4. Identify test utilities: `setupTestDatabase()`, `cleanupTestDatabase()`, token helpers, factories. Consult DB schema (MCP MySQL) for FK constraints if needed.
- 5. Map scenarios: CRUD, auth/authorization, validation, not-found, edge cases, boundaries, relationships, concurrency, security (SQLi/XSS), data integrity, and **query growth** (N+1): one recorded outcome per endpoint in its scope (`references/pabx-rules.md`, "Query growth — Scope and outcomes").
+ 1. Read the test-profile section of `GATES.md` and pick the suite: the integration suite whose sources contain the target's handler. Resolve its **language** (`integration-rules.md`, "Language") and read its file in `references/languages/`. A language with no file → the generic rules alone, noted in the checklist.
+ 2. Build the **project profile** (`integration-rules.md`, first section). A required item missing from both `GATES.md` and the repository → return **"not resolved — environment: integration harness not declared (<items>)"**, naming every missing item.
+ 3. Confirm the environment can be reached with the profile's commands. It cannot → **"not resolved — environment: <which>"**.
+ 4. Read the project's rules file when the profile names one. It is binding.
+ 5. Read existing tests of the suite for helpers and to avoid duplicating a case already covered.
+ 6. Read the target fully — route, middleware, handler, data access — and map its code paths. With a `feature`, read its folder's `spec.md` and `contract.md` for what the endpoint is meant to do.
+ 7. For every record a test will create: how it is created, what it depends on, and how it is removed, in the profile's removal order (D1–D8).
+ 8. Map the scenarios (V2), each with an expected value that does not come from the product's own code (V5). When the profile declares a query counter, decide **one outcome per endpoint** in the scope of "Query growth — Scope and outcomes".
### Phase 2 — Checklist Creation
- Create a `.test.md` checklist (name, objective, input, expected status + response). Cover the
- minimum categories from `references/pabx-rules.md`.
- - **Interactive:** ask the coverage/security/auth checkpoint questions → **WAIT for approval.**
+ One row per test, plus the query-growth table, as `integration-rules.md` describes.
+ - **Interactive:** ask — is every failure path covered, including authentication and authorization? does any test create data it cannot remove? → **WAIT for approval.**
- **Autonomous / correction:** skip the checkpoint; proceed.
### Phase 3 — Batch Implementation
- GROUP into batches of 5–10 → IMPLEMENT with `setupTestDatabase`/try-finally/FK-order cleanup →
- EXECUTE with `NODE_ENV=testing` and `--forceExit --detectOpenHandles` → UPDATE checklist →
- REPEAT. In correction mode, implement only the corrected test(s).
+ GROUP 5 to 10 tests per batch → IMPLEMENT per `integration-rules.md`, the language file and the
+ project's rules, with guaranteed cleanup in the profile's removal order → RUN the batch's
+ selection with the profile's command and read the result and **how many tests ran** → PROVE the
+ batch can fail (rule E5): invert every test's expectation, run once and see each one red at its
+ assertion with its cleanup done, restore, run once more → UPDATE the checklist → REPEAT. Run the
+ whole suite once at the end.
+ ### Phase C — Correction mode
+ 1. Build the profile and resolve the language as in Phase 1 (steps 1 to 4): a corrector needs the environment as much as a writer does. Read the report's `testFile`, `targetFile`, `message`, `evidence`, and the target; with a `feature`, its `spec.md` and `contract.md` — a corrected expectation needs a source that is not the product's code (V5).
+ 2. Run the narrowest selection the profile's command offers that holds the flagged test — the test alone where the runner selects by name, its file or package otherwise — and read why it fails.
+ 3. Fix the smallest footprint that makes it conform and pass, and run that selection again. The whole suite is not run.
+ 4. When the test's assertion changed, prove that it can fail (rule E5) with the corrected test as a batch of one: invert it, run and see it red at its assertion with its cleanup done, restore, run once more.
+ 5. Record the correction where the test file already has a checklist — its row, and one Execution line with the runs. Create none for a file that has none: the runs then go in the result. Return *done*.
+
---
## RULES
**Always:**
- - Follow `references/pabx-rules.md` (file structure, cleanup, coverage, execution).
- - Use `setupTestDatabase()`/`cleanupTestDatabase()`; `try-finally` for any test that creates data; `try-catch` inside `finally`; FK order (children before parents); delete only test-created data.
- - Write ALL test content in English; independent, deterministic tests; assert status codes and response bodies.
- - Set `NODE_ENV=testing`; run with `--forceExit --detectOpenHandles`.
- - In correction mode, fix only the flagged test and return to the evaluator.
+ - Build the project profile from `GATES.md` before anything else, and follow `references/integration-rules.md` and the suite's language file exactly.
+ - Follow the project's own rules file where the profile names one; it wins where it is stricter.
+ - Open and close the environment through the profile's helpers.
+ - Create the test's own records and remove them in a block that runs even when the test fails, children before parents, by stored id, with no removal failing silently.
+ - Assert the status of every request, verify a write by reading it back, and write every expected value from outside the product's own code.
+ - Run every batch, count what ran, and see it red once.
+ - Record exactly one query-growth outcome per endpoint in scope, when the profile declares a counter.
+ - End with exactly one of the two signals in OUTPUT, with its `red growth test` and `spec mismatch` lines when it has any.
**Never:**
- - Modify production code (`*.model.js`, `*.controller.js`, routes). Fix only tests.
- - Leave test data in the DB or remove pre-existing data. Rely solely on `afterEach`/`afterAll` for created data.
- - Clean in the wrong FK order; use external data-population scripts; write Portuguese in tests.
- - Pause for approval in autonomous/correction mode.
+ - Modify production code. Fix only tests.
+ - Change or remove data the test did not create, or leave data behind.
+ - Rely on a suite-level hook alone to remove what a test created.
+ - Replace the handler, the router or the data-access layer under test.
+ - Take a helper, a removal order or a command from another project or from memory instead of the project profile.
+ - Relax a query-growth assertion with a margin or a budget.
+ - Commit. The caller decides when the tests are committed.
+ - Pause for approval in autonomous or correction mode.
---
## Edge Cases
- - **Data created inside `it()`:** `try-finally` is mandatory (not just `afterAll`).
- - **FK-constrained entities:** delete children before parents per the documented order.
- - **> ~20 tests with `--verbose`:** redirect output to a file to avoid AI disconnections.
- - **Stack not PABX backend:** this skill is PABX-specific; report that a generic approach is needed.
+ - **`GATES.md` has no test profile, but the suite exists:** build the profile from its config and helpers (the fallback column), say so in the checklist, and proceed.
+ - **`GATES.md` is absent, and the language file says the toolchain fixes the convention:** where tests live, how they are named and the two commands are the toolchain's. The entry point and the environment are never a convention: the repository shows them, or the harness is not declared.
+ - **Neither reveals a required item:** "not resolved — environment: integration harness not declared (<items>)". Declaring it is the `gate-builder`'s job.
+ - **The environment cannot be reached** (database down, container not started, wrong configuration): "not resolved — environment: <which>". Never point the suite at a non-test environment to get a run.
+ - **The whole-suite command fails for a reason that is not a test** (a path the runner does not accept, a script that does not exist): the tests proved by the selection's command stand. Return *done*, and report the command and its error in the result — repairing a gate's command is the `gate-builder`'s, not this skill's.
+ - **The profile says the suite's isolation replaces cleanup** (a rollback per test, a database per worker): rule D7 — do not add manual cleanup on top. A private database whose data policy still names removal helpers is not that case.
+ - **A record no helper can remove:** do not create it. Cover the behavior on existing data read-only, and record the gap in the checklist.
+ - **The suite's language has no file in `references/languages/`:** the generic rules alone, read in the language's own idiom; note it in the checklist. Never stop for it.
+ - **There is no spec** (no `feature`, or its folder has none): expected values come from what the test sent and created and from the rules the code states, the tests pin what the code decides, and the checklist says so once.
+ - **A test only passes by asserting behavior the spec contradicts:** write it as the code behaves, record the mismatch in the checklist (rule F1), and repeat it in a `spec mismatch` line of the signal — whoever dispatched the writer may be able to fix the code, and no dispatcher reads the checklist for it.
+ - **Dispatched again after the caller corrected the code** — it answered a `spec mismatch` line: the test that pinned the old behavior is now red; rewrite it to the spec and remove its note.
+ - **The profile declares no query counter:** no query-growth test and no outcome; say so once in the checklist.
+ - **A growth test is red on legacy code:** the `pre-existing N+1` outcome, with the statement and both locations; the red test is not committed.
+ - **A growth test is red on the feature's own code:** it stays red and unrelaxed, its title is the endpoint's outcome, and the signal names it with the statement that repeats. Never fix the production code, and never weaken the assertion to get a green run.
+ - **Called autonomously and the checklist reveals an ambiguity:** apply a best-practice default, note it in the checklist, and proceed.