Files
portal/app/tests/Frontend/menuRepositionFix.spec.ts
T
Дмитрий 54451d2ea6 feat(projects): RegionsBulkDialog — subject-level regions (89 RF subjects) #1426
Bulk regions dialog reworked from federal-district bitmask to subject/region
selection, consistent with ProjectDetailsDrawer/NewProjectDialog. Full-stack:
add_regions/remove_regions on projects.regions INT[], BulkProjectActionRequest
split validation, ProjectService model-instance update. federal-districts.ts
removed (zero consumers). +menuRepositionFix util for v-autocomplete menu.
phpstan-baseline: bump actingAs ignore count 14->15 (new validation test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 03:41:46 +03:00

57 lines
2.4 KiB
TypeScript

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<void> => 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();
});
});