/ src / lib / server / create-notification.test.ts
create-notification.test.ts
 1  import assert from 'node:assert/strict'
 2  import { describe, it } from 'node:test'
 3  
 4  import type { AppNotification } from '@/types'
 5  import { createNotification } from './create-notification'
 6  
 7  describe('createNotification', () => {
 8    it('coalesces repeated dedupKey events into one notification record', () => {
 9      const store = new Map<string, AppNotification>()
10      const notifyTopics: string[] = []
11      const dispatched: string[] = []
12  
13      const deps = {
14        now: (() => {
15          let current = 1_700_000_000_000
16          return () => {
17            current += 1_000
18            return current
19          }
20        })(),
21        save: (id: string, data: AppNotification) => {
22          store.set(id, data)
23        },
24        notifyTopic: (topic: string) => {
25          notifyTopics.push(topic)
26        },
27        dispatch: async (notification: AppNotification) => {
28          dispatched.push(notification.id)
29        },
30        findByDedupKey: (dedupKey: string) => {
31          for (const notification of store.values()) {
32            if (notification.dedupKey === dedupKey) return notification
33          }
34          return null
35        },
36        createId: (() => {
37          let seq = 0
38          return () => `notif_${++seq}`
39        })(),
40      }
41  
42      const first = createNotification({
43        type: 'warning',
44        title: 'Provider unreachable',
45        message: 'Timeout',
46        dedupKey: 'provider-down:test',
47      }, deps)
48  
49      const second = createNotification({
50        type: 'warning',
51        title: 'Provider unreachable',
52        message: 'Still timing out',
53        dedupKey: 'provider-down:test',
54      }, deps)
55  
56      assert.equal(first.created, true)
57      assert.equal(second.created, false)
58      assert.equal(store.size, 1)
59      assert.equal(second.notification.id, first.notification.id)
60      assert.equal(second.notification.message, 'Still timing out')
61      assert.equal(second.notification.occurrenceCount, 2)
62      assert.equal(second.notification.read, false)
63      assert.deepEqual(notifyTopics, ['notifications', 'notifications'])
64      assert.deepEqual(dispatched, [first.notification.id])
65    })
66  
67    it('can keep a notification in-app only without external dispatch', () => {
68      const store = new Map<string, AppNotification>()
69      const dispatched: string[] = []
70  
71      const result = createNotification({
72        type: 'warning',
73        title: 'SwarmClaw health alert',
74        message: 'Connector recovered.',
75        dedupKey: 'health-alert:connector-recovered',
76        dispatchExternally: false,
77      }, {
78        now: () => 1_700_000_000_000,
79        save: (id: string, data: AppNotification) => {
80          store.set(id, data)
81        },
82        notifyTopic: () => {},
83        dispatch: async (notification: AppNotification) => {
84          dispatched.push(notification.id)
85        },
86        findByDedupKey: () => null,
87        createId: () => 'notif_health',
88      })
89  
90      assert.equal(result.created, true)
91      assert.equal(store.get('notif_health')?.title, 'SwarmClaw health alert')
92      assert.deepEqual(dispatched, [])
93    })
94  })