import { describe, it, expect } from 'vitest'; import { zipSync, strToU8 } from 'fflate'; import { importDocx } from '../../src/lib/import/docx'; // A 1x1 PNG — real bytes so the importer's magic-number sniff accepts the media. const PNG = Uint8Array.from( atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='), (c) => c.charCodeAt(0), ); const REL = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'; function docx(files: Record): Uint8Array { const entries: Record = {}; for (const [k, v] of Object.entries(files)) entries[k] = typeof v === 'string' ? strToU8(v) : v; return zipSync(entries); } // Header with a floating full-page VML background ("Falzmarken"-style, position:absolute, // A4-sized) followed by a genuine inline (as-character) logo. Templates put backgrounds // and watermarks there; the one-paragraph zone can't position them, so they're dropped. const HEADER_XML = ` `; const DOCUMENT_XML = ` Body `; const rel = (id: string, type: string, target: string) => ``; function images(node: any, out: any[] = []): any[] { if (node?.type === 'image') out.push(node); for (const c of node?.content ?? []) images(c, out); return out; } describe('DOCX header floating image', () => { const bytes = docx({ 'word/document.xml': DOCUMENT_XML, 'word/_rels/document.xml.rels': `${rel('rId1', 'header', 'header1.xml')}`, 'word/header1.xml': HEADER_XML, 'word/_rels/header1.xml.rels': `${rel('rIdBg', 'image', 'media/bg.png')}${rel('rIdLogo', 'image', 'media/logo.png')}`, 'word/media/bg.png': PNG, 'word/media/logo.png': PNG, }); it('drops the full-page floating background but keeps the inline logo', () => { const res = importDocx(bytes); const imgs = images(res.header); // Only the inline logo (571500 EMU ≈ 60px), never the A4-sized page background (≈794px). expect(imgs).toHaveLength(1); expect(imgs[0].attrs.width).toBe(60); expect(imgs.some((i) => i.attrs.width > 700)).toBe(false); expect([...res.warnings]).toContain('Drawings were removed'); }); });