feat(db): phase 4 group 1 — lib/ settings + notifications to Drizzle
Convert lib/settings.ts, lib/notifications/{in-app,email,capa-escalation,
effectiveness-recheck}.ts from Supabase PostgREST to Drizzle asAdmin queries.
Drop supabase arg from all call sites in app/api/ and cron routes. Rewrite
notification unit tests to mock @/lib/db/with-user instead of SupabaseClient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,60 +1,58 @@
|
||||
// @vitest-environment node
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { createInAppNotifications } from '@/lib/notifications/in-app'
|
||||
import type { SupabaseClient } from '@supabase/supabase-js'
|
||||
|
||||
function makeSupabaseMock(rpcResult: { error: unknown } = { error: null }) {
|
||||
return {
|
||||
rpc: vi.fn().mockResolvedValue(rpcResult),
|
||||
} as unknown as SupabaseClient
|
||||
}
|
||||
// Mock asAdmin before importing the module under test
|
||||
const mockInsert = vi.fn()
|
||||
const mockValues = vi.fn().mockResolvedValue([])
|
||||
vi.mock('@/lib/db/with-user', () => ({
|
||||
asAdmin: vi.fn().mockImplementation(fn =>
|
||||
fn({
|
||||
insert: mockInsert.mockReturnValue({ values: mockValues }),
|
||||
})
|
||||
),
|
||||
}))
|
||||
|
||||
import { createInAppNotifications } from '@/lib/notifications/in-app'
|
||||
|
||||
describe('createInAppNotifications', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockInsert.mockReturnValue({ values: mockValues })
|
||||
mockValues.mockResolvedValue([])
|
||||
})
|
||||
|
||||
it('calls create_in_app_notification RPC once per recipient', async () => {
|
||||
const supabase = makeSupabaseMock()
|
||||
const { created } = await createInAppNotifications(supabase, [
|
||||
it('inserts once per recipient', async () => {
|
||||
const { created } = await createInAppNotifications([
|
||||
{ userId: 'u1', title: 'New incident', link: '/hse/incidents/i1', incidentId: 'i1' },
|
||||
{ userId: 'u2', title: 'New incident', link: '/hse/incidents/i1', incidentId: 'i1' },
|
||||
])
|
||||
expect(created).toBe(2)
|
||||
expect(supabase.rpc).toHaveBeenCalledTimes(2)
|
||||
expect(supabase.rpc).toHaveBeenCalledWith('create_in_app_notification', {
|
||||
p_recipient: 'u1',
|
||||
p_title: 'New incident',
|
||||
p_link: '/hse/incidents/i1',
|
||||
p_incident_id: 'i1',
|
||||
p_capa_id: null,
|
||||
})
|
||||
expect(mockValues).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('skips entries missing userId or title', async () => {
|
||||
const supabase = makeSupabaseMock()
|
||||
const { created } = await createInAppNotifications(supabase, [
|
||||
const { created } = await createInAppNotifications([
|
||||
{ userId: '', title: 'x' },
|
||||
{ userId: 'u1', title: '' },
|
||||
])
|
||||
expect(created).toBe(0)
|
||||
expect(supabase.rpc).not.toHaveBeenCalled()
|
||||
expect(mockValues).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('counts only successful inserts when RPC errors', async () => {
|
||||
const supabase = makeSupabaseMock({ error: { message: 'boom' } })
|
||||
const { created } = await createInAppNotifications(supabase, [
|
||||
it('counts only successful inserts; failed insert is caught', async () => {
|
||||
mockValues.mockRejectedValueOnce(new Error('DB error'))
|
||||
const { created } = await createInAppNotifications([
|
||||
{ userId: 'u1', title: 'x' },
|
||||
])
|
||||
expect(created).toBe(0)
|
||||
})
|
||||
|
||||
it('deduplicates recipients for the same notification', async () => {
|
||||
const supabase = makeSupabaseMock()
|
||||
const { created } = await createInAppNotifications(supabase, [
|
||||
it('deduplicates same userId+title+incidentId', async () => {
|
||||
const { created } = await createInAppNotifications([
|
||||
{ userId: 'u1', title: 'same', incidentId: 'i1' },
|
||||
{ userId: 'u1', title: 'same', incidentId: 'i1' },
|
||||
])
|
||||
expect(created).toBe(1)
|
||||
expect(supabase.rpc).toHaveBeenCalledTimes(1)
|
||||
expect(mockValues).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user