test(11-05): RED — CR-01 custom alarm round-trip
- expand.test.ts: 3 new tests asserting reminderIsCustom:true for absolute DATE-TIME trigger and multi-VALARM, false for relative preset - EventForm.test.tsx: 3 new tests asserting __custom__ picker init, 'Custom (kept)' option visibility, and payload omits reminderLeadMinutes - Fixtures: absolute-alarm.ics (DATE-TIME VALARM), multi-alarm.ics (2 VALARMs) - All 6 new tests FAIL (RED): reminderIsCustom field not yet on interface
This commit is contained in:
@@ -1231,3 +1231,94 @@ describe('EventForm — Phase 11 reminder picker (Plan 04)', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ── Phase 11 Plan 05: CR-01 custom alarm round-trip (TDD RED) ─────────────────
|
||||
|
||||
/**
|
||||
* Fixture: edit occurrence with reminderIsCustom:true (absolute DATE-TIME or multi-VALARM).
|
||||
* This field is added by Plan 05 — before the fix, CalendarOccurrence does not carry it,
|
||||
* so the form cannot distinguish custom from no-reminder.
|
||||
*/
|
||||
const CUSTOM_ALARM_OCCURRENCE: CalendarOccurrence & { reminderIsCustom?: boolean } = {
|
||||
id: 'custom-alarm-uid::2026-12-15',
|
||||
uid: 'custom-alarm-uid',
|
||||
calendarId: 1,
|
||||
calendarName: 'My Calendar',
|
||||
ownerUserId: 1,
|
||||
ownerName: 'Alice',
|
||||
color: '#4A90D9',
|
||||
isShared: false,
|
||||
title: 'Holiday Party',
|
||||
start: '2026-12-15',
|
||||
end: '2026-12-16',
|
||||
allDay: true,
|
||||
location: null,
|
||||
description: null,
|
||||
hasRrule: false,
|
||||
reminderLeadMinutes: null, // custom alarms cannot be reduced to a lead
|
||||
reminderIsCustom: true, // CR-01 new field: signals absolute/multi alarm
|
||||
};
|
||||
|
||||
describe('EventForm — Phase 11 Plan 05 CR-01: custom alarm round-trip', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockEventFormOpen = true;
|
||||
mockEventFormMode = 'create';
|
||||
mockEventFormUid = null;
|
||||
});
|
||||
|
||||
it('CR-01: edit with reminderIsCustom=true initializes picker to __custom__ (not __none__)', () => {
|
||||
// Before the fix: occurrence.reminderIsCustom does not exist; deriveReminderValue(null, ...)
|
||||
// returns '__none__'. This test MUST FAIL before the fix.
|
||||
renderForm({
|
||||
mode: 'edit',
|
||||
uid: 'custom-alarm-uid',
|
||||
eventOccurrence: CUSTOM_ALARM_OCCURRENCE as CalendarOccurrence,
|
||||
});
|
||||
|
||||
const reminderSelect = document.querySelector('#event-reminder') as HTMLSelectElement;
|
||||
expect(reminderSelect).not.toBeNull();
|
||||
// Must be __custom__, NOT __none__ (the pre-fix incorrect value)
|
||||
expect(reminderSelect.value).toBe('__custom__');
|
||||
});
|
||||
|
||||
it('CR-01: Custom (kept) disabled option is visible when reminderIsCustom=true', () => {
|
||||
renderForm({
|
||||
mode: 'edit',
|
||||
uid: 'custom-alarm-uid',
|
||||
eventOccurrence: CUSTOM_ALARM_OCCURRENCE as CalendarOccurrence,
|
||||
});
|
||||
|
||||
// The read-only "Custom (kept)" option must be visible
|
||||
const customOption = screen.queryByText('Custom (kept)');
|
||||
expect(customOption).not.toBeNull();
|
||||
});
|
||||
|
||||
it('CR-01: submitting in __custom__ state omits reminderLeadMinutes from payload (D-08 preserve)', async () => {
|
||||
// The critical data-loss test: edit a custom-alarm event, change the title, save.
|
||||
// The payload must NOT include reminderLeadMinutes (field absent = preserve VALARM).
|
||||
renderForm({
|
||||
mode: 'edit',
|
||||
uid: 'custom-alarm-uid',
|
||||
eventOccurrence: CUSTOM_ALARM_OCCURRENCE as CalendarOccurrence,
|
||||
});
|
||||
|
||||
// Change the title to simulate a real edit
|
||||
fireEvent.change(screen.getByPlaceholderText('Event title'), {
|
||||
target: { value: 'Holiday Party (Updated)' },
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText('Save Changes'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpdateEvent).toHaveBeenCalled();
|
||||
const callPayload = mockUpdateEvent.mock.calls[0][1] as Record<string, unknown>;
|
||||
// MUST be absent: the presence of reminderLeadMinutes:null would cause the outbox
|
||||
// worker to clear the VALARM — the CR-01 data-loss bug.
|
||||
expect(Object.prototype.hasOwnProperty.call(callPayload, 'reminderLeadMinutes')).toBe(
|
||||
false,
|
||||
'reminderLeadMinutes must be absent from payload when alarm is custom (D-08 preserve path)',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user