eletrotupi / tcc/ api/tests/notifications/create.test.tsdafa6f8a8e3b0e51605fc953a979d50ff6085b26
4.0 KB | 126 lines Raw
1
import { describe, it, expect, afterAll, beforeEach, vi } from 'vitest'
2
import { NotificationKind } from '@prisma/client'
3
import { buildPrisma, cleanupTestDb, createTestUser } from '../test-helper'
4

5
vi.mock('@app/lib/sendPushNotification', () => ({
6
  sendPushNotification: vi.fn().mockResolvedValue(undefined),
7
}))
8

9
import { sendPushNotification } from '@app/lib/sendPushNotification'
10
import { createNotification } from '@app/services/notification.service'
11

12
const mockedSend = vi.mocked(sendPushNotification)
13

14
const db = buildPrisma()
15

16
afterAll(() => db.$disconnect())
17
beforeEach(async () => {
18
  await cleanupTestDb(db)
19
  mockedSend.mockClear()
20
  mockedSend.mockResolvedValue(undefined)
21
})
22

23
// São Paulo is UTC-3 year round, so this instant is midday in the app timezone
24
const midday = new Date('2026-03-10T12:00:00-03:00')
25

26
const dailyInput = (userId: number) => ({
27
  userId,
28
  kind: NotificationKind.DAILY_REMINDER,
29
  title: 'Como você está?',
30
  body: 'Registre seu humor para acompanhar sua saúde.',
31
  scheduledFor: midday,
32
})
33

34
describe('createNotification', () => {
35
  it('stores a notification whose window ends at the end of the app day', async () => {
36
    const user = await createTestUser(db)
37

38
    await createNotification(dailyInput(user.id))
39

40
    const row = await db.notification.findFirst()
41
    expect(row).toMatchObject({
42
      userId: user.id,
43
      kind: 'DAILY_REMINDER',
44
      title: 'Como você está?',
45
      regimenId: null,
46
    })
47
    expect(row?.scheduledFor.toISOString()).toBe(midday.toISOString())
48
    expect(row?.expiresAt?.toISOString()).toBe('2026-03-11T02:59:59.999Z')
49
  })
50

51
  it('stores a timeless notification without a window', async () => {
52
    const user = await createTestUser(db)
53

54
    await createNotification({
55
      userId: user.id,
56
      kind: NotificationKind.INSIGHT_ALERT,
57
      title: 'Trabalho aparece muito',
58
      body: 'Trabalho tem aparecido bastante nos seus gatilhos.',
59
      scheduledFor: midday,
60
    })
61

62
    const row = await db.notification.findFirst()
63
    expect(row?.kind).toBe('INSIGHT_ALERT')
64
    expect(row?.expiresAt).toBeNull()
65
  })
66

67
  it('records when a push was dispatched', async () => {
68
    const user = await createTestUser(db, {
69
      pushToken: 'ExponentPushToken[abc123]',
70
      notificationsEnabled: true,
71
    })
72

73
    await createNotification(dailyInput(user.id))
74

75
    expect(mockedSend).toHaveBeenCalledOnce()
76
    const row = await db.notification.findFirst()
77
    expect(row?.pushedAt).not.toBeNull()
78
  })
79

80
  it('stores the notification but does not push when notifications are disabled', async () => {
81
    const user = await createTestUser(db, {
82
      pushToken: 'ExponentPushToken[disabled]',
83
      notificationsEnabled: false,
84
    })
85

86
    await createNotification(dailyInput(user.id))
87

88
    expect(mockedSend).not.toHaveBeenCalled()
89
    const row = await db.notification.findFirst()
90
    expect(row).not.toBeNull()
91
    expect(row?.pushedAt).toBeNull()
92
  })
93

94
  it('stores the notification but does not push without a push token', async () => {
95
    const user = await createTestUser(db, { notificationsEnabled: true })
96

97
    await createNotification(dailyInput(user.id))
98

99
    expect(mockedSend).not.toHaveBeenCalled()
100
    const row = await db.notification.findFirst()
101
    expect(row).not.toBeNull()
102
    expect(row?.pushedAt).toBeNull()
103
  })
104

105
  it('keeps an unpushed record when the push fails', async () => {
106
    const user = await createTestUser(db, {
107
      pushToken: 'ExponentPushToken[boom]',
108
      notificationsEnabled: true,
109
    })
110
    mockedSend.mockRejectedValueOnce(new Error('Expo push API returned 500'))
111

112
    await expect(createNotification(dailyInput(user.id))).resolves.toBeDefined()
113

114
    const row = await db.notification.findFirst()
115
    expect(row).not.toBeNull()
116
    expect(row?.pushedAt).toBeNull()
117
  })
118

119
  it('stores nothing when the user does not exist', async () => {
120
    const result = await createNotification(dailyInput(999999))
121

122
    expect(result).toBeNull()
123
    expect(await db.notification.count()).toBe(0)
124
    expect(mockedSend).not.toHaveBeenCalled()
125
  })
126
})