feat: add notification badge counts
هذا الالتزام موجود في:
@@ -1,7 +1,19 @@
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { NotificationUnreadCountQueryDto } from './dto/notification-query.dto';
|
||||
import { NotificationsService } from './notifications.service';
|
||||
|
||||
describe('NotificationsService', () => {
|
||||
it('rejects invalid unread-count category through DTO validation', async () => {
|
||||
const dto = plainToInstance(NotificationUnreadCountQueryDto, { category: 'badges' });
|
||||
|
||||
const errors = await validate(dto);
|
||||
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
expect(errors[0].property).toBe('category');
|
||||
});
|
||||
|
||||
it('creates mention notifications with mention type', async () => {
|
||||
const notificationsRepository = {
|
||||
create: jest.fn().mockResolvedValue({ toJSON: () => ({ _id: 'notification-1' }) }),
|
||||
@@ -107,6 +119,139 @@ describe('NotificationsService', () => {
|
||||
expect(notificationsRepository.countUnread).toHaveBeenCalledWith('507f1f77bcf86cd799439011');
|
||||
});
|
||||
|
||||
it('returns total unread count without category for backward compatibility', async () => {
|
||||
const notificationsRepository = {
|
||||
countUnread: jest.fn().mockResolvedValue(10),
|
||||
};
|
||||
const notificationsGateway = {};
|
||||
|
||||
const service = new NotificationsService(
|
||||
notificationsRepository as any,
|
||||
notificationsGateway as any,
|
||||
);
|
||||
|
||||
await expect(service.getUnreadCountByCategory('507f1f77bcf86cd799439011')).resolves.toEqual({
|
||||
unreadCount: 10,
|
||||
});
|
||||
expect(notificationsRepository.countUnread).toHaveBeenCalledWith('507f1f77bcf86cd799439011');
|
||||
});
|
||||
|
||||
it('returns unread count for interactions category only', async () => {
|
||||
const notificationsRepository = {
|
||||
countUnreadByFilter: jest.fn().mockResolvedValue(4),
|
||||
};
|
||||
const notificationsGateway = {};
|
||||
|
||||
const service = new NotificationsService(
|
||||
notificationsRepository as any,
|
||||
notificationsGateway as any,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.getUnreadCountByCategory('507f1f77bcf86cd799439011', 'interactions'),
|
||||
).resolves.toEqual({
|
||||
unreadCount: 4,
|
||||
category: 'interactions',
|
||||
});
|
||||
expect(notificationsRepository.countUnreadByFilter).toHaveBeenCalledWith(
|
||||
'507f1f77bcf86cd799439011',
|
||||
{
|
||||
type: {
|
||||
$in: [
|
||||
'like',
|
||||
'comment',
|
||||
'reply',
|
||||
'mention',
|
||||
'save',
|
||||
'share',
|
||||
'collaboration_request',
|
||||
'system',
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('returns unread count for messages category only', async () => {
|
||||
const notificationsRepository = {
|
||||
countUnreadByFilter: jest.fn().mockResolvedValue(3),
|
||||
};
|
||||
const notificationsGateway = {};
|
||||
|
||||
const service = new NotificationsService(
|
||||
notificationsRepository as any,
|
||||
notificationsGateway as any,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.getUnreadCountByCategory('507f1f77bcf86cd799439011', 'messages'),
|
||||
).resolves.toEqual({
|
||||
unreadCount: 3,
|
||||
category: 'messages',
|
||||
});
|
||||
expect(notificationsRepository.countUnreadByFilter).toHaveBeenCalledWith(
|
||||
'507f1f77bcf86cd799439011',
|
||||
{ type: { $in: ['message'] } },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns unread count for follow requests category only', async () => {
|
||||
const notificationsRepository = {
|
||||
countUnreadByFilter: jest.fn().mockResolvedValue(2),
|
||||
};
|
||||
const notificationsGateway = {};
|
||||
|
||||
const service = new NotificationsService(
|
||||
notificationsRepository as any,
|
||||
notificationsGateway as any,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.getUnreadCountByCategory('507f1f77bcf86cd799439011', 'follow_requests'),
|
||||
).resolves.toEqual({
|
||||
unreadCount: 2,
|
||||
category: 'follow_requests',
|
||||
});
|
||||
expect(notificationsRepository.countUnreadByFilter).toHaveBeenCalledWith(
|
||||
'507f1f77bcf86cd799439011',
|
||||
{
|
||||
type: {
|
||||
$in: ['follow_request', 'follow_request_approved', 'follow_request_rejected'],
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('returns grouped unread counts for badge hydration', async () => {
|
||||
const notificationsRepository = {
|
||||
countUnread: jest.fn().mockResolvedValue(10),
|
||||
countUnreadByFilter: jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(4)
|
||||
.mockResolvedValueOnce(3)
|
||||
.mockResolvedValueOnce(1)
|
||||
.mockResolvedValueOnce(2)
|
||||
.mockResolvedValueOnce(1)
|
||||
.mockResolvedValueOnce(0),
|
||||
};
|
||||
const notificationsGateway = {};
|
||||
|
||||
const service = new NotificationsService(
|
||||
notificationsRepository as any,
|
||||
notificationsGateway as any,
|
||||
);
|
||||
|
||||
await expect(service.getUnreadCounts('507f1f77bcf86cd799439011')).resolves.toEqual({
|
||||
total: 10,
|
||||
interactions: 4,
|
||||
messages: 3,
|
||||
follows: 1,
|
||||
followRequests: 2,
|
||||
collaboration: 1,
|
||||
system: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('filters notifications by interactions category', async () => {
|
||||
const notificationsRepository = {
|
||||
findMine: jest.fn().mockResolvedValue([]),
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم