* Start a TDD cycle for testName. In loop mode, also links the cycle to * the currently-active requirement (or the first pending one if none active).
(testName)
| 211 | * the currently-active requirement (or the first pending one if none active). |
| 212 | */ |
| 213 | beginCycle(testName) { |
| 214 | if (this.disabled) return { ok: true, phase: 'idle', message: 'TDD gating disabled.' }; |
| 215 | if (!testName || typeof testName !== 'string' || !testName.trim()) { |
| 216 | return { ok: false, phase: this._phase, message: 'beginCycle requires a non-empty testName.' }; |
| 217 | } |
| 218 | |
| 219 | // In loop mode, mark the associated requirement as active |
| 220 | if (this._loopActive) { |
| 221 | const activeReq = this.activeRequirement(); |
| 222 | if (!activeReq) { |
| 223 | // Try to activate the first pending requirement |
| 224 | const first = this._requirements.find(r => r.status === REQ_STATUS.PENDING); |
| 225 | if (first) first.status = REQ_STATUS.ACTIVE; |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | this._phase = PHASES.RED; |
| 230 | this._targetTest = testName.trim(); |
| 231 | this._redConfirmed = false; |
| 232 | this._cycleId = (this._cycleId || 0) + 1; |
| 233 | this._startedAt = new Date().toISOString(); |
| 234 | this._save(); |
| 235 | |
| 236 | return { |
| 237 | ok: true, |
| 238 | phase: PHASES.RED, |
| 239 | message: `TDD cycle started for "${this._targetTest}". Call run_tests (with test_filter "${this._targetTest}") to confirm it fails (RED phase).`, |
| 240 | }; |
| 241 | } |
| 242 | |
| 243 | confirmRed(testResult) { |
| 244 | if (this.disabled) return { ok: true, phase: 'idle', message: 'TDD gating disabled.' }; |