/** * RED test scaffold: broker/write.ts — tsdav PUT/DELETE wrappers (CAL-04, CAL-05, CAL-06) * * Behaviors under test: * 1. createCalendarEvent calls client.createCalendarObject with `${uid}.ics` filename * 2. updateCalendarEvent passes etag into the calendarObject (If-Match for D-08) * 3. deleteCalendarEvent passes etag into the calendarObject (If-Match for D-08) * 4. Each returns the raw Response from the tsdav client mock * * These tests FAIL (RED) because broker/write.ts does not exist yet. * They will turn GREEN in Plan 03-02 when the implementation is added. */ import { describe, it, expect, vi } from 'vitest' // This import fails (RED) — broker/write.ts does not exist yet. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore intentional RED import import { createCalendarEvent, updateCalendarEvent, deleteCalendarEvent, } from '../../src/broker/write.js' const makeMockResponse = (status: number): Response => ({ status, ok: status >= 200 && status < 300, headers: new Headers() }) as unknown as Response describe('createCalendarEvent', () => { it('calls client.createCalendarObject with uid.ics filename', async () => { const mockClient = { createCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(201)), } const mockCalendar = { url: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/' } const uid = 'abc-123@familysync' const icsString = 'BEGIN:VCALENDAR\r\nEND:VCALENDAR' const result = await createCalendarEvent(mockClient as never, mockCalendar as never, uid, icsString) expect(mockClient.createCalendarObject).toHaveBeenCalledWith({ calendar: mockCalendar, filename: `${uid}.ics`, iCalString: icsString, }) expect(result.status).toBe(201) }) it('returns the raw Response from client', async () => { const mockClient = { createCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(204)), } const mockCalendar = { url: 'https://caldav.fastmail.com/' } const result = await createCalendarEvent(mockClient as never, mockCalendar as never, 'uid@fs', 'ICS') expect(result).toBeDefined() expect(result.status).toBe(204) }) }) describe('updateCalendarEvent', () => { it('calls client.updateCalendarObject with etag in calendarObject (If-Match)', async () => { const mockClient = { updateCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(204)), } const calendarObjectUrl = 'https://caldav.fastmail.com/dav/calendars/user/test/Default/uid.ics' const icsString = 'BEGIN:VCALENDAR\r\nEND:VCALENDAR' const etag = '"etag-123"' const result = await updateCalendarEvent(mockClient as never, calendarObjectUrl, icsString, etag) expect(mockClient.updateCalendarObject).toHaveBeenCalledWith({ calendarObject: { url: calendarObjectUrl, data: icsString, etag, }, }) expect(result.status).toBe(204) }) it('passes empty string as etag when etag is null (safe for If-Match)', async () => { const mockClient = { updateCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(204)), } await updateCalendarEvent(mockClient as never, 'https://caldav.fastmail.com/uid.ics', 'ICS', null) const callArg = mockClient.updateCalendarObject.mock.calls[0][0] expect(callArg.calendarObject.etag).toBe('') }) }) describe('deleteCalendarEvent', () => { it('calls client.deleteCalendarObject with etag in calendarObject (If-Match)', async () => { const mockClient = { deleteCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(204)), } const calendarObjectUrl = 'https://caldav.fastmail.com/dav/calendars/user/test/Default/uid.ics' const etag = '"etag-456"' const result = await deleteCalendarEvent(mockClient as never, calendarObjectUrl, etag) expect(mockClient.deleteCalendarObject).toHaveBeenCalledWith({ calendarObject: { url: calendarObjectUrl, data: '', etag, }, }) expect(result.status).toBe(204) }) it('passes empty string as etag when etag is null', async () => { const mockClient = { deleteCalendarObject: vi.fn().mockResolvedValue(makeMockResponse(204)), } await deleteCalendarEvent(mockClient as never, 'https://caldav.fastmail.com/uid.ics', null) const callArg = mockClient.deleteCalendarObject.mock.calls[0][0] expect(callArg.calendarObject.etag).toBe('') }) })