import { describe, expect, it, vi } from 'vitest'; import { BadRequestException, type ExecutionContext, NotFoundException, UnauthorizedException } from '@nestjs/common'; import { CommentAccessService } from '../../application/services/comment-access.service.js'; import { IssueVisibleGuard } from './issue-visible.guard.js'; const buildContext = (params: Record, userId?: string) => ({ switchToHttp: () => ({ getRequest: () => ({ params, session: userId ? { user: { id: userId } } : undefined }), }), }) as unknown as ExecutionContext; const buildGuard = (visible: boolean) => { const commentAccess = { isIssueVisible: vi.fn().mockResolvedValue(visible) } as unknown as CommentAccessService; return { guard: new IssueVisibleGuard(commentAccess), commentAccess }; }; describe('IssueVisibleGuard', () => { it('allows access to a visible issue', async () => { const { guard, commentAccess } = buildGuard(true); await expect(guard.canActivate(buildContext({ issueId: '1' }, 'user-1'))).resolves.toBe(true); expect(commentAccess.isIssueVisible).toHaveBeenCalledWith(1, 'user-1'); }); it('throws NotFoundException when the issue is not visible', async () => { const { guard } = buildGuard(false); await expect(guard.canActivate(buildContext({ issueId: '1' }, 'user-2'))).rejects.toThrow(NotFoundException); }); it('throws BadRequestException for a non-numeric issueId', async () => { const { guard, commentAccess } = buildGuard(true); await expect(guard.canActivate(buildContext({ issueId: 'abc' }, 'user-1'))).rejects.toThrow(BadRequestException); expect(commentAccess.isIssueVisible).not.toHaveBeenCalled(); }); it('throws UnauthorizedException without a session', async () => { const { guard } = buildGuard(true); await expect(guard.canActivate(buildContext({ issueId: '1' }))).rejects.toThrow(UnauthorizedException); }); });