test(03-09): add RED contract tests for canonical title/start/end client payload
- POST /create with {title,start,end,allDay,recurrence} asserts 202 (fails: server requires summary/dtstart/dtend)
- PATCH /:uid/edit with same shape asserts 202 (fails: same schema mismatch CR-01)
This commit is contained in:
@@ -446,6 +446,85 @@ describe('GET /api/events/sync-status', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// CR-01 contract tests — canonical client payload shape (title/start/end)
|
||||||
|
//
|
||||||
|
// The PWA sends {title, start, end, allDay, recurrence} — the exact
|
||||||
|
// CreateEventPayload shape from apps/pwa/src/api/client.ts:119-128.
|
||||||
|
// These tests assert the server schema accepts that shape (202), NOT 400.
|
||||||
|
// RED before Task 1 schema rename; GREEN after.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
describe('CR-01: canonical client payload (title/start/end) accepted by server', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Seed a calendar row for calendar ownership check in create
|
||||||
|
mockDbRows = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
url: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/',
|
||||||
|
displayName: 'Default',
|
||||||
|
color: '#4A90D9',
|
||||||
|
userId: 1,
|
||||||
|
isShared: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const mockSimpleWhere = vi.fn().mockImplementation(() => Promise.resolve(mockDbRows))
|
||||||
|
mockFromFn.mockReturnValue({ where: mockSimpleWhere })
|
||||||
|
mockSelectFn.mockReturnValue({ from: mockFromFn })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('POST /create with exact CreateEventPayload shape {title,start,end,allDay,recurrence} returns 202 not 400', async () => {
|
||||||
|
// This mirrors the exact payload apps/pwa/src/api/client.ts CreateEventPayload sends
|
||||||
|
const { app } = await import('../../src/index.js')
|
||||||
|
const res = await app.request('/api/events/create', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
title: 'Team standup',
|
||||||
|
allDay: false,
|
||||||
|
start: '2026-06-15T10:00:00Z',
|
||||||
|
end: '2026-06-15T10:30:00Z',
|
||||||
|
recurrence: 'none',
|
||||||
|
calendarUrl: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(202)
|
||||||
|
const body = await res.json() as { uid: string }
|
||||||
|
expect(body).toHaveProperty('uid')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('PATCH /:uid/edit with exact CreateEventPayload shape {title,start,end,allDay,recurrence} returns 202 not 400', async () => {
|
||||||
|
// Seed an event row for edit lookup
|
||||||
|
mockDbRows = [
|
||||||
|
{
|
||||||
|
uid: 'uid-cr01@familysync',
|
||||||
|
etag: '"etag-cr01"',
|
||||||
|
objectUrl: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/uid-cr01.ics',
|
||||||
|
calendarId: 1,
|
||||||
|
calendarUrl: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/',
|
||||||
|
userId: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const mockSimpleWhere = vi.fn().mockImplementation(() => Promise.resolve(mockDbRows))
|
||||||
|
mockFromFn.mockReturnValue({ where: mockSimpleWhere })
|
||||||
|
mockSelectFn.mockReturnValue({ from: mockFromFn })
|
||||||
|
|
||||||
|
const { app } = await import('../../src/index.js')
|
||||||
|
const res = await app.request('/api/events/uid-cr01%40familysync/edit', {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
title: 'Updated standup',
|
||||||
|
allDay: false,
|
||||||
|
start: '2026-06-15T10:00:00Z',
|
||||||
|
end: '2026-06-15T10:30:00Z',
|
||||||
|
recurrence: 'weekly',
|
||||||
|
calendarUrl: 'https://caldav.fastmail.com/dav/calendars/user/test@fm.com/Default/',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(202)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// GET /api/events/writable-calendars
|
// GET /api/events/writable-calendars
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user