$npx -y skills add tody-agent/codymaster --skill cm-tddUse when implementing any feature or bugfix, before writing implementation code
| 1 | # Test-Driven Development (TDD) |
| 2 | |
| 3 | ## TL;DR |
| 4 | - **Use when** writing or fixing any feature/bugfix |
| 5 | - **Cycle**: red (failing test) → green (minimal code) → refactor |
| 6 | - **No prod code** without a failing test first |
| 7 | - **Next**: cm-execution or cm-code-review |
| 8 | |
| 9 | ## Overview |
| 10 | |
| 11 | Write the test first. Watch it fail. Write minimal code to pass. |
| 12 | |
| 13 | **Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing. |
| 14 | |
| 15 | **Violating the letter of the rules is violating the spirit of the rules.** |
| 16 | |
| 17 | ## When to Use |
| 18 | |
| 19 | **Always:** |
| 20 | |
| 21 | - New features |
| 22 | - Bug fixes |
| 23 | - Refactoring |
| 24 | - Behavior changes |
| 25 | |
| 26 | **Exceptions (ask your human partner):** |
| 27 | |
| 28 | - Throwaway prototypes |
| 29 | - Generated code |
| 30 | - Configuration files |
| 31 | |
| 32 | Thinking "skip TDD just this once"? Stop. That's rationalization. |
| 33 | |
| 34 | ## The Iron Law |
| 35 | |
| 36 | ``` |
| 37 | NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST |
| 38 | ``` |
| 39 | |
| 40 | Write code before the test? Delete it. Start over. |
| 41 | |
| 42 | **No exceptions:** |
| 43 | |
| 44 | - Don't keep it as "reference" |
| 45 | - Don't "adapt" it while writing tests |
| 46 | - Don't look at it |
| 47 | - Delete means delete |
| 48 | |
| 49 | Implement fresh from tests. Period. |
| 50 | |
| 51 | ## Red-Green-Refactor |
| 52 | |
| 53 | ```dot |
| 54 | digraph tdd_cycle { |
| 55 | rankdir=LR; |
| 56 | red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"]; |
| 57 | verify_red [label="Verify fails\ncorrectly", shape=diamond]; |
| 58 | green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"]; |
| 59 | verify_green [label="Verify passes\nAll green", shape=diamond]; |
| 60 | refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"]; |
| 61 | next [label="Next", shape=ellipse]; |
| 62 | |
| 63 | red -> verify_red; |
| 64 | verify_red -> green [label="yes"]; |
| 65 | verify_red -> red [label="wrong\nfailure"]; |
| 66 | green -> verify_green; |
| 67 | verify_green -> refactor [label="yes"]; |
| 68 | verify_green -> green [label="no"]; |
| 69 | refactor -> verify_green [label="stay\ngreen"]; |
| 70 | verify_green -> next; |
| 71 | next -> red; |
| 72 | } |
| 73 | ``` |
| 74 | |
| 75 | ### Step 0: Check Working Memory |
| 76 | |
| 77 | Before writing ANY test, check `.cm/CONTINUITY.md`: |
| 78 | |
| 79 | - **"Mistakes & Learnings"** → Are there known edge cases for this area? |
| 80 | - **"Working Context"** → What patterns/conventions are being followed? |
| 81 | - **"Key Decisions"** → Any architecture choices that affect test design? |
| 82 | |
| 83 | > **Token savings:** Writes better tests on first try by knowing past failures. |
| 84 | > **Quality boost:** Tests cover edge cases that caused bugs before. |
| 85 | |
| 86 | ### RED - Write Failing Test |
| 87 | |
| 88 | Write one minimal test showing what should happen. |
| 89 | |
| 90 | ```typescript test('retries failed operations 3 times', async () => { let attempts = 0; const operation = () => { attempts++; if (attempts < 3) throw new Error('fail'); return 'success'; }; |
| 91 | |
| 92 | const result = await retryOperation(operation); |
| 93 | |
| 94 | expect(result).toBe('success'); |
| 95 | expect(attempts).toBe(3); |
| 96 | }); |
| 97 | |
| 98 | ``` |
| 99 | Clear name, tests real behavior, one thing |
| 100 | </Good> |
| 101 | |
| 102 | <Bad> |
| 103 | ```typescript |
| 104 | test('retry works', async () => { |
| 105 | const mock = jest.fn() |
| 106 | .mockRejectedValueOnce(new Error()) |
| 107 | .mockRejectedValueOnce(new Error()) |
| 108 | .mockResolvedValueOnce('success'); |
| 109 | await retryOperation(mock); |
| 110 | expect(mock).toHaveBeenCalledTimes(3); |
| 111 | }); |
| 112 | ``` |
| 113 | |
| 114 | Vague name, tests mock not code |
| 115 | |
| 116 | |
| 117 | **Requirements:** |
| 118 | |
| 119 | - One behavior |
| 120 | - Clear name |
| 121 | - Real code (no mocks unless unavoidable) |
| 122 | |
| 123 | ### Verify RED - Watch It Fail |
| 124 | |
| 125 | **MANDATORY. Never skip.** |
| 126 | |
| 127 | ```bash |
| 128 | npm test path/to/test.test.ts |
| 129 | ``` |
| 130 | |
| 131 | Confirm: |
| 132 | |
| 133 | - Test fails (not errors) |
| 134 | - Failure message is expected |
| 135 | - Fails because feature missing (not typos) |
| 136 | |
| 137 | **Test passes?** You're testing existing behavior. Fix test. |
| 138 | |
| 139 | **Test errors?** Fix error, re-run until it fails correctly. |
| 140 | |
| 141 | ### GREEN - Minimal Code |
| 142 | |
| 143 | Write simplest code to pass the test. |
| 144 | |
| 145 | ```typescript async function retryOperation(fn: () => Promise): Promise { for (let i = 0; i < 3; i++) { try { return await fn(); } catch (e) { if (i === 2) throw e; } } throw new Error('unreachable'); } ``` Just enough to pass |
| 146 | |
| 147 | ```typescript async function retryOperation( fn: () => Promise, options?: { maxRetries?: number; backoff?: 'linear' | 'exponential'; onRetry?: (attempt: number) => void; } ): Promise { // YAGNI } ``` Over-engineered |
| 148 | |
| 149 | Don't add features, refactor other code, or "improve" beyond the test. |
| 150 | |
| 151 | ### Verify GREEN - Watch It Pass |
| 152 | |
| 153 | **MANDATORY.** |
| 154 | |
| 155 | ```bash |
| 156 | npm test path/to/test.test.ts |
| 157 | ``` |
| 158 | |
| 159 | Confirm: |
| 160 | |
| 161 | - Test passes |
| 162 | - Other tests still pass |
| 163 | - Output pristine (no errors, warnings) |
| 164 | |
| 165 | **Test fails?** Fix code, not test. |
| 166 | |
| 167 | **Other tests fail?** Fix now. |
| 168 | |
| 169 | ### REFACTOR - Clean Up |
| 170 | |
| 171 | After green only: |
| 172 | |
| 173 | - Remove duplication |
| 174 | - Improve names |
| 175 | - Extract helpers |
| 176 | |
| 177 | Keep tests green. Don't add behavior. |
| 178 | |
| 179 | ### Repeat |
| 180 | |
| 181 | Next failing test for next feature. |
| 182 | |
| 183 | ## Good Tests |
| 184 | |
| 185 | |
| 186 | | Quality | Good | Bad | |
| 187 | | ---------------- | ----------------------------------- | --------------------------------------------------- | |
| 188 | | **Minimal** | One thing |