test(06-02): add failing tests for RRULE UNTIL/COUNT + FREQ persistence
- vevent.test.ts: add COUNT, UNTIL-DATE, UNTIL-DATETIME serialization assertions - outboxWorker.test.ts: add assembleRruleString (D-06) describe block (not yet exported) - outboxWorker.test.ts: add FREQ persistence (D-07 regression) describe block - RED: assembleRruleString not yet exported; FREQ-persistence cases fail on missing helper
This commit is contained in:
@@ -18,7 +18,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
// This import fails (RED) — broker/outboxWorker.ts does not exist yet.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore intentional RED import
|
||||
import { runOutboxDrain } from '../../src/broker/outboxWorker.js'
|
||||
import { runOutboxDrain, assembleRruleString } from '../../src/broker/outboxWorker.js'
|
||||
|
||||
// ── Drizzle DB mock ────────────────────────────────────────────────────────
|
||||
// Follows the pattern from PATTERNS.md §Drizzle DB mock in tests.
|
||||
@@ -647,3 +647,69 @@ describe('runOutboxDrain — fail closed on bad credentials (CR-03) + backoff in
|
||||
expect(setArg?.nextAttemptAt?.getTime()).toBeLessThanOrEqual(expectedMaxMs)
|
||||
})
|
||||
})
|
||||
|
||||
// ─── D-06: assembleRruleString unit tests ─────────────────────────────────────
|
||||
// These tests import the NOT-YET-EXPORTED `assembleRruleString` helper.
|
||||
// RED: will fail because assembleRruleString is not exported yet.
|
||||
|
||||
describe('assembleRruleString (D-06)', () => {
|
||||
it('returns base preset unchanged when no bound given', () => {
|
||||
expect(assembleRruleString('FREQ=DAILY')).toBe('FREQ=DAILY')
|
||||
})
|
||||
|
||||
it('appends COUNT when count is given (count wins over until)', () => {
|
||||
expect(assembleRruleString('FREQ=DAILY', undefined, 5, false)).toBe('FREQ=DAILY;COUNT=5')
|
||||
})
|
||||
|
||||
it('COUNT wins when both until and count are provided (mutual exclusion, RFC 5545 §3.3.10)', () => {
|
||||
expect(assembleRruleString('FREQ=WEEKLY', '2026-06-30', 5, false)).toBe('FREQ=WEEKLY;COUNT=5')
|
||||
})
|
||||
|
||||
it('appends UNTIL as DATE form (YYYYMMDD) for all-day events', () => {
|
||||
expect(assembleRruleString('FREQ=WEEKLY', '2026-06-30', undefined, true)).toBe('FREQ=WEEKLY;UNTIL=20260630')
|
||||
})
|
||||
|
||||
it('appends UNTIL as DATETIME UTC form (YYYYMMDDTHHMMSSZ) for timed events', () => {
|
||||
expect(assembleRruleString('FREQ=WEEKLY', '2026-06-30', undefined, false)).toBe('FREQ=WEEKLY;UNTIL=20260630T235959Z')
|
||||
})
|
||||
|
||||
it('COUNT=5 appended to FREQ=DAILY (matches plan behavior assertion)', () => {
|
||||
expect(assembleRruleString('FREQ=DAILY', undefined, 5, false)).toBe('FREQ=DAILY;COUNT=5')
|
||||
})
|
||||
})
|
||||
|
||||
// ─── D-07: FREQ-persistence regression lock ────────────────────────────────────
|
||||
// RED: will fail because the outbox worker does not yet wire recurrenceUntil/recurrenceCount
|
||||
// and the FREQ-persistence assertion catches the D-07 regression scenario.
|
||||
|
||||
describe('FREQ persistence (D-07 regression)', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks()
|
||||
mockPendingRows = []
|
||||
wireMockChain()
|
||||
})
|
||||
|
||||
it('D-07: daily-recurrence payload assembles to FREQ=DAILY (not weekly or none) in emitted ICS', async () => {
|
||||
const { createCalendarEvent } = await import('../../src/broker/write.js')
|
||||
let capturedIcsString: unknown = null
|
||||
vi.mocked(createCalendarEvent).mockImplementation(async (_client, _cal, _uid, icsString) => {
|
||||
capturedIcsString = icsString
|
||||
return makeResponse(201)
|
||||
})
|
||||
const dailyPayload = JSON.stringify({
|
||||
title: 'Daily standup',
|
||||
allDay: false,
|
||||
start: '2026-06-10T09:00:00',
|
||||
end: '2026-06-10T09:30:00',
|
||||
recurrence: 'daily',
|
||||
})
|
||||
mockPendingRows = [makeRow({ payload: dailyPayload })]
|
||||
|
||||
await runOutboxDrain()
|
||||
|
||||
expect(typeof capturedIcsString).toBe('string')
|
||||
// D-07: FREQ must be DAILY — not WEEKLY or absent
|
||||
expect(capturedIcsString as string).toContain('RRULE:FREQ=DAILY')
|
||||
expect(capturedIcsString as string).not.toContain('FREQ=WEEKLY')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user