import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { InstalledPlugin } from '../plugin-types'; import { resetPluginRateLimits } from '../plugin-sandbox/host-api-input'; import { printDocument } from '../plugin-sandbox/host-api-print'; vi.mock('@/stores/toast-store', () => ({ toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn() }, })); import { dispatchApiCall } from '../plugin-sandbox/host-api'; const PLUGIN: InstalledPlugin = { id: 'e-invoice', name: 'E-Invoice', version: '1.0.0', author: 'test', description: '', type: 'ui-extension', permissions: [], grantedPermissions: [], entrypoint: 'index.js', enabled: true, status: 'running', settings: {}, }; const call = (method: string, ...args: unknown[]) => dispatchApiCall(PLUGIN, method, args); describe('api.ui.print', () => { let printed: string[]; beforeEach(() => { resetPluginRateLimits(); printed = []; document.querySelectorAll('iframe').forEach((f) => f.remove()); // jsdom neither loads srcdoc nor prints: load the frame when it is // attached and record what its print() would have printed. vi.spyOn(document.body, 'appendChild').mockImplementation(function (this: HTMLElement, node: Node) { HTMLElement.prototype.appendChild.call(this, node); if (node instanceof HTMLIFrameElement) { const srcdoc = node.srcdoc; node.contentWindow!.print = () => { printed.push(srcdoc); }; queueMicrotask(() => node.dispatchEvent(new Event('load'))); } return node; } as never); }); it('prints the page from a frame that runs no scripts and loads nothing', async () => { expect(await call('ui.print', { title: 'Rechnung 2026-117', html: '
Total119,00 €
' + '
', })).toBe(true); expect(printed).toHaveLength(1); const page = printed[0]; expect(page).toContain('Rechnung 2026-117'); expect(page).toContain('119,00 €'); expect(page).toContain('td { padding: 4px }'); expect(page).not.toContain(' { expect(printDocument('', '', 'ltr')).toContain('</title><script>'); await expect(call('ui.print', { html: 42 })).rejects.toThrow(/html must be a string/); await expect(call('ui.print', { title: 'a\nb', html: '' })).rejects.toThrow(/title must be one line/); await expect(call('ui.print', { html: '', url: 'https://x.example' })).rejects.toThrow(/unknown property "url"/); expect(printed).toEqual([]); }); it('prints at most three times a minute', async () => { for (let i = 0; i < 3; i++) await call('ui.print', { html: '<p>x</p>' }); await expect(call('ui.print', { html: '<p>x</p>' })).rejects.toThrow(/at most 3 times a minute/); expect(printed).toHaveLength(3); }); });