import { describe, test, expect, vi, afterEach } from 'vitest'; import React from 'react'; import { createRoot, Root } from 'react-dom/client'; import { act } from 'react-dom/test-utils'; import { HeadCodeModal } from './HeadCodeModal'; import { SiteDesignProvider, useSiteDesign } from '../../state/SiteDesignContext'; /* ---------- DOM test harness -- same react-dom/client + `act` pattern used throughout src/ui/*.test.tsx (no @testing-library/react in this repo). ---------- */ let container: HTMLDivElement; let root: Root; function render(ui: React.ReactElement) { container = document.createElement('div'); document.body.appendChild(container); act(() => { root = createRoot(container); root.render(ui); }); } afterEach(() => { if (container) { act(() => { root.unmount(); }); container.remove(); } document.body.style.overflow = ''; }); // Exposes the current headCode so assertions can read it back after a // simulated edit -- CodeEditor writes through `updateDesign`, this just // surfaces the result. function Harness({ onReady }: { onReady: (headCode: string) => void }) { const { design } = useSiteDesign(); onReady(design.headCode); return null; } describe('HeadCodeModal', () => { // HeadCodeModal portals its content to document.body (see the comment in // HeadCodeModal.tsx), so the rendered DOM lives outside `container` -- // query document.body instead. test('renders the CodeEditor (fallback textarea path) seeded with the current headCode', () => { render( , ); // CodeMirror loads via async dynamic import (see CodeEditor.test.tsx); // synchronously after mount the fallback textarea is what's live. const textarea = document.body.querySelector('[data-testid="code-editor-fallback"]'); expect(textarea).not.toBeNull(); expect(textarea!.value).toBe(''); expect(textarea!.dataset.language).toBe('html'); }); test('typing in the editor writes through to SiteDesignContext.headCode', () => { let latestHeadCode = ''; render( { latestHeadCode = v; }} /> , ); const textarea = document.body.querySelector('[data-testid="code-editor-fallback"]')!; act(() => { const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')!.set!; setter.call(textarea, ''); textarea.dispatchEvent(new Event('input', { bubbles: true })); }); expect(latestHeadCode).toBe(''); }); test('does not render when closed', () => { render( , ); expect(document.body.querySelector('[data-testid="code-editor-fallback"]')).toBeNull(); }); });