Verified against GitHub Copilot Chat · 2026-07-31
Get a test suite that targets edge cases and regressions, not a mirror of the implementation
A standalone test-generation prompt for Copilot Chat that forces a deliberate enumeration of edge cases, boundary values, and failure modes before any test is written, so the suite catches what the code might get wrong instead of restating what it currently does.
The prompt
Ready to copy — highlighted parts are example details you can swap.
Generate a test suite for the applyLateFee function in lib/billing/late-fees.ts using Vitest. Before writing a single test, list the specific edge cases and failure modes this needs coverage for — do not start from the happy path and pad outward from there, since that produces a suite that mirrors what the code does on typical input rather than one that checks what happens when input stops being typical. WHAT THIS CURRENTLY DOES Calculates a flat 5% late fee on any invoice more than 30 days overdue, rounded to two decimal places. EDGE CASES ALREADY KNOWN TO MATTER An invoice paid exactly on day 30 (should not incur a fee); an invoice with a zero balance. TEST FRAMEWORK Vitest COVERAGE GOAL No specific percentage target — the goal is catching every boundary and shared-state case, not hitting a coverage number. WORK IN THIS ORDER 1. List every edge case you can identify from the actual signature and logic of the applyLateFee function in lib/billing/late-fees.ts — empty input, a single-element input, the largest and smallest plausible values, a value at exactly a boundary condition used in a comparison, null or undefined where the type allows it, a duplicate or out-of-order input if ordering matters, and a concurrent or repeated call if state is shared across calls. Do not stop at the ones already listed in An invoice paid exactly on day 30 (should not incur a fee); an invoice with a zero balance. — that list is a floor, not the ceiling. 2. For each edge case listed, state in one sentence what the correct behavior should be and why — derived from reading Calculates a flat 5% late fee on any invoice more than 30 days overdue, rounded to two decimal places. and the actual code, not assumed from what would be reasonable in the abstract, since the actual required behavior sometimes differs from what seems reasonable and that gap is exactly what a test should catch if the code disagrees with the stated correct behavior. 3. Only after step 2 is complete, write the tests — one test per edge case identified, each named for the specific case it covers rather than a generic name like 'handles edge case,' so a failing test tells a future reader what broke without them having to read the test body first. 4. Add one test explicitly for the happy path last, not first — it is the case least likely to be wrong and least valuable to write first, and writing it last keeps attention on the edge cases while they are still being actively reasoned about. CONSTRAINTS - If an edge case you identified in step 1 reveals that the current implementation's actual behavior is genuinely wrong, say so explicitly rather than writing a test that just asserts whatever the code currently does — a test asserting a bug is a trap for the next person who fixes it and watches a passing test start failing for the right reason. - Do not generate a test for a case that cannot actually occur given the function's real type signature — a test for a null input on a parameter TypeScript's own types already make impossible is not coverage, it is noise that makes the suite look more thorough than it is. - If No specific percentage target — the goal is catching every boundary and shared-state case, not hitting a coverage number. names a specific percentage or line-coverage target, do not treat hitting that number as the actual goal — a suite that hits 90% line coverage by exercising every line once with typical input has covered less of the real risk than a smaller suite built from a genuine edge-case list.
Customize
Optional — swap in your own details for the highlighted parts above.
Why this works
The enumerate-before-write ordering directly counters the default pattern in AI-assisted test generation, which is to pattern-match to typical input plus one or two obvious cases and call that thorough — a test suite generated without a separate enumeration step tends to mirror the implementation's own happy-path behavior back as assertions, which proves the code does what it does today without ever probing whether what it does today is actually correct at the boundaries. The instruction to flag a genuinely wrong behavior discovered during enumeration, rather than writing a test that asserts it, targets a specific and real failure mode of AI-generated tests written against a possibly-wrong implementation with no independent correctness check: a test asserting a bug passes cleanly right up until someone fixes the underlying bug, at which point a test that was supposed to provide safety starts failing for exactly the reason it should have caught the bug in the first place, and by then it reads as if the fix broke something rather than fixed something. Filtering out edge cases the function's real type signature already makes impossible is a genuinely actionable check in a strictly typed codebase specifically — a test asserting behavior for a null value on a parameter typed to exclude null is not defensive coverage, it is noise dressed as thoroughness, and it dilutes a reader's sense of which tests in the suite are protecting against a real, reachable input versus one that can never occur. The line-coverage-number warning addresses a documented and specific way test suites get gamed, intentionally or not: a suite can hit a high line-coverage percentage by exercising every line exactly once with typical input, which tells you every line ran, not that every line was checked against a case where it could plausibly be wrong — coverage percentage and actual risk coverage are correlated but very much not the same measurement, and optimizing for the number that is easy to display trades away the one that is actually protective.
Verified against
GitHub Copilot Chat Copilot Chat 1.270 (VS Code) · 2026-07-31
Changelog
- 2026-07-31 — Initial publish, verified against Copilot Chat 1.270 (VS Code).
Need this built into your business?
If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.
EXPLORE CUSTOM SOFTWARE
