import { describe, it, expect } from 'vitest'; import { FdxExporter } from './fdx'; import type { ScreenplayElement } from '../screenplay/types'; const sampleElements: ScreenplayElement[] = [ { id: 'e1', type: 'sceneHeading', content: 'INT. COFFEE SHOP - DAY' }, { id: 'e2', type: 'action', content: 'A bustling coffee shop.' }, { id: 'e3', type: 'character', content: 'Jessica' }, { id: 'e4', type: 'dialogue', content: 'Hello there.' }, { id: 'e5', type: 'parenthetical', content: 'smiling' }, { id: 'e6', type: 'transition', content: 'SMASH CUT TO:' }, { id: 'e7', type: 'note', content: 'Writer note' }, { id: 'e8', type: 'retained', content: 'Retained from v1' }, { id: 'e9', type: 'centered', content: 'FADE OUT.' }, ]; describe('FdxExporter', () => { const exporter = new FdxExporter(); it('supports fdx format', () => { expect(exporter.supportedFormats).toContain('fdx'); }); it('produces valid XML structure', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain(''); expect(result.data).toContain(''); expect(result.data).toContain(''); }); it('includes title page', () => { const result = exporter.export(sampleElements, { format: 'fdx', title: 'Test Script', author: 'Jane Doe', }); expect(result.data).toContain(''); expect(result.data).toContain('Test Script'); expect(result.data).toContain('Jane Doe'); }); it('includes font face and page setup', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('FontFace'); expect(result.data).toContain('PageSetup'); }); it('exports scene headings as SceneHeading tags', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('INT. COFFEE SHOP - DAY'); }); it('exports action as Action tags', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('A bustling coffee shop.'); }); it('exports characters in uppercase', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('JESSICA'); }); it('exports dialogue', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('Hello there.'); }); it('exports parentheticals', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('smiling'); }); it('exports transitions in uppercase', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('SMASH CUT TO:'); }); it('exports notes', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('Writer note'); }); it('exports retained text', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('Retained from v1'); }); it('exports centered text', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.data).toContain('FADE OUT.'); }); it('escapes XML special characters', () => { const elements: ScreenplayElement[] = [ { id: 'e1', type: 'action', content: 'A sign reads: "Hello & Goodbye"' }, ]; const result = exporter.export(elements, { format: 'fdx' }); expect(result.data).toContain('&'); expect(result.data).toContain('"'); }); it('uses correct content type and extension', () => { const result = exporter.export(sampleElements, { format: 'fdx' }); expect(result.contentType).toBe('application/xml'); expect(result.extension).toBe('.fdx'); }); it('generates filename from title', () => { const result = exporter.export(sampleElements, { format: 'fdx', title: 'My Script' }); expect(result.filename).toBe('My_Script.fdx'); }); it('handles empty elements array', () => { const result = exporter.export([], { format: 'fdx' }); expect(result.data).toContain(''); expect(result.data).toContain(''); }); it('includes contact when provided', () => { const result = exporter.export(sampleElements, { format: 'fdx', contact: 'jane@example.com', }); expect(result.data).toContain('jane@example.com'); }); });