60 lines
3.7 KiB
TypeScript
60 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import Fastify from 'fastify'
|
|
import routes from '../src/routes/notifications'
|
|
import { NotificationService } from '../src/modules/notification.service'
|
|
import { notificationsEventTypes, notificationsPreferences } from '../db/schema'
|
|
|
|
function fixture(prefs: any[] = [], defaults: any[] = []) {
|
|
const writes: any[] = []
|
|
const event = { eventKey: 'communication.message.direct', displayName: 'Direktnachrichten', category: 'communication', allowedChannels: ['inapp', 'email', 'push'], isActive: true }
|
|
const db: any = {
|
|
select: () => ({ from: (table: any) => ({ where: async () => table === notificationsEventTypes ? [event] : table === notificationsPreferences ? prefs : defaults }) }),
|
|
transaction: async (callback: any) => callback(db),
|
|
insert: () => ({ values: (value: any) => ({ onConflictDoUpdate: async () => { writes.push(value) } }) }),
|
|
}
|
|
return { service: new NotificationService({ db } as any, async () => null), db, writes }
|
|
}
|
|
|
|
test('defaults are quiet for email, user overrides win over tenant defaults', async () => {
|
|
assert.deepEqual((await fixture().service.preferences(1, 'user')).events[0].channels, { email: false, push: true })
|
|
const { service } = fixture([{ channel: 'push', enabled: false }], [{ channel: 'push', enabled: true }, { channel: 'email', enabled: true }])
|
|
assert.deepEqual((await service.preferences(1, 'user')).events[0].channels, { email: true, push: false })
|
|
})
|
|
|
|
test('invalid batches cause no writes, including duplicates and unsupported channels', async () => {
|
|
for (const bad of [null, {}, [{ eventType: 'unknown', channel: 'push', enabled: true }],
|
|
[{ eventType: 'communication.message.direct', channel: 'sms', enabled: true }],
|
|
[{ eventType: 'communication.message.direct', channel: 'push', enabled: 'false' }],
|
|
Array(2).fill({ eventType: 'communication.message.direct', channel: 'push', enabled: true })]) {
|
|
const { service, writes } = fixture()
|
|
await assert.rejects(service.savePreferences(1, 'user', bad), { statusCode: 400 })
|
|
assert.equal(writes.length, 0)
|
|
}
|
|
})
|
|
|
|
test('API ignores supplied tenant/user identifiers and saves in the authenticated context', async () => {
|
|
const { db, writes } = fixture()
|
|
const app = Fastify()
|
|
app.decorate('db', db)
|
|
app.addHook('preHandler', async (req: any) => { req.user = { tenant_id: 7, user_id: 'current-user' } })
|
|
await app.register(routes)
|
|
try {
|
|
const response = await app.inject({ method: 'PUT', url: '/notifications/preferences', payload: [
|
|
{ tenantId: 999, userId: 'other', eventType: 'communication.message.direct', channel: 'push', enabled: false },
|
|
] })
|
|
assert.equal(response.statusCode, 200, response.body)
|
|
assert.deepEqual(writes, [{ tenantId: 7, userId: 'current-user', eventType: 'communication.message.direct', channel: 'push', enabled: false }])
|
|
const invalid = await app.inject({ method: 'PUT', url: '/notifications/preferences', payload: [{ eventType: 'system.test_push', channel: 'push', enabled: false }] })
|
|
assert.equal(invalid.statusCode, 400)
|
|
} finally { await app.close() }
|
|
})
|
|
|
|
test('room notifications stay opt-in while direct messages remain enabled', async () => {
|
|
const { service } = fixture()
|
|
const resolve = (eventType: string) => (service as any).resolveEnabledChannels({ tenantId: 1, userId: 'user', eventType, channels: ['email', 'push'] })
|
|
assert.deepEqual(await resolve('communication.message.room'), [])
|
|
assert.deepEqual(await resolve('communication.room.invited'), [])
|
|
assert.deepEqual(await resolve('communication.message.direct'), ['push'])
|
|
})
|