import { flushPromises, mount } from '@vue/test-utils' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import MoleculeInput from '../../components/MoleculeInput.vue' type JSMEWindow = Window & { __jsmeLoaded__?: boolean __jsmeLoadPromise__?: Promise JSApplet?: { JSME?: new (...args: unknown[]) => unknown } jsmeOnLoad?: () => void } const jsmeWindow = window as JSMEWindow const happyDOMSettings = (window as unknown as { happyDOM: { settings: { handleDisabledFileLoadingAsSuccess: boolean } } }).happyDOM.settings beforeEach(() => { // A browser loads the CDN script asynchronously; happy-dom would fail it synchronously. happyDOMSettings.handleDisabledFileLoadingAsSuccess = true }) afterEach(() => { happyDOMSettings.handleDisabledFileLoadingAsSuccess = false vi.restoreAllMocks() delete jsmeWindow.__jsmeLoaded__ delete jsmeWindow.__jsmeLoadPromise__ delete jsmeWindow.JSApplet delete jsmeWindow.jsmeOnLoad document.querySelectorAll('script[data-jsme]').forEach(script => script.remove()) vi.useRealTimers() }) describe('MoleculeInput', () => { it('does not create an editor after the component is unmounted', async () => { let resolveLoad!: () => void jsmeWindow.__jsmeLoadPromise__ = new Promise(resolve => { resolveLoad = resolve }) const createEditor = vi.fn() const wrapper = mount(MoleculeInput) wrapper.unmount() jsmeWindow.JSApplet = { JSME: createEditor as unknown as new () => unknown } resolveLoad() await flushPromises() expect(createEditor).not.toHaveBeenCalled() }) it('should remove the failed script when the JSME load errors', async () => { const wrapper = mount(MoleculeInput) document.querySelector('script[data-jsme]')?.dispatchEvent(new Event('error')) await flushPromises() expect(document.querySelector('script[data-jsme]')).toBeNull() wrapper.unmount() }) it('should clear the cached loader when the JSME load times out', async () => { vi.useFakeTimers() const wrapper = mount(MoleculeInput) await vi.advanceTimersByTimeAsync(15000) expect(jsmeWindow.__jsmeLoadPromise__).toBeUndefined() wrapper.unmount() }) it('should clear the cached loader when an existing script never initializes', async () => { vi.useFakeTimers() const stale = document.createElement('script') stale.setAttribute('data-jsme', 'true') document.head.appendChild(stale) const wrapper = mount(MoleculeInput) await vi.advanceTimersByTimeAsync(15000) expect(jsmeWindow.__jsmeLoadPromise__).toBeUndefined() wrapper.unmount() }) })