From 20b1e1bb6faefc6c26f1afe6b5830ee8951f9f3f Mon Sep 17 00:00:00 2001 From: lorentz Date: Thu, 16 Jul 2026 14:26:28 -0400 Subject: [PATCH] test(22-01): add failing test for resolveTicketToCampaign - Covers no-report, ungrouped, and grouped resolution states - Asserts parameterized ticket_id lookup query shape --- lib/services/phishing-ticket-resolver.test.ts | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 lib/services/phishing-ticket-resolver.test.ts diff --git a/lib/services/phishing-ticket-resolver.test.ts b/lib/services/phishing-ticket-resolver.test.ts new file mode 100644 index 0000000..49c0082 --- /dev/null +++ b/lib/services/phishing-ticket-resolver.test.ts @@ -0,0 +1,76 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// Mock postgresClient BEFORE importing the module under test — mirrors +// campaign-classifier.test.ts's vi.mock() factory-mocking discipline. +const queryMock = vi.fn(); +vi.mock('./postgres-client', () => ({ + postgresClient: { + query: (...args: unknown[]) => queryMock(...args), + }, +})); + +// eslint-disable-next-line import/first -- imported after vi.mock hoisting +import { resolveTicketToCampaign } from './phishing-ticket-resolver'; + +describe('resolveTicketToCampaign', () => { + beforeEach(() => { + queryMock.mockReset(); + }); + + it('returns { found: false } when no reports row exists for the ticket id', async () => { + queryMock.mockResolvedValue({ rows: [], rowCount: 0 }); + + const result = await resolveTicketToCampaign(999); + + expect(result).toEqual({ found: false }); + }); + + it('returns { found: true, campaignId: null } for an ungrouped report', async () => { + queryMock.mockResolvedValue({ + rows: [{ id: 'report-1', campaign_id: null, ticket_number: 'T20260716.0001' }], + rowCount: 1, + }); + + const result = await resolveTicketToCampaign(123); + + expect(result).toEqual({ + found: true, + reportId: 'report-1', + campaignId: null, + ticketNumber: 'T20260716.0001', + }); + }); + + it('returns { found: true, reportId, campaignId, ticketNumber } for a grouped report', async () => { + queryMock.mockResolvedValue({ + rows: [ + { + id: 'report-2', + campaign_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', + ticket_number: 'T20260716.0002', + }, + ], + rowCount: 1, + }); + + const result = await resolveTicketToCampaign(456); + + expect(result).toEqual({ + found: true, + reportId: 'report-2', + campaignId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', + ticketNumber: 'T20260716.0002', + }); + }); + + it('queries reports filtered by ticket_id with a parameterized query', async () => { + queryMock.mockResolvedValue({ rows: [], rowCount: 0 }); + + await resolveTicketToCampaign(1); + + expect(queryMock).toHaveBeenCalledWith( + expect.stringContaining('FROM reports WHERE ticket_id = $1'), + [1] + ); + }); +});