import { EmailQuoteExtractor } from '../emailQuoteExtractor.js'; const SAMPLE_EMAIL_HTML = `
method
`; const EMAIL_WITH_SIGNATURE = `On Mon, Sep 29, 2025 at 5:18 PM John shivam@chatwoot.com wrote:
Hi
On Mon, Sep 29, 2025 at 5:17 PM Shivam Mishra shivam@chatwoot.com wrote:
Yes, it is.
On Mon, Sep 29, 2025 at 5:16 PM John from Shaneforwoot < shaneforwoot@gmail.com> wrote:
Hey
On Mon, Sep 29, 2025 at 4:59 PM John shivam@chatwoot.com wrote:
This is another quoted quoted text reply
This is nice
On Mon, Sep 29, 2025 at 4:21 PM John from Shaneforwoot < > shaneforwoot@gmail.com> wrote:
Hey there, this is a reply from Chatwoot, notice the quoted text
Hey there
This is an email text, enjoy reading this
-- Shivam Mishra, Chatwoot
Latest reply here.
Thanks,
Jane Doe
`; const EMAIL_WITH_FOLLOW_UP_CONTENT = `On Mon, Sep 22, Someone wrote:
Previous reply content
Inline quote that should stay
Internal note follows
Regards,
`; // Regression coverage for the quote-toggle rewrite shipped on this branch. // Parse cleaned HTML into a container so each test can assert against // .textContent or query nested nodes. const cleaned = html => { const c = document.createElement('div'); c.innerHTML = EmailQuoteExtractor.extractQuotes(html); return c; }; describe('EmailQuoteExtractor', () => { it('removes blockquote-based quotes from the email body', () => { const c = cleaned(SAMPLE_EMAIL_HTML); expect(c.querySelectorAll('blockquote').length).toBe(0); expect(c.textContent?.trim()).toBe('method'); expect(c.textContent).not.toContain('On Mon, Sep 29, 2025 at 5:18 PM'); }); it('keeps blockquote fallback when it is not the last top-level element', () => { const c = cleaned(EMAIL_WITH_FOLLOW_UP_CONTENT); expect(c.querySelector('blockquote')).not.toBeNull(); expect(c.lastElementChild?.tagName).toBe('P'); }); it('detects quote indicators in nested blockquotes', () => { expect(EmailQuoteExtractor.hasQuotes(SAMPLE_EMAIL_HTML)).toBe(true); }); it('does not flag blockquotes that are followed by other elements', () => { expect(EmailQuoteExtractor.hasQuotes(EMAIL_WITH_FOLLOW_UP_CONTENT)).toBe( false ); }); it('returns false when no quote indicators are present', () => { expect(EmailQuoteExtractor.hasQuotes('Plain content
')).toBe(false); }); it('removes trailing blockquotes while preserving trailing signatures', () => { const c = cleaned(EMAIL_WITH_SIGNATURE); expect(c.querySelector('blockquote')).toBeNull(); expect(c.textContent).toContain('Thanks,'); expect(c.textContent).toContain('Jane Doe'); }); it('detects quotes for trailing blockquotes even when signatures follow text', () => { expect(EmailQuoteExtractor.hasQuotes(EMAIL_WITH_SIGNATURE)).toBe(true); }); describe('HTML sanitization', () => { it('removes onerror handlers from img tags in extractQuotes', () => { const maliciousHtml = 'Hello
Hello
'); }); it('removes onerror handlers from img tags in hasQuotes', () => { const maliciousHtml = 'Hello
Content
More
'; const cleanedHtml = EmailQuoteExtractor.extractQuotes(maliciousHtml); expect(cleanedHtml).not.toContain('