// @vitest-environment jsdom // // Integration tests for the installer IIFE (`install.ts`). These import the real // module so the self-executing installer runs in jsdom, then assert behavior by // observing the mocked global bundles (`window.AgentWidget` / // `window.AgentWidgetLauncher`) and the lifecycle callbacks / DOM events. // // The installer defers loading to `setTimeout` (via `waitForHydration`, since // jsdom has no `requestIdleCallback`), so tests use fake timers and // `vi.runAllTimersAsync()` to drive it forward deterministically. import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const PERSONA_EVENTS = [ "persona:script-load", "persona:launcher-shown", "persona:chat-ready", "persona:error", ] as const; type FakeHandle = { open: ReturnType; close: ReturnType; on: ReturnType }; // Captured across a single installer run. let capturedOnOpen: (() => void) | null; let launcherMount: ReturnType; let launcherDestroy: ReturnType; let launcherElement: HTMLButtonElement; let initAgentWidget: ReturnType; let fakeHandle: FakeHandle; let errorSpy: ReturnType; /** Subscribe to every persona:* event and record dispatch order + detail. */ function recordEvents() { const log: Array<{ type: string; detail: any }> = []; const handlers: Array<[string, (e: Event) => void]> = []; for (const type of PERSONA_EVENTS) { const handler = (e: Event) => log.push({ type, detail: (e as CustomEvent).detail }); window.addEventListener(type, handler); handlers.push([type, handler]); } return { log, types: () => log.map((entry) => entry.type), stop() { handlers.forEach(([type, handler]) => window.removeEventListener(type, handler)); }, }; } /** Make `isCssLoaded()` return true so `loadCSS()` resolves without a network. */ function markCssLoaded() { const link = document.createElement("link"); link.rel = "stylesheet"; link.setAttribute("data-persona", "true"); document.head.appendChild(link); } /** Provide the full bundle global so `loadJS()` short-circuits to resolved. */ function provideFullBundle() { (window as any).AgentWidget = { initAgentWidget }; } /** Provide the critical launcher global so `loadLauncher()` short-circuits. */ function provideLauncherBundle() { (window as any).AgentWidgetLauncher = { mount: launcherMount }; } /** * Force the next dynamically-inserted