diff --git a/src/lib/ai/create.test.ts b/src/lib/ai/create.test.ts index 82c28f49..9cbc5099 100644 --- a/src/lib/ai/create.test.ts +++ b/src/lib/ai/create.test.ts @@ -26,7 +26,7 @@ describe('lib ai', () => { it('should return an error if creating the AI execution fails', async () => { const expectedError = new Error('Ups'); - prisma.aiExecution.create = vi.fn().mockRejectedValue(expectedError); + vi.spyOn(prisma.aiExecution, 'create').mockRejectedValueOnce(expectedError); await expect(createAiExecution(execution)).rejects.toThrowError(expectedError); }); diff --git a/src/lib/meetings/get.test.ts b/src/lib/meetings/get.test.ts index 4329595d..1349f8bf 100644 --- a/src/lib/meetings/get.test.ts +++ b/src/lib/meetings/get.test.ts @@ -1,15 +1,16 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { calculateNextMeeting } from './get'; import { Meeting, MeetingDescription, Rythm } from './types'; describe('calculateNextMeeting', () => { const fakeCurrentDate = new Date(2023, 0, 1); + beforeEach(() => { vi.useFakeTimers({ now: fakeCurrentDate }); }); - test('returns the closest next meeting', async () => { + it('should return the closest next meeting', async () => { const meetingDescriptions: MeetingDescription[] = [ { startDate: new Date('2023-01-01T23:00:00.000Z'), @@ -35,7 +36,7 @@ describe('calculateNextMeeting', () => { expect(result).toEqual(expectedResult); }); - test('returns the closest next meeting also when they are started in the past', async () => { + it('should return the closest next meeting also when they are started in the past', async () => { const meetingDescriptions: MeetingDescription[] = [ { startDate: new Date('2022-12-28T11:00:00.000Z'), @@ -61,7 +62,7 @@ describe('calculateNextMeeting', () => { expect(result).toEqual(expectedResult); }); - test('returns null when no next meeting is found', async () => { + it('should return null when no next meeting is found', async () => { const result = calculateNextMeeting([]); expect(result).toBeNull(); }); diff --git a/src/lib/notifications/persistent/create.test.ts b/src/lib/notifications/persistent/create.test.ts new file mode 100644 index 00000000..0fc2458f --- /dev/null +++ b/src/lib/notifications/persistent/create.test.ts @@ -0,0 +1,97 @@ +import { NotificationType } from '@prisma/client'; +import { revalidatePath } from 'next/cache'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import prisma from '@/lib/prisma/client'; + +import { createNotification, createNotificationAction } from './create'; +import { getNotifications } from './get'; + +vi.mock('../../auth/session', async () => ({ + getServerSession: vi.fn().mockResolvedValue({ user: { id: 'userId' } }) +})); + +vi.mock('next/cache', () => ({ + revalidatePath: vi.fn() +})); + +describe('lib notifications', () => { + describe('persistent create', () => { + const notification = { + title: 'title', + type: NotificationType.SignupWelcome, + payload: {} + }; + + const userId = 'userId'; + + beforeEach(() => { + prisma.notification.deleteMany({}); + }); + + describe('createNotification', () => { + it('should create a notification', async () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { ownerId, ...createdNotification } = await createNotification(userId, notification); + const retrievedNotification = (await getNotifications({ userId }))[0]; + + expect(retrievedNotification).toStrictEqual(createdNotification); + }); + + it('should create a notification with a default payload if none is provided', async () => { + const createdNotification = await createNotification(userId, { ...notification, payload: undefined }); + + expect(createdNotification.payload).toStrictEqual({}); + }); + + it('should return an error if creating the notification fails', async () => { + const expectedError = new Error('Ups'); + vi.spyOn(prisma.notification, 'create').mockRejectedValueOnce(expectedError); + + await expect(createNotification(userId, notification)).rejects.toThrowError(expectedError); + }); + }); + + describe('createNotificationAction', () => { + it('should create a notification and return its id', async () => { + const id = await createNotificationAction(notification); + const retrievedNotification = await getNotifications({ userId }); + + expect(retrievedNotification[0].id).toBe(id); + }); + + it('should revalidate the notifications path after creating the notification', async () => { + await createNotificationAction(notification); + expect(revalidatePath).toHaveBeenCalledWith('/notifications'); + }); + + it('should return an error if creating the notification fails', async () => { + const expectedError = new Error('Ups'); + vi.spyOn(prisma.notification, 'create').mockRejectedValueOnce(expectedError); + + await expect(createNotificationAction(notification)).rejects.toThrowError(expectedError); + }); + + describe('validations', () => { + it('should return a validation error if the title is not a string', async () => { + const expectedError = new Error('Validation error: Expected string, received number at "title"'); + await expect(createNotificationAction({ ...notification, title: (1 as any) })).rejects.toThrowError(expectedError); + }); + + it('should return a validation error if the payload is not an object', async () => { + const expectedError = new Error('Validation error: Expected object, received string at "payload"'); + await expect(createNotificationAction({ ...notification, payload: ('nope' as any) })).rejects.toThrowError(expectedError); + }); + + it('should return a validation error if the type is not a NotificationType', async () => { + try { + await createNotificationAction({ ...notification, type: ('nope' as any) }); + } catch (error: any) { + expect(error.message).toContain('Validation error: Invalid enum value'); + expect(error.message).toContain('received \'nope\' at "type"'); + } + }); + }); + }); + }); +});