feat(v2.7): 增加通知与评论协作模块
This commit is contained in:
112
apps/server/src/modules/comment/comment.service.spec.ts
Normal file
112
apps/server/src/modules/comment/comment.service.spec.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { AuditService } from '../../common/audit/audit.service';
|
||||
import { NotificationService } from '../notification/notification.service';
|
||||
import { CommentService } from './comment.service';
|
||||
|
||||
describe('CommentService', () => {
|
||||
const makeService = () => {
|
||||
const prisma = {
|
||||
comment: {
|
||||
create: jest.fn(),
|
||||
findUnique: jest.fn(),
|
||||
update: jest.fn(),
|
||||
},
|
||||
projectMember: {
|
||||
findMany: jest.fn(),
|
||||
},
|
||||
};
|
||||
const notifications = {
|
||||
createMany: jest.fn(),
|
||||
} as unknown as NotificationService;
|
||||
const audit = {
|
||||
record: jest.fn(),
|
||||
} as unknown as AuditService;
|
||||
return {
|
||||
prisma,
|
||||
notifications,
|
||||
audit,
|
||||
service: new CommentService(prisma as any, notifications, audit),
|
||||
};
|
||||
};
|
||||
|
||||
it('creates a polymorphic comment, extracts @mentions, notifies mentioned members, and writes audit', async () => {
|
||||
const { prisma, notifications, audit, service } = makeService();
|
||||
prisma.projectMember.findMany.mockResolvedValue([
|
||||
{ userId: 'm-alice', user: { id: 'm-alice', name: 'Alice' } },
|
||||
{ userId: 'm-bob', user: { id: 'm-bob', name: 'Bob' } },
|
||||
]);
|
||||
prisma.comment.create.mockResolvedValue({
|
||||
id: 'comment-1',
|
||||
entityType: 'dev_task',
|
||||
entityId: 'task-1',
|
||||
mentionedMemberIds: ['m-alice', 'm-bob'],
|
||||
});
|
||||
|
||||
const result = await service.create({
|
||||
actorId: 'm-author',
|
||||
entityType: 'dev_task',
|
||||
entityId: 'task-1',
|
||||
entityVersionId: 'ver-1',
|
||||
projectId: 'project-1',
|
||||
versionId: 'ver-1',
|
||||
content: '请 @Alice 看一下接口,Bob 也同步一下',
|
||||
mentionMemberIds: ['m-bob'],
|
||||
});
|
||||
|
||||
expect(result.id).toBe('comment-1');
|
||||
expect(prisma.comment.create).toHaveBeenCalledWith({
|
||||
data: expect.objectContaining({
|
||||
entityType: 'dev_task',
|
||||
entityId: 'task-1',
|
||||
authorId: 'm-author',
|
||||
mentionedMemberIds: ['m-alice', 'm-bob'],
|
||||
}),
|
||||
});
|
||||
expect((notifications.createMany as jest.Mock)).toHaveBeenCalledWith([
|
||||
expect.objectContaining({ recipientId: 'm-alice', type: 'mention', resourceType: 'comment', resourceId: 'comment-1' }),
|
||||
expect.objectContaining({ recipientId: 'm-bob', type: 'mention', resourceType: 'comment', resourceId: 'comment-1' }),
|
||||
]);
|
||||
expect((audit.record as jest.Mock)).toHaveBeenCalledWith(expect.objectContaining({
|
||||
actorId: 'm-author',
|
||||
action: 'comment.created',
|
||||
resourceType: 'comment',
|
||||
resourceId: 'comment-1',
|
||||
}));
|
||||
});
|
||||
|
||||
it('soft deletes a comment and writes audit', async () => {
|
||||
const { prisma, audit, service } = makeService();
|
||||
prisma.comment.findUnique.mockResolvedValue({
|
||||
id: 'comment-1',
|
||||
authorId: 'm-author',
|
||||
entityType: 'bug',
|
||||
entityId: 'bug-1',
|
||||
deletedAt: null,
|
||||
});
|
||||
prisma.comment.update.mockResolvedValue({ id: 'comment-1', deletedAt: new Date('2026-07-08T08:00:00.000Z') });
|
||||
|
||||
await service.remove('comment-1', 'm-author');
|
||||
|
||||
expect(prisma.comment.update).toHaveBeenCalledWith({
|
||||
where: { id: 'comment-1' },
|
||||
data: { deletedAt: expect.any(Date) },
|
||||
});
|
||||
expect((audit.record as jest.Mock)).toHaveBeenCalledWith(expect.objectContaining({
|
||||
actorId: 'm-author',
|
||||
action: 'comment.deleted',
|
||||
resourceType: 'comment',
|
||||
resourceId: 'comment-1',
|
||||
}));
|
||||
});
|
||||
|
||||
it('rejects unsupported comment entity types', async () => {
|
||||
const { service } = makeService();
|
||||
|
||||
await expect(service.create({
|
||||
actorId: 'm-author',
|
||||
entityType: 'task',
|
||||
entityId: 'task-1',
|
||||
content: 'legacy task comment',
|
||||
} as any)).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user