- normalizeSubject strips repeated Re:/Fwd:/Fw: prefixes case-insensitively, lowercases, trims (D-03) - extractUrlDomain returns hostname or null (never throws) for malformed URLs (Pitfall 4) - test file mocks ./postgres-client before import, mirroring phishing-eml-service.test.ts's discipline
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
|
|
// Mock postgresClient BEFORE importing the module under test.
|
|
const queryMock = vi.fn();
|
|
const transactionMock = vi.fn();
|
|
vi.mock('./postgres-client', () => ({
|
|
postgresClient: {
|
|
query: (...args: unknown[]) => queryMock(...args),
|
|
transaction: (...args: unknown[]) => transactionMock(...args),
|
|
},
|
|
}));
|
|
|
|
// eslint-disable-next-line import/first -- imported after vi.mock hoisting
|
|
import { normalizeSubject, extractUrlDomain } from './campaign-grouping-service';
|
|
|
|
describe('normalizeSubject', () => {
|
|
it('strips a single Re: prefix, lowercases, trims', () => {
|
|
expect(normalizeSubject('Re: Your Invoice ')).toBe('your invoice');
|
|
});
|
|
|
|
it('strips repeated Re:/Fwd:/Fw: prefixes case-insensitively', () => {
|
|
expect(normalizeSubject('FW: Re: fwd: Urgent Payment')).toBe('urgent payment');
|
|
});
|
|
|
|
it('handles null', () => {
|
|
expect(normalizeSubject(null)).toBe('');
|
|
});
|
|
|
|
it('handles empty string', () => {
|
|
expect(normalizeSubject('')).toBe('');
|
|
});
|
|
|
|
it('lowercases and trims a subject with no prefix', () => {
|
|
expect(normalizeSubject(' Urgent Payment ')).toBe('urgent payment');
|
|
});
|
|
});
|
|
|
|
describe('extractUrlDomain', () => {
|
|
it('extracts hostname from a full URL', () => {
|
|
expect(extractUrlDomain('https://evil.example.com/path?x=1')).toBe('evil.example.com');
|
|
});
|
|
|
|
it('returns null for a malformed URL instead of throwing', () => {
|
|
expect(extractUrlDomain('not-a-url')).toBeNull();
|
|
});
|
|
|
|
it('extracts hostname regardless of scheme', () => {
|
|
expect(extractUrlDomain('http://another.example.net')).toBe('another.example.net');
|
|
});
|
|
});
|