import { describe, it, expect, vi, afterEach } from 'vitest'; import { repositionMenuAfterOpen } from '../../resources/js/utils/menuRepositionFix'; /** * Unit-тесты воркэраунда Vuetify location-strategy (см. menuRepositionFix.ts). * Реальный баг — гонка позиционирования в браузере под prefers-reduced-motion — * в jsdom не воспроизводится (нет layout); он покрыт Playwright-пробой. Здесь * проверяется контракт утилиты: при стабилизации overlay-меню шлётся один resize. */ function makeStableMenu(left: number): HTMLElement { const overlay = document.createElement('div'); overlay.className = 'v-overlay v-menu'; const content = document.createElement('div'); content.className = 'v-overlay__content'; content.getBoundingClientRect = () => ({ width: 400, height: 300, left, top: 50, right: left + 400, bottom: 350, x: left, y: 50, toJSON() {} }) as DOMRect; overlay.appendChild(content); document.body.appendChild(overlay); return overlay; } const wait = (ms: number): Promise => new Promise((r) => setTimeout(r, ms)); describe('repositionMenuAfterOpen', () => { afterEach(() => { document.querySelectorAll('.v-overlay').forEach((el) => el.remove()); }); it('does nothing when menu is closing (open=false)', async () => { const spy = vi.fn(); window.addEventListener('resize', spy); repositionMenuAfterOpen(false); await wait(200); window.removeEventListener('resize', spy); expect(spy).not.toHaveBeenCalled(); }); it('dispatches a single resize once the overlay content is geometrically stable', async () => { makeStableMenu(120); const spy = vi.fn(); window.addEventListener('resize', spy); repositionMenuAfterOpen(true); await wait(400); window.removeEventListener('resize', spy); expect(spy).toHaveBeenCalled(); }); it('does not dispatch resize or throw when no overlay is present', async () => { const spy = vi.fn(); window.addEventListener('resize', spy); expect(() => repositionMenuAfterOpen(true)).not.toThrow(); await wait(300); window.removeEventListener('resize', spy); expect(spy).not.toHaveBeenCalled(); }); });