import { describe, it, expect } from 'vitest'; import { buildEmbeddedSignatureHtml, htmlComposeBodyToPlainText, plainComposeBodyToHtml, stripEmbeddedSignature, } from '../compose-format'; import { SIGNATURE_BLOCK_MARKER, SIGNATURE_RANGE_MARKER, containsEmbeddedSignature } from '../signature-block'; import { plainTextBodyHasSignature } from '@/lib/signature-utils'; const identity = { htmlSignature: 'Alice
Acme', textSignature: 'Alice\nAcme' }; const count = (haystack: string, needle: string) => haystack.split(needle).length - 1; describe('compose-format (#1022): HTML <-> plain text switch', () => { describe('stripEmbeddedSignature', () => { it('removes the marker-bracketed range and reports it', () => { const html = `

Hi

${buildEmbeddedSignatureHtml(identity, { embed: true, separator: true })}`; const out = stripEmbeddedSignature(html); expect(out.hadSignature).toBe(true); expect(out.html).toBe('

Hi

'); }); it('stops before the quote when the end marker is missing', () => { const html = `

Hi

--

Alice

original
`; const out = stripEmbeddedSignature(html); expect(out.hadSignature).toBe(true); expect(out.html).toBe('

Hi

original
'); }); it('leaves a body without markers untouched', () => { expect(stripEmbeddedSignature('

Hi

')).toEqual({ html: '

Hi

', hadSignature: false }); }); }); describe('htmlComposeBodyToPlainText', () => { it('flattens formatting and carries the signature over as plain text', () => { const html = `

Hello there

Second

${buildEmbeddedSignatureHtml(identity, { embed: true, separator: true })}`; const text = htmlComposeBodyToPlainText(html, identity, { separator: true }); expect(text).toBe('Hello there\n\nSecond\n\n-- \nAlice\nAcme'); expect(plainTextBodyHasSignature(text, identity)).toBe(true); expect(count(text, 'Alice')).toBe(1); }); it('does not invent a signature for a body that had none (below-quote reply)', () => { const text = htmlComposeBodyToPlainText('

Thanks

original
', identity, { separator: true }); expect(text).toBe('Thanks\n\noriginal'); expect(plainTextBodyHasSignature(text, identity)).toBe(false); }); it('honours the separator setting', () => { const html = `

Hi

${buildEmbeddedSignatureHtml(identity, { embed: true, separator: false })}`; expect(htmlComposeBodyToPlainText(html, identity, { separator: false })).toBe('Hi\n\nAlice\nAcme'); }); }); describe('plainComposeBodyToHtml', () => { it('wraps paragraphs and re-embeds the signature with markers', () => { const html = plainComposeBodyToHtml('Hello\nthere\n\nSecond\n\n-- \nAlice\nAcme', identity, { separator: true }); expect(html.startsWith('

Hello
there

Second

')).toBe(true); expect(containsEmbeddedSignature(html)).toBe(true); expect(count(html, SIGNATURE_BLOCK_MARKER)).toBe(1); expect(html).toContain('Alice'); // The plain-text copy is gone - only the embedded HTML one remains. expect(count(html, 'Alice')).toBe(1); }); it('keeps a body without signature signature-free', () => { const html = plainComposeBodyToHtml('Thanks\n\n> original', identity, { separator: true }); expect(html).toBe('

Thanks

> original

'); expect(containsEmbeddedSignature(html)).toBe(false); }); it('gives an untouched signature-only body an empty paragraph to type into', () => { const html = plainComposeBodyToHtml('\n\n-- \nAlice\nAcme', identity, { separator: true }); expect(html.startsWith('

')).toBe(true); expect(containsEmbeddedSignature(html)).toBe(true); }); }); it('round-trips a compose body without duplicating or losing the signature', () => { const start = `

Draft text

${buildEmbeddedSignatureHtml(identity, { embed: true, separator: true })}`; const text = htmlComposeBodyToPlainText(start, identity, { separator: true }); const back = plainComposeBodyToHtml(text, identity, { separator: true }); expect(back).toBe(start); }); });