comments implement

This commit is contained in:
vadim committed 2026-10-01 12:02:03 +03:00
1 parent 9e0bef2527
commit 4b6ecfbf5d
41 files changed
+1350 -13

No files matched your search

@@ -0,0 +1,73 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ICommentRepository } from '../../../domain/repositories/comment.repository.interface.js';
import type { IIssueRepository } from '../../../../issue/domain/repositories/issue.repository.interface.js';
import { CommentNotFoundException } from '../../../domain/exceptions/comment-not-found.exception.js';
import { CommentForbiddenException } from '../../../domain/exceptions/comment-forbidden.exception.js';
import { CommentEventsService } from '../../services/comment-events.service.js';
import { CommentAccessService } from '../../services/comment-access.service.js';
import { UpdateCommentUseCase } from './update-comment.use-case.js';
import { UpdateCommentCommand } from './update-comment.command.js';
import { buildComment, buildIssue, mockAuthorExpander, mockCommentRepository, mockIssueRepository } from '../test-helpers.js';
describe('UpdateCommentUseCase', () => {
let commentRepository: ICommentRepository;
let issueRepository: IIssueRepository;
let commentEventsService: CommentEventsService;
let useCase: UpdateCommentUseCase;
let received: unknown[];
beforeEach(() => {
commentRepository = mockCommentRepository();
issueRepository = mockIssueRepository();
commentEventsService = new CommentEventsService();
useCase = new UpdateCommentUseCase(
commentRepository,
new CommentAccessService(commentRepository, issueRepository),
mockAuthorExpander(),
commentEventsService,
);
received = [];
commentEventsService.onEvents().subscribe((event) => received.push(event));
vi.mocked(issueRepository.findById).mockResolvedValue(buildIssue());
});
it('updates the content and emits comment.updated', async () => {
vi.mocked(commentRepository.findById).mockResolvedValue(buildComment());
const dto = await useCase.execute(new UpdateCommentCommand('comment-1', 'user-1', 'Changed'));
expect(dto.content).toBe('Changed');
expect(dto.editedAt).toBeInstanceOf(Date);
expect(commentRepository.update).toHaveBeenCalledTimes(1);
expect(received).toEqual([{ type: 'comment.updated', comment: dto }]);
});
it('skips saving and events when content did not change', async () => {
vi.mocked(commentRepository.findById).mockResolvedValue(buildComment());
await useCase.execute(new UpdateCommentCommand('comment-1', 'user-1', 'Original'));
expect(commentRepository.update).not.toHaveBeenCalled();
expect(received).toEqual([]);
});
it('throws CommentForbiddenException for a non-author', async () => {
vi.mocked(commentRepository.findById).mockResolvedValue(buildComment());
await expect(useCase.execute(new UpdateCommentCommand('comment-1', 'user-2', 'Changed'))).rejects.toThrow(CommentForbiddenException);
expect(commentRepository.update).not.toHaveBeenCalled();
});
it('throws CommentNotFoundException for a deleted comment', async () => {
vi.mocked(commentRepository.findById).mockResolvedValue(buildComment({ deletedAt: new Date() }));
await expect(useCase.execute(new UpdateCommentCommand('comment-1', 'user-1', 'Changed'))).rejects.toThrow(CommentNotFoundException);
});
it('throws CommentNotFoundException when the issue is not visible to the user', async () => {
vi.mocked(commentRepository.findById).mockResolvedValue(buildComment());
vi.mocked(issueRepository.findById).mockResolvedValue(null);
await expect(useCase.execute(new UpdateCommentCommand('comment-1', 'user-1', 'Changed'))).rejects.toThrow(CommentNotFoundException);
});
});