Milestone v1.0: FamilySync MVP #1

Merged
luckberg merged 376 commits from gsd/v1.0-milestone into main 2026-06-10 17:39:19 -04:00
Showing only changes of commit 931f767922 - Show all commits
+50
View File
@@ -448,6 +448,56 @@ describe('PATCH /api/lists/:id (authorized update)', () => {
const body = await res.json() as { name: string }
expect(body.name).toBe('Sharee Renamed')
})
it('T-04-08: sharee sending { isShared: false } gets 403 and list_shares is unchanged', async () => {
const ownerId = await seedUser('t04-08-owner')
const shareeId = await seedUser('t04-08-sharee')
const listId = await seedList(ownerId, 'T04-08 Shared List', true)
await shareList(listId, shareeId)
// Act as sharee
currentDevUserId = shareeId
const app = await getApp()
// Sharee tries to set isShared: false — must be blocked
const res = await app.request(jsonRequest('PATCH', `/api/lists/${listId}`, { isShared: false }))
expect(res.status).toBe(403)
const body = await res.json() as { error: string }
// Response should mention owner/sharing
expect(body.error).toMatch(/owner|shar/i)
// Prove list_shares is untouched — sharee row still exists
const { and, eq } = await import('drizzle-orm')
const shares = await db.select().from(listShares).where(
and(eq(listShares.listId, listId), eq(listShares.userId, shareeId)),
)
expect(shares.length).toBe(1)
})
it('T-04-08: sharee sending { isShared: true } gets 403 and no new shares are inserted', async () => {
const ownerId = await seedUser('t04-08-true-owner')
const shareeId = await seedUser('t04-08-true-sharee')
// Private list (isShared: false) but sharee already has explicit access
const listId = await seedList(ownerId, 'T04-08 Private List', false)
await shareList(listId, shareeId)
// Act as sharee
currentDevUserId = shareeId
const app = await getApp()
// Record share count before the attempted mutation
const { eq } = await import('drizzle-orm')
const beforeShares = await db.select().from(listShares).where(eq(listShares.listId, listId))
const beforeCount = beforeShares.length
// Sharee tries to set isShared: true — must be blocked
const res = await app.request(jsonRequest('PATCH', `/api/lists/${listId}`, { isShared: true }))
expect(res.status).toBe(403)
// Prove no new shares were inserted
const afterShares = await db.select().from(listShares).where(eq(listShares.listId, listId))
expect(afterShares.length).toBe(beforeCount)
})
})
// ---------------------------------------------------------------------------