import { afterEach, beforeAll, beforeEach, describe, expect, it, mock } from 'bun:test'; const disableOpacityMock = mock(() => {}); const enableOpacityMock = mock(() => {}); const syncOpacityMock = mock(() => {}); mock.module('~/utils', () => ({ disableOpacity: disableOpacityMock, enableOpacity: enableOpacityMock, syncOpacity: syncOpacityMock, })); (globalThis as typeof globalThis & { defineNuxtPlugin?: (setup: () => void) => () => void }).defineNuxtPlugin = (setup) => setup; let plugin: Awaited['default']; let started = false; const flushMutations = async (): Promise => { await Promise.resolve(); await new Promise((resolve) => setTimeout(resolve, 0)); }; const createOverlay = (): HTMLDivElement => { const overlay = document.createElement('div'); overlay.setAttribute('data-slot', 'overlay'); return overlay; }; const startPlugin = (): void => { if (started) { return; } plugin(); document.dispatchEvent(new window.Event('DOMContentLoaded')); started = true; }; beforeAll(async () => { plugin = (await import('../../app/plugins/modal-opacity.client.ts')).default; }); beforeEach(() => { globalThis.MutationObserver = window.MutationObserver; document.body.innerHTML = ''; disableOpacityMock.mockClear(); enableOpacityMock.mockClear(); syncOpacityMock.mockClear(); }); afterEach(async () => { document.body.innerHTML = ''; await flushMutations(); }); describe('modal opacity plugin', () => { it('ignores a settings-only overlay', async () => { startPlugin(); const settingsPanel = document.createElement('div'); settingsPanel.className = 'yt-settings-panel'; document.body.append(settingsPanel, createOverlay()); await flushMutations(); expect(disableOpacityMock).not.toHaveBeenCalled(); expect(enableOpacityMock).not.toHaveBeenCalled(); expect(syncOpacityMock).not.toHaveBeenCalled(); }); it('restores opacity when a normal overlay closes back to settings-only', async () => { startPlugin(); const settingsPanel = document.createElement('div'); settingsPanel.className = 'yt-settings-panel'; const settingsOverlay = createOverlay(); const modalOverlay = createOverlay(); document.body.append(settingsPanel, settingsOverlay); await flushMutations(); document.body.append(modalOverlay); await flushMutations(); expect(disableOpacityMock).toHaveBeenCalledTimes(1); modalOverlay.remove(); await flushMutations(); expect(enableOpacityMock).toHaveBeenCalledTimes(1); }); it('resyncs opacity when overlays change while already locked', async () => { startPlugin(); document.body.append(createOverlay()); await flushMutations(); document.body.append(createOverlay()); await flushMutations(); expect(disableOpacityMock).toHaveBeenCalledTimes(1); expect(syncOpacityMock).toHaveBeenCalledTimes(1); }); it('does not unlock opacity on beforeunload when reload is canceled', async () => { startPlugin(); document.body.append(createOverlay()); await flushMutations(); expect(disableOpacityMock).toHaveBeenCalledTimes(1); window.dispatchEvent(new window.Event('beforeunload')); await flushMutations(); expect(enableOpacityMock).not.toHaveBeenCalled(); }); });