import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { getDefaultReplyParserConfig, parseEmailReply } from './replyParser';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
function readFixture(file: string): string {
return fs.readFileSync(path.join(__dirname, '__fixtures__', file), 'utf8');
}
describe('replyParser', () => {
it('honours explicit reply boundaries and extracts hidden tokens', () => {
const text = readFixture('gmail-top-post.txt');
const html = readFixture('gmail-top-post.html');
const result = parseEmailReply({ text, html });
expect(result.confidence).toBe('high');
expect(result.strategy).toBe('custom-boundary');
expect(result.tokens).toEqual({
conversationToken: 'GHFTK-123',
ticketId: '8f4e9f72-1d7d-4b3c-94fb-2f8f9ccce901',
commentId: '6e5874a5-22a9-479d-a20e-052b43165c0d',
});
expect(result.appliedHeuristics).toContain('explicit-boundary');
expect(result.sanitizedText).toMatchInlineSnapshot(`
"Hi support team,\n\nHappy to confirm the restart worked fine."
`);
expect(result.sanitizedHtml).toMatchInlineSnapshot(`
"
Hi support team,
\nHappy to confirm the restart worked fine.
\nThanks,
Jane Doe
Sent from my iPhone
"
`);
});
it('removes inline quoted sections but preserves responder notes for Outlook style replies', () => {
const text = readFixture('outlook-inline.txt');
const result = parseEmailReply({ text });
expect(result.confidence).toBe('medium');
expect(result.appliedHeuristics).toContain('quote-prefix');
expect(result.sanitizedText).toMatchInlineSnapshot(`
"Hi Alex,\n\nSee inline below.\n\nSerial: SN-998877."
`);
});
it('keeps user preface while discarding forwarded chains', () => {
const text = readFixture('forwarded-thread.txt');
const result = parseEmailReply({ text });
expect(result.strategy).toMatch(/provider-header|custom-boundary|quoted-block/);
expect(result.sanitizedText).toMatchInlineSnapshot(`
"Please see the forwarded ticket below – looks like the customer escalated again."
`);
});
it('strips signatures and confidentiality footers', () => {
const text = readFixture('signature-heavy.txt');
const result = parseEmailReply({ text });
expect(result.sanitizedText).not.toMatch(/Confidentiality Notice/);
expect(result.appliedHeuristics).toContain('signature-trim');
expect(result.sanitizedText).toMatchInlineSnapshot(`
"Hello,\n\nHere is the update you requested. The service has been restored as of 16:45 UTC."
`);
});
it('falls back gracefully when no heuristics match', () => {
const text = 'Quick confirmation that everything works as expected.';
const result = parseEmailReply({ text }, getDefaultReplyParserConfig());
expect(result.strategy).toBe('fallback');
expect(result.sanitizedText).toMatchInlineSnapshot('"Quick confirmation that everything works as expected."');
});
it('recovers tokens wrapped/quoted by Gmail', () => {
const text = `let's see if replies work now
*Robert Isaacs* | *CEO*
2963 Gulf to Bay Blvd. Clearwater, FL | 727-591-7436
On Thu, Nov 20, 2025 at 7:58 AM Software wrote:
> [ALGA-REPLY-TOKEN a83113b5-d30f-4ec9-85ce-0d0ce95fa49a
> ticketId=a5ea2cf5-f572-436c-b485-9b5ca07a9e17
> commentId=3de1cc6a-8d4a-4b3c-9a27-72990ab84226]
> --- Please reply above this line ---
>
> --- Please reply above this line ---
> New Comment Added
`;
const result = parseEmailReply({ text });
expect(result.tokens).toEqual({
conversationToken: 'a83113b5-d30f-4ec9-85ce-0d0ce95fa49a',
ticketId: 'a5ea2cf5-f572-436c-b485-9b5ca07a9e17',
commentId: '3de1cc6a-8d4a-4b3c-9a27-72990ab84226',
});
});
});