(overrides: Record<string, unknown> = {})
| 18 | `; |
| 19 | |
| 20 | function buildMockIframe(overrides: Record<string, unknown> = {}) { |
| 21 | const scriptEl = document.createElement("script"); |
| 22 | scriptEl.textContent = |
| 23 | 'const tl = gsap.timeline({ paused: true }); tl.to("#box", { opacity: 0.5 });'; |
| 24 | const container = document.createElement("div"); |
| 25 | container.appendChild(scriptEl); |
| 26 | |
| 27 | const mockTimeline = { kill: vi.fn(), pause: vi.fn() }; |
| 28 | const contentWindow = { |
| 29 | gsap: { timeline: vi.fn() }, |
| 30 | __hfForceTimelineRebind: vi.fn(), |
| 31 | __timelines: { root: mockTimeline } as Record<string, typeof mockTimeline>, |
| 32 | __player: { getTime: () => 2.0, seek: vi.fn() }, |
| 33 | __hfStudioManualEditsApply: vi.fn(), |
| 34 | __hfSuppressSceneMutations: undefined as undefined | (<T>(fn: () => T) => T), |
| 35 | ...overrides, |
| 36 | }; |
| 37 | |
| 38 | // Intercept appendChild: when a <script> is appended, simulate execution by |
| 39 | // repopulating __timelines (mimicking what the real GSAP script would do). |
| 40 | const realAppendChild = container.appendChild.bind(container); |
| 41 | container.appendChild = <T extends Node>(node: T): T => { |
| 42 | const result = realAppendChild(node); |
| 43 | if (node instanceof HTMLScriptElement && node.textContent?.includes("gsap.timeline")) { |
| 44 | // Simulate the script populating __timelines |
| 45 | const cw = contentWindow as { __timelines?: Record<string, unknown> }; |
| 46 | if (cw.__timelines) { |
| 47 | cw.__timelines.root = { kill: vi.fn(), pause: vi.fn() }; |
| 48 | } |
| 49 | } |
| 50 | return result; |
| 51 | }; |
| 52 | |
| 53 | const contentDocument = { |
| 54 | querySelectorAll: (sel: string) => (sel === "script:not([src])" ? [scriptEl] : []), |
| 55 | createElement: (tag: string) => document.createElement(tag), |
| 56 | body: container, |
| 57 | head: document.createElement("div"), |
| 58 | }; |
| 59 | |
| 60 | return { |
| 61 | iframe: { contentWindow, contentDocument } as unknown as HTMLIFrameElement, |
| 62 | contentWindow, |
| 63 | mockTimeline, |
| 64 | }; |
| 65 | } |
| 66 | |
| 67 | describe("applySoftReload", () => { |
| 68 | it('returns "cannot-soft-reload" when iframe is null', () => { |
no outgoing calls
no test coverage detected