You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.0 KiB
116 lines
3.0 KiB
// @vitest-environment jsdom
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { BodyScrollLock } from '../body-scroll-lock.svelte';
|
|
|
|
describe('BodyScrollLock', () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
BodyScrollLock.reset();
|
|
document.body.setAttribute('style', 'background: red;');
|
|
Object.defineProperty(window, 'innerWidth', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: 1200
|
|
});
|
|
Object.defineProperty(document.documentElement, 'clientWidth', {
|
|
configurable: true,
|
|
value: 1180
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
BodyScrollLock.reset();
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('locks body scroll and restores the initial body style when unlocked', async () => {
|
|
const lock = new BodyScrollLock(true);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.overflow).toBe('hidden');
|
|
expect(document.body.style.getPropertyValue('--scrollbar-width')).toBe('20px');
|
|
|
|
lock.locked.current = false;
|
|
vi.runAllTimers();
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.getAttribute('style')).toBe('background: red;');
|
|
});
|
|
|
|
it('does not block pointer events while locked', async () => {
|
|
const lock = new BodyScrollLock(true);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.pointerEvents).toBe('');
|
|
|
|
lock.destroy();
|
|
vi.runAllTimers();
|
|
await Promise.resolve();
|
|
});
|
|
|
|
it('keeps the body locked until the last lock is released', async () => {
|
|
const first = new BodyScrollLock(true);
|
|
const second = new BodyScrollLock(true);
|
|
await Promise.resolve();
|
|
|
|
first.locked.current = false;
|
|
vi.runAllTimers();
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.overflow).toBe('hidden');
|
|
|
|
second.destroy();
|
|
vi.runAllTimers();
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.getAttribute('style')).toBe('background: red;');
|
|
});
|
|
|
|
it('uses the last active lock delay instead of stale unlocked instances', async () => {
|
|
const first = new BodyScrollLock(true, () => 200);
|
|
const second = new BodyScrollLock(true, () => 50);
|
|
await Promise.resolve();
|
|
|
|
first.locked.current = false;
|
|
vi.runAllTimers();
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.overflow).toBe('hidden');
|
|
|
|
second.locked.current = false;
|
|
vi.advanceTimersByTime(49);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.overflow).toBe('hidden');
|
|
|
|
vi.advanceTimersByTime(1);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.getAttribute('style')).toBe('background: red;');
|
|
});
|
|
|
|
it('keeps the final lock restore delay when destroyed', async () => {
|
|
const lock = new BodyScrollLock(true, () => 120);
|
|
await Promise.resolve();
|
|
|
|
lock.destroy();
|
|
vi.advanceTimersByTime(119);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.style.overflow).toBe('hidden');
|
|
|
|
vi.advanceTimersByTime(1);
|
|
await Promise.resolve();
|
|
|
|
expect(document.body.getAttribute('style')).toBe('background: red;');
|
|
});
|
|
|
|
it('allows creating unlocked instances without mutating the body', () => {
|
|
new BodyScrollLock(false);
|
|
|
|
expect(document.body.getAttribute('style')).toBe('background: red;');
|
|
});
|
|
});
|