import { describe, it, expect } from 'vitest'; import { KNOWN_PHISHING_PATTERNS, matchesPhishingPatterns, computePhishingContentHash, } from './phishing-detector'; describe('KNOWN_PHISHING_PATTERNS', () => { it('has exactly 8 locked patterns', () => { expect(KNOWN_PHISHING_PATTERNS).toHaveLength(8); }); }); describe('matchesPhishingPatterns', () => { it('flags a title containing "Phishing Report"', () => { const result = matchesPhishingPatterns('Fwd: Phishing Report', null); expect(result.flagged).toBe(true); expect(result.matched).toContain('Phishing Report'); }); it('flags a title containing "Spam Alert"', () => { const result = matchesPhishingPatterns('Spam Alert - user reported', null); expect(result.flagged).toBe(true); expect(result.matched).toContain('Spam Alert'); }); it('flags a title containing "Phishing Alert - Email Security Report"', () => { const result = matchesPhishingPatterns('Phishing Alert - Email Security Report', null); expect(result.flagged).toBe(true); expect(result.matched).toContain('Phishing Alert - Email Security Report'); }); it('flags a description containing "KnowBe4 Phish Alert Report"', () => { const result = matchesPhishingPatterns(null, 'This is a KnowBe4 Phish Alert Report for review'); expect(result.flagged).toBe(true); expect(result.matched).toContain('KnowBe4 Phish Alert Report'); }); it('flags a description containing "Source: KnowBe4 Phish Alert Button"', () => { const result = matchesPhishingPatterns(null, 'Source: KnowBe4 Phish Alert Button'); expect(result.flagged).toBe(true); expect(result.matched).toContain('Source: KnowBe4 Phish Alert Button'); }); it('flags a description containing "userSubmissionsReportMessage"', () => { const result = matchesPhishingPatterns(null, 'Generated by userSubmissionsReportMessage flow'); expect(result.flagged).toBe(true); expect(result.matched).toContain('userSubmissionsReportMessage'); }); it('flags a description containing "reported message destinations"', () => { const result = matchesPhishingPatterns(null, 'See reported message destinations below'); expect(result.flagged).toBe(true); expect(result.matched).toContain('reported message destinations'); }); it('flags a description containing "Microsoft directly"', () => { const result = matchesPhishingPatterns(null, 'This message was reported to Microsoft directly'); expect(result.flagged).toBe(true); expect(result.matched).toContain('Microsoft directly'); }); it('does not flag a ticket with none of the patterns', () => { const result = matchesPhishingPatterns('Re: order confirmation', 'please review invoice'); expect(result.flagged).toBe(false); expect(result.matched).toEqual([]); }); it('matches case-insensitively', () => { const result = matchesPhishingPatterns('SPAM ALERT from user', null); expect(result.flagged).toBe(true); expect(result.matched).toContain('Spam Alert'); }); it('returns only the patterns actually present in matched[]', () => { const result = matchesPhishingPatterns('Phishing Report', 'unrelated body text'); expect(result.matched).toEqual(['Phishing Report']); }); it('checks both title and description for a match', () => { const result = matchesPhishingPatterns('Unrelated subject', 'Spam Alert triggered'); expect(result.flagged).toBe(true); expect(result.matched).toContain('Spam Alert'); }); }); describe('computePhishingContentHash', () => { it('is stable for identical title+description', () => { expect(computePhishingContentHash('t', 'd')).toBe(computePhishingContentHash('t', 'd')); }); it('changes when the title changes', () => { expect(computePhishingContentHash('t', 'd')).not.toBe(computePhishingContentHash('t2', 'd')); }); it('changes when the description changes', () => { expect(computePhishingContentHash('t', 'd')).not.toBe(computePhishingContentHash('t', 'd2')); }); it('is defined and stable when description is null', () => { const hash1 = computePhishingContentHash('t', null); const hash2 = computePhishingContentHash('t', null); expect(hash1).toBeTruthy(); expect(hash1).toBe(hash2); }); });