markRead() pruefte bisher nicht, ob die Benachrichtigung dem anfragenden Nutzer gehoert - jeder authentifizierte Nutzer konnte fremde Benachrichtigungen als gelesen markieren. Jetzt: 403 bei fremder Benachrichtigung, weiterhin erlaubt fuer eigene und Broadcast-Benachrichtigungen (userId = null). E2E-Regressionstest ergaenzt.
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import { ForbiddenException, NotFoundException } from '@nestjs/common';
|
|
import { NotificationsService } from './notifications.service';
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
|
|
describe('NotificationsService', () => {
|
|
let service: NotificationsService;
|
|
let prisma: {
|
|
notification: {
|
|
create: jest.Mock;
|
|
findMany: jest.Mock;
|
|
findUnique: jest.Mock;
|
|
update: jest.Mock;
|
|
};
|
|
};
|
|
|
|
beforeEach(() => {
|
|
prisma = {
|
|
notification: {
|
|
create: jest.fn(),
|
|
findMany: jest.fn(),
|
|
findUnique: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
};
|
|
service = new NotificationsService(prisma as unknown as PrismaService);
|
|
});
|
|
|
|
it('records a notification with the given priority and message', async () => {
|
|
const created = {
|
|
id: 'n1',
|
|
priority: 'KRITISCH',
|
|
message: 'Keine Königin gesehen',
|
|
};
|
|
prisma.notification.create.mockResolvedValueOnce(created);
|
|
|
|
const result = await service.record({
|
|
priority: 'KRITISCH',
|
|
message: 'Keine Königin gesehen',
|
|
});
|
|
|
|
expect(result).toEqual(created);
|
|
expect(prisma.notification.create).toHaveBeenCalledWith({
|
|
data: { priority: 'KRITISCH', message: 'Keine Königin gesehen' },
|
|
});
|
|
});
|
|
|
|
it('lists notifications for a user including broadcast notifications', async () => {
|
|
await service.findAll({ userId: 'user-1' });
|
|
|
|
const [[queryArg]] = prisma.notification.findMany.mock.calls as [
|
|
[{ where: { OR?: { userId: string | null }[] } }],
|
|
];
|
|
expect(queryArg.where.OR).toEqual([{ userId: 'user-1' }, { userId: null }]);
|
|
});
|
|
|
|
it('throws NotFoundException when marking an unknown notification as read', async () => {
|
|
prisma.notification.findUnique.mockResolvedValueOnce(null);
|
|
await expect(service.markRead('missing', 'user-1')).rejects.toBeInstanceOf(
|
|
NotFoundException,
|
|
);
|
|
});
|
|
|
|
it("throws ForbiddenException when marking another user's notification as read", async () => {
|
|
prisma.notification.findUnique.mockResolvedValueOnce({
|
|
id: 'n1',
|
|
userId: 'owner',
|
|
read: false,
|
|
});
|
|
await expect(service.markRead('n1', 'someone-else')).rejects.toBeInstanceOf(
|
|
ForbiddenException,
|
|
);
|
|
});
|
|
|
|
it('marks a broadcast notification (no owner) as read for any user', async () => {
|
|
prisma.notification.findUnique.mockResolvedValueOnce({
|
|
id: 'n1',
|
|
userId: null,
|
|
read: false,
|
|
});
|
|
prisma.notification.update.mockResolvedValueOnce({ id: 'n1', read: true });
|
|
|
|
const result = await service.markRead('n1', 'any-user');
|
|
|
|
expect(result.read).toBe(true);
|
|
});
|
|
|
|
it("marks the owner's own notification as read", async () => {
|
|
prisma.notification.findUnique.mockResolvedValueOnce({
|
|
id: 'n1',
|
|
userId: 'user-1',
|
|
read: false,
|
|
});
|
|
prisma.notification.update.mockResolvedValueOnce({ id: 'n1', read: true });
|
|
|
|
const result = await service.markRead('n1', 'user-1');
|
|
|
|
expect(result.read).toBe(true);
|
|
});
|
|
});
|