feat: autoplay() module with hover/focus pause and reduce-motion guard
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
|
||||
import { autoplay } from '../src/autoplay.ts';
|
||||
|
||||
function fakeCarousel(count = 3) {
|
||||
let index = 0;
|
||||
return {
|
||||
get index() {
|
||||
return index;
|
||||
},
|
||||
count,
|
||||
next: vi.fn(() => {
|
||||
index = (index + 1) % count;
|
||||
}),
|
||||
prev: vi.fn(),
|
||||
scrollToIndex: vi.fn(),
|
||||
on: () => () => {},
|
||||
destroy: vi.fn(),
|
||||
};
|
||||
}
|
||||
|
||||
// jsdom has no matchMedia — stub it. reduce = whether reduce-motion matches.
|
||||
function stubMatchMedia(reduce: boolean) {
|
||||
vi.stubGlobal('matchMedia', (q: string) => ({
|
||||
matches: reduce && q.includes('reduce'),
|
||||
media: q,
|
||||
addEventListener() {},
|
||||
removeEventListener() {},
|
||||
}));
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
stubMatchMedia(false);
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
test('advances every interval', () => {
|
||||
const c = fakeCarousel();
|
||||
autoplay(c as never, { interval: 1000, root: document.createElement('div') });
|
||||
vi.advanceTimersByTime(2000);
|
||||
expect(c.next).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('pause on pointerenter, resume on pointerleave', () => {
|
||||
const c = fakeCarousel();
|
||||
const root = document.createElement('div');
|
||||
autoplay(c as never, { interval: 1000, root });
|
||||
root.dispatchEvent(new Event('pointerenter'));
|
||||
vi.advanceTimersByTime(3000);
|
||||
expect(c.next).not.toHaveBeenCalled();
|
||||
root.dispatchEvent(new Event('pointerleave'));
|
||||
vi.advanceTimersByTime(1000);
|
||||
expect(c.next).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('does not start under prefers-reduced-motion', () => {
|
||||
stubMatchMedia(true);
|
||||
const c = fakeCarousel();
|
||||
autoplay(c as never, { interval: 1000, root: document.createElement('div') });
|
||||
vi.advanceTimersByTime(5000);
|
||||
expect(c.next).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('stop() halts and removes listeners', () => {
|
||||
const c = fakeCarousel();
|
||||
const stop = autoplay(c as never, { interval: 1000, root: document.createElement('div') });
|
||||
stop();
|
||||
vi.advanceTimersByTime(5000);
|
||||
expect(c.next).not.toHaveBeenCalled();
|
||||
});
|
||||
Reference in New Issue
Block a user