From 4d37dff9f87c5e4bf266d6dfdcaa9a41b7cd26bf Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:46:11 +0200 Subject: [PATCH] ui(alerts): RED tests for form-state fireMode toggle clearing Three failing tests pinning Task 4.3's mode-toggle state hygiene: - clears threshold+windowSeconds on COUNT_IN_WINDOW -> PER_EXCHANGE - returns to defaults (not stale values) on PER_EXCHANGE -> COUNT_IN_WINDOW - forces reNotifyMinutes=0 and forDurationSeconds=0 on PER_EXCHANGE Targets a to-be-introduced pure helper `applyFireModeChange(form, newMode)` in form-state.ts. Task 4.3 will implement the helper and wire it into ExchangeMatchForm so the Fire-mode will call in place of the current +// raw `patch({ fireMode })`. It must guarantee: +// +// - Switching to PER_EXCHANGE clears COUNT_IN_WINDOW-only fields +// (condition.threshold, condition.windowSeconds) AND forces +// top-level reNotifyMinutes = 0, forDurationSeconds = 0. PER_EXCHANGE +// is exactly-once-per-exchange — re-notify cadence and hold-duration +// are semantically meaningless and must not leak into toRequest(). +// - Switching back to COUNT_IN_WINDOW resets to defaults (zero), never +// restoring stale values from the previous COUNT_IN_WINDOW session. +// +// These tests will fail until Task 4.3 introduces the helper. +// ---------------------------------------------------------------------------- +describe('applyFireModeChange (fire-mode toggle hygiene)', () => { + const exchangeMatchForm = () => { + const f = initialForm(); + f.conditionKind = 'EXCHANGE_MATCH'; + f.condition = { + kind: 'EXCHANGE_MATCH', + scope: {}, + fireMode: 'COUNT_IN_WINDOW', + } as unknown as typeof f.condition; + return f; + }; + + it('clears COUNT_IN_WINDOW fields when switching to PER_EXCHANGE', () => { + let f = exchangeMatchForm(); + // Simulate a user who filled in COUNT_IN_WINDOW fields first. + f.condition = { + ...(f.condition as Record), + threshold: 5, + windowSeconds: 300, + } as typeof f.condition; + + f = applyFireModeChange(f, 'PER_EXCHANGE'); + + const c = f.condition as Record; + expect(c.fireMode).toBe('PER_EXCHANGE'); + expect(c.threshold ?? 0).toBe(0); + expect(c.windowSeconds ?? 0).toBe(0); + }); + + it('resets to defaults (not stale values) when switching back to COUNT_IN_WINDOW', () => { + let f = exchangeMatchForm(); + f.condition = { + ...(f.condition as Record), + threshold: 5, + windowSeconds: 300, + } as typeof f.condition; + + f = applyFireModeChange(f, 'PER_EXCHANGE'); + f = applyFireModeChange(f, 'COUNT_IN_WINDOW'); + + const c = f.condition as Record; + expect(c.fireMode).toBe('COUNT_IN_WINDOW'); + // Must be fresh defaults, not the stale 5 / 300 the user typed before. + expect(c.threshold ?? 0).toBe(0); + expect(c.windowSeconds ?? 0).toBe(0); + }); + + it('forces reNotifyMinutes=0 and forDurationSeconds=0 when switching to PER_EXCHANGE', () => { + let f = exchangeMatchForm(); + f.reNotifyMinutes = 60; + f.forDurationSeconds = 120; + + f = applyFireModeChange(f, 'PER_EXCHANGE'); + + expect(f.reNotifyMinutes).toBe(0); + expect(f.forDurationSeconds).toBe(0); + }); +});