Skip to main content

tdd

PitLog test patterns and the anti-rationalization table. The Red-Green-Refactor cycle itself is already mandated in AGENTS.md — this skill encodes only the project-specific patterns (dependency injection over database fixtures, invariant tests, the exact-answer fixture race) and the excuses for skipping the cycle. TRIGGER when writing or modifying code in packages/ or apps/api/src/. DO NOT trigger for documentation, YAML config, CI workflow files, or styling-only changes.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
weaties/pitlog
آخر نشاط في المصدر
١٩ أغسطس ٢٠٢٦ في ١٥:٣٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
tdd
description
PitLog test patterns and the anti-rationalization table. The Red-Green-Refactor cycle itself is already mandated in AGENTS.md — this skill encodes only the project-specific patterns (dependency injection over database fixtures, invariant tests, the exact-answer fixture race) and the excuses for skipping the cycle. TRIGGER when writing or modifying code in packages/ or apps/api/src/. DO NOT trigger for documentation, YAML config, CI workflow files, or styling-only changes.
# TDD — PitLog patterns AGENTS.md already mandates: **failing test → implement → green → lint.** This skill encodes only the bits that aren't obvious from reading the existing tests. ## Patterns **Unit tests never touch a database or a browser.** Inject the dependency instead. The tenancy gates take a `MembershipResolver` precisely so the whole role matrix can be tested with a plain object: ```ts function resolverFor(memberships: Partial<Record<string, Role>>): MembershipResolver { return async (userId, teamId) => { /* … */ } } ``` The real query is exercised once, by the browser smoke test. Do not stand up Postgres to test a rule about roles. **API route tests drive Hono in-process** — no port, no network: ```ts const res = await app.request(`/teams/${TEAM}/thing`) expect(res.status).toBe(403) ``` **Test the invariant, not the instance.** `packages/db/src/schema.test.ts` asserts that *every* domain table carries `team_id`, enumerated from the schema module, rather than listing the tables that do. A new table cannot quietly skip the rule. When you add a cross-cutting requirement, write the test that way. **The fixture race is the planner's test bed** (SPEC §7). Its numbers are chosen so the correct answer is exact — 6 stints × 75 min + 5 stops × 6 min = 8 h to the second, 3 drivers × 2 stints = perfectly equal seat time. Assert **equality** on seat time and stint boundaries, not tolerance. A planner that is "close" on fairness is wrong. Import it from `@pitlog/domain`; it has no database dependency: ```ts import { EIGHT_HOUR_RACE, KNOWN_GOOD_SOLUTION } from '@pitlog/domain' ``` **Determinism is a test requirement.** `generateFixtureLaps()` uses a seeded Mulberry32 PRNG, not `Math.random()`, and there is a test asserting two calls are identical. Any new fixture data follows the same rule — a fixture that differs per run cannot be a known-good answer. **Browser tests are thin.** `tests/e2e/` proves the app boots, login works, and the shell renders. Behavioural depth belongs in Vitest, which runs in under a second. ## What must be TDD'd Logic, always: the stint planner, the burn-rate model, the sync merge, the rule engine, expense splitting, the role gates, anything that computes a number a human will act on at 3am. Exempt: scaffolding, config files, CI workflows, Tailwind classes, route wiring that only calls into tested code. ## Don't rationalize skipping the cycle The cycle only helps if you don't talk yourself out of it. | Rationalization | Rebuttal | |---|---| | "This change is too small to need a test." | Size predicts neither breakage nor regression. The failing test is what proves the change does what you think. | | "I'll write the test after I see it work." | Test-after rationalizes whatever the code already does, bugs included. | | "It's just a route handler — I'll eyeball it." | Route handlers are the easiest place to ship a silent 500 or a missing `team_id` filter. `app.request()` costs you three lines. | | "Testing this properly needs a database." | Then the dependency is in the wrong place. Inject it. That is why `MembershipResolver` exists. | | "Tests pass, so it's correct." | Passing tests are evidence, not proof. Confirm the test would actually fail without your change — if you didn't see it red, you don't know. | | "The planner is close enough on fairness." | The fixture race has an exact answer on purpose. "Close" means a driver gets short-changed on seat time at a real race. | | "I'll use `Math.random()` in the fixture, it's only test data." | Then the known-good solution isn't known. Seed the PRNG. | | "Lint is noisy here, I'll skip the gate." | There is no pre-existing-error allowlist in this repo and there must never be one. Zero, always. | | "I'll add the `team_id` filter in a follow-up." | That follow-up is a data leak across a tenancy boundary. Do it now. | ## Running things ```bash make test # vitest, sub-second make e2e # playwright; needs make up && make migrate && make seed first make check # typecheck + lint + test — the pre-PR gate npx vitest packages/domain # watch one package while iterating ``` There is **no pre-existing-error allowlist** in this repo, deliberately (see AGENTS.md → Decisions). If lint or typecheck is red, fix it.
عرض على GitHub