// Test harness: boots the real editor against the mock CMS inside jsdom. import { act } from 'react' import { Api } from '../src/api' import { AuthManager } from '../src/auth' import { boot } from '../src/boot' import type { EditorHandle } from '../src/boot' import { createMockCms } from '../mock/server' import { renderPage } from '../mock/fixtures' export interface Harness { cms: ReturnType auth: AuthManager editor: EditorHandle /** Wait for async work (fetches, patch application, React). */ settle(): Promise shadow: ShadowRoot /** Click something inside the editor UI by accessible label. */ press(label: string): Promise cleanup(): void } /** `stale`: the DOM is the *published* page, and the store has moved on since (the base-page problem). */ export async function setup(opts: { token?: string; auth?: boolean; stale?: boolean; noPreviewApi?: boolean; keepStorage?: boolean } = {}): Promise { // Fresh profile by default: remembered panel state must not leak between tests. // Pass keepStorage to simulate a reload with the same profile. if (!opts.keepStorage) localStorage.clear() const cms = createMockCms({ token: opts.token, auth: opts.auth }) document.head.innerHTML = '' window.open = () => null document.body.innerHTML = renderPage(cms.graph).match(/([\s\S]*)<\/body>/)![1] if (opts.stale) cms.graph.edit([{ op: 'set', id: 'h1', data: { text: 'Latest from the store' } }]) if (opts.noPreviewApi) cms.disablePreviewApi() const auth = new AuthManager({ fetch: cms.fetch, persistent: null, session: null, sleep: (ms) => new Promise((r) => setTimeout(r, Math.min(ms, 5))) }) const api = new Api({ fetch: cms.fetch, auth }) let editor!: EditorHandle await act(async () => { editor = boot({ api }) }) const settle = () => act(async () => void (await new Promise((r) => setTimeout(r, 25)))) const shadow = document.getElementById('cms-onpage-editor')!.shadowRoot! return { cms, auth, editor, settle, shadow, async press(label) { const el = shadow.querySelector(`[aria-label="${label}"], [title="${label}"]`) if (!el) throw new Error(`no control "${label}" in editor UI`) await act(async () => el.click()) await settle() }, cleanup() { editor.destroy() document.body.innerHTML = '' }, } } export const click = (el: Element) => el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, composed: true })) export const byId = (id: string) => document.querySelector(`[data-cms="${id}"]`)!