import { ForbiddenException, NotFoundException } from '@nestjs/common'; import { TeamRolesEnum } from '../team-roles/team-roles.enum'; import { CashboxExportService } from './cashbox-export.service'; describe('CashboxExportService', () => { const teamRepository = { findOne: jest.fn() }; const access = { assertAtLeast: jest.fn() }; let service: CashboxExportService; let callOrder: string[]; const team = { id: 5, name: 'Team A', alias: 'team-a', transactions: [ { date: '2026-08-05T00:00:00.000Z', amount: 10, note: 'Sponsoring', type: { name: 'credit' } }, ], players: [], }; beforeEach(() => { jest.clearAllMocks(); callOrder = []; access.assertAtLeast.mockImplementation(async () => { callOrder.push('assertAtLeast'); }); teamRepository.findOne.mockImplementation(async () => { callOrder.push('findOne'); return team; }); service = new CashboxExportService(teamRepository as any, access as any); }); it('checks permission before loading data', async () => { await service.exportForUser(5, 42, '2026-08-01', '2026-08-31', 'csv'); expect(access.assertAtLeast).toHaveBeenCalledWith( 42, 5, 'transaction_create_min_role', TeamRolesEnum.scnd_treasurer, ); }); it('calls assertAtLeast before findOne to enforce permission check ordering', async () => { await service.exportForUser(5, 42, '2026-08-01', '2026-08-31', 'csv'); expect(callOrder).toEqual(['assertAtLeast', 'findOne']); }); it('skips team lookup when permission check rejects', async () => { access.assertAtLeast.mockRejectedValueOnce(new ForbiddenException('Insufficient permissions')); await expect( service.exportForUser(5, 42, '2026-08-01', '2026-08-31', 'csv'), ).rejects.toBeInstanceOf(ForbiddenException); expect(teamRepository.findOne).not.toHaveBeenCalled(); }); it('throws NotFoundException for an unknown team', async () => { teamRepository.findOne.mockResolvedValueOnce(null); await expect( service.exportForUser(999, 42, '2026-08-01', '2026-08-31', 'csv'), ).rejects.toBeInstanceOf(NotFoundException); }); it('builds a CSV buffer with the correct content type and filename', async () => { const result = await service.exportForUser(5, 42, '2026-08-01', '2026-08-31', 'csv'); expect(result.contentType).toBe('text/csv; charset=utf-8'); expect(result.filename).toBe('kassenbuch_team-a_2026-08-01_2026-08-31.csv'); expect(result.buffer.toString('utf-8')).toContain('Sponsoring'); }); it('builds a PDF buffer with the correct content type and filename', async () => { const result = await service.exportForUser(5, 42, '2026-08-01', '2026-08-31', 'pdf'); expect(result.contentType).toBe('application/pdf'); expect(result.filename).toBe('kassenbuch_team-a_2026-08-01_2026-08-31.pdf'); expect(result.buffer.subarray(0, 5).toString('utf-8')).toBe('%PDF-'); }); });