// resendRedemptionConfirmation rebuilds the confirmation email from stored // redemption data and records the new outcome. Only the resend path is // exercised here; the shared send/record logic is covered by // confirmation-email.test.ts. jest.mock('../../src/models/tickets/Tickets.db', () => ({ NachklangTicketsDB: {getConnection: jest.fn()} })); jest.mock('../../src/models/tickets/tickets.confirmation-email', () => ({ sendRedemptionConfirmation: jest.fn(), recordConfirmationEmailResult: jest.fn() })); import {NachklangTicketsDB} from '../../src/models/tickets/Tickets.db'; import {recordConfirmationEmailResult, sendRedemptionConfirmation} from '../../src/models/tickets/tickets.confirmation-email'; import {resendRedemptionConfirmation} from '../../src/models/tickets/admin/redemptions.admin.service'; const mockGetConnection = NachklangTicketsDB.getConnection as jest.Mock; const mockSend = sendRedemptionConfirmation as jest.Mock; const mockRecord = recordConfirmationEmailResult as jest.Mock; const ACTIVE_ROW = { redemption_id: 5, code: 'ABC123', event_id: 42, status: 'ACTIVE', contact_name: 'Erika Mustermann', contact_email: 'erika@example.com', contact_address: null, guest_count: 2, redeemed_at: new Date('2026-06-01T10:00:00Z'), confirmation_email_status: 'FAILED' }; // getRedemption issues: 1) SELECT redemptions, 2) SELECT redemption_guests const connFor = (redemptionRows: any[], guestRows: any[] = []) => ({ query: jest .fn() .mockResolvedValueOnce(redemptionRows) .mockResolvedValueOnce(guestRows), end: jest.fn().mockResolvedValue(undefined) }); beforeEach(() => { jest.clearAllMocks(); mockSend.mockResolvedValue(true); }); describe('resendRedemptionConfirmation', () => { it('returns NOT_FOUND when the redemption does not exist', async () => { mockGetConnection.mockResolvedValue(connFor([])); expect(await resendRedemptionConfirmation(5)).toBe('NOT_FOUND'); expect(mockSend).not.toHaveBeenCalled(); }); it('returns NOT_ACTIVE for an undone redemption', async () => { mockGetConnection.mockResolvedValue(connFor([{...ACTIVE_ROW, status: 'UNDONE'}])); expect(await resendRedemptionConfirmation(5)).toBe('NOT_ACTIVE'); expect(mockSend).not.toHaveBeenCalled(); }); it('resends from the stored data and records SENT on success', async () => { mockGetConnection.mockResolvedValue(connFor([ACTIVE_ROW], [{name: 'Erika Mustermann'}, {name: 'Hans Mustermann'}])); const result = await resendRedemptionConfirmation(5); expect(result).toBe('SENT'); expect(mockSend).toHaveBeenCalledWith({ eventId: 42, contactName: 'Erika Mustermann', contactEmail: 'erika@example.com', guestNames: ['Erika Mustermann', 'Hans Mustermann'] }); expect(mockRecord).toHaveBeenCalledWith(5, true); }); it('records FAILED and returns FAILED when the relay rejects the send', async () => { mockGetConnection.mockResolvedValue(connFor([ACTIVE_ROW], [{name: 'Erika Mustermann'}])); mockSend.mockResolvedValue(false); const result = await resendRedemptionConfirmation(5); expect(result).toBe('FAILED'); expect(mockRecord).toHaveBeenCalledWith(5, false); }); });