import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { defineComponent, h } from 'vue'; import { mount } from '@vue/test-utils'; import { usePolling } from '../../resources/js/composables/usePolling'; /** * Тесты polling-composable. Используется fake-timers — `setInterval` под * контролем `vi.advanceTimersByTime` для детерминированности. */ beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); // Сбросим document.hidden если он был установлен. Object.defineProperty(document, 'hidden', { value: false, configurable: true, writable: true }); }); function makeHostComponent(loader: () => void, options?: Parameters[1]) { return defineComponent({ setup() { usePolling(loader, options); return () => h('div'); }, }); } describe('usePolling', () => { it('вызывает loader каждые intervalMs миллисекунд', () => { const loader = vi.fn(); const Host = makeHostComponent(loader, { intervalMs: 5000 }); const wrapper = mount(Host); expect(loader).not.toHaveBeenCalled(); // только onMounted, без stale-вызова vi.advanceTimersByTime(5000); expect(loader).toHaveBeenCalledTimes(1); vi.advanceTimersByTime(5000); expect(loader).toHaveBeenCalledTimes(2); wrapper.unmount(); }); it('default intervalMs = 30 секунд', () => { const loader = vi.fn(); const Host = makeHostComponent(loader); const wrapper = mount(Host); vi.advanceTimersByTime(29_999); expect(loader).not.toHaveBeenCalled(); vi.advanceTimersByTime(1); expect(loader).toHaveBeenCalledTimes(1); wrapper.unmount(); }); it('skip loader когда document.hidden=true', () => { const loader = vi.fn(); const Host = makeHostComponent(loader, { intervalMs: 1000 }); const wrapper = mount(Host); Object.defineProperty(document, 'hidden', { value: true, configurable: true, writable: true }); vi.advanceTimersByTime(3000); expect(loader).not.toHaveBeenCalled(); Object.defineProperty(document, 'hidden', { value: false, configurable: true, writable: true }); vi.advanceTimersByTime(1000); expect(loader).toHaveBeenCalledTimes(1); wrapper.unmount(); }); it('cleanup на unmount — больше не вызывает loader', () => { const loader = vi.fn(); const Host = makeHostComponent(loader, { intervalMs: 1000 }); const wrapper = mount(Host); vi.advanceTimersByTime(1000); expect(loader).toHaveBeenCalledTimes(1); wrapper.unmount(); vi.advanceTimersByTime(10_000); expect(loader).toHaveBeenCalledTimes(1); // больше не растёт }); it('enabled=false — loader НЕ вызывается совсем', () => { const loader = vi.fn(); const Host = makeHostComponent(loader, { intervalMs: 1000, enabled: false }); const wrapper = mount(Host); vi.advanceTimersByTime(10_000); expect(loader).not.toHaveBeenCalled(); wrapper.unmount(); }); it('visibilitychange — pause при hidden и resume на возврате с немедленным loader', () => { const loader = vi.fn(); const Host = makeHostComponent(loader, { intervalMs: 5000 }); const wrapper = mount(Host); // Скрываем вкладку — interval останавливается. Object.defineProperty(document, 'hidden', { value: true, configurable: true, writable: true }); document.dispatchEvent(new Event('visibilitychange')); vi.advanceTimersByTime(20_000); expect(loader).not.toHaveBeenCalled(); // interval остановлен // Возвращаемся — должен сразу вызваться loader (без ожидания interval). Object.defineProperty(document, 'hidden', { value: false, configurable: true, writable: true }); document.dispatchEvent(new Event('visibilitychange')); expect(loader).toHaveBeenCalledTimes(1); // И interval снова работает. vi.advanceTimersByTime(5000); expect(loader).toHaveBeenCalledTimes(2); wrapper.unmount(); }); });