import { act, render, waitFor } from '@testing-library/react' import { StrictMode } from 'react' import { afterEach, describe, expect, it, vi } from 'vite-plus/test' import { createZendeskRuntime } from '../runtime' import { ZendeskScript } from '../script' describe('ZendeskScript', () => { afterEach(() => { vi.useRealTimers() vi.restoreAllMocks() window.zE = undefined }) it('does not insert the SDK script until loading is requested', async () => { const runtime = createZendeskRuntime(() => window.zE) const appendChild = vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node) const getScripts = () => appendChild.mock.calls .map(([node]) => node) .filter((node): node is HTMLScriptElement => node instanceof HTMLScriptElement) render() expect(getScripts()).toHaveLength(0) let loadPromise!: Promise act(() => { loadPromise = runtime.requestLoad() void runtime.requestLoad() }) await waitFor(() => expect(getScripts()).toHaveLength(1)) const script = getScripts()[0]! expect(script.src).toBe('https://static.zdassets.com/ekr/snippet.js?key=test-key') expect(script.nonce).toBe('test-nonce') window.zE = vi.fn() act(() => script.dispatchEvent(new Event('load'))) await loadPromise }) it('removes a failed script and inserts a fresh one when retried', async () => { const runtime = createZendeskRuntime(() => window.zE) const appendChild = vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node) const getScripts = () => appendChild.mock.calls .map(([node]) => node) .filter((node): node is HTMLScriptElement => node instanceof HTMLScriptElement) render() let failedLoad!: Promise act(() => { failedLoad = runtime.requestLoad() }) await waitFor(() => expect(getScripts()).toHaveLength(1)) const failedScript = getScripts()[0]! const failedExpectation = expect(failedLoad).rejects.toThrow('Failed to load Zendesk') act(() => failedScript.dispatchEvent(new Event('error'))) await failedExpectation let retryLoad!: Promise act(() => { retryLoad = runtime.requestLoad() }) await waitFor(() => expect(getScripts()).toHaveLength(2)) const retryScript = getScripts()[1]! expect(retryScript).not.toBe(failedScript) window.zE = vi.fn() act(() => retryScript.dispatchEvent(new Event('load'))) await retryLoad }) it('fails a stalled load so the user can retry', async () => { vi.useFakeTimers() const runtime = createZendeskRuntime(() => window.zE) const appendChild = vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node) const getScripts = () => appendChild.mock.calls .map(([node]) => node) .filter((node): node is HTMLScriptElement => node instanceof HTMLScriptElement) render() let stalledLoad!: Promise act(() => { stalledLoad = runtime.requestLoad() }) expect(getScripts()).toHaveLength(1) const stalledScript = getScripts()[0]! const remove = vi.spyOn(stalledScript, 'remove') const stalledExpectation = expect(stalledLoad).rejects.toThrow('Failed to load Zendesk') await act(() => vi.advanceTimersByTimeAsync(15_000)) await stalledExpectation expect(runtime.getSnapshot()).toEqual({ attempt: 1, status: 'error' }) expect(remove).toHaveBeenCalledOnce() }) it('fails the pending load when its loader unmounts', async () => { const runtime = createZendeskRuntime(() => window.zE) const appendChild = vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node) const loadPromise = runtime.requestLoad() const loadExpectation = expect(loadPromise).rejects.toThrow('Failed to load Zendesk') const { unmount } = render() const script = appendChild.mock.calls.at(-1)![0] as HTMLScriptElement const remove = vi.spyOn(script, 'remove') await act(async () => { unmount() await Promise.resolve() }) await loadExpectation expect(runtime.getSnapshot()).toEqual({ attempt: 1, status: 'error' }) expect(remove).toHaveBeenCalledOnce() }) it('keeps the first load active through Strict Mode effect replay', async () => { const runtime = createZendeskRuntime(() => window.zE) const appendChild = vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node) const loadPromise = runtime.requestLoad() render( , ) await act(() => Promise.resolve()) expect(runtime.getSnapshot()).toEqual({ attempt: 1, status: 'loading' }) const activeScript = appendChild.mock.calls.at(-1)![0] as HTMLScriptElement window.zE = vi.fn() act(() => activeScript.dispatchEvent(new Event('load'))) await loadPromise expect(runtime.getSnapshot()).toEqual({ attempt: 1, status: 'ready' }) }) })