125 lines
4.4 KiB
TypeScript
125 lines
4.4 KiB
TypeScript
|
|
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<typeof usePolling>[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();
|
||
|
|
});
|
||
|
|
});
|