Files
nimbus/resources/js/tests/composables/useTabHorizontalScroll.test.ts
Mazen Touati 6ba071dc98 test: front-end tests cleanup (round 1)
the aim is to make the tests more about the behavior rather than implementation, add some missing tests, and improve the code.
2025-11-16 19:03:40 +01:00

96 lines
3.1 KiB
TypeScript

import { useTabHorizontalScroll } from '@/composables/ui/useTabHorizontalScroll';
import { describe, expect, it, vi } from 'vitest';
import { effectScope } from 'vue';
const scrollMocks = vi.hoisted(() => ({
getScrollBounds: vi.fn(() => ({ current: 50 })),
getMaskVisibility: vi.fn(() => ({ showLeftMask: true, showRightMask: false })),
getElementVisibility: vi.fn(() => ({ isFullyVisible: false })),
calculateScrollToElement: vi.fn(() => 120),
}));
const debounceMock = vi.hoisted(() => vi.fn((fn: () => void) => fn));
vi.mock('@/utils/scroll', () => scrollMocks);
vi.mock('@vueuse/core', () => ({
useDebounceFn: debounceMock,
}));
describe('useTabHorizontalScroll', () => {
const runComposable = () => {
let composable: ReturnType<typeof useTabHorizontalScroll>;
effectScope().run(() => {
composable = useTabHorizontalScroll({
MASK_WIDTH: 20,
SCROLL_THRESHOLD: 30,
SCROLL_PADDING: 10,
ANIMATION_DURATION: 0,
DEBOUNCE_DELAY: 0,
});
});
// @ts-expect-error assigned above
return composable as ReturnType<typeof useTabHorizontalScroll>;
};
it('updates mask visibility and saves scroll position', () => {
const composable = runComposable();
const container = {
scrollLeft: 0,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
} as unknown as HTMLElement;
composable.scrollContainer.value = container;
composable.updateScrollMasks();
expect(scrollMocks.getScrollBounds).toHaveBeenCalledWith(container, 30);
expect(scrollMocks.getMaskVisibility).toHaveBeenCalled();
expect(composable.showLeftMask.value).toBe(true);
expect(composable.showRightMask.value).toBe(false);
});
it('scrolls tab into view when not visible', () => {
vi.useFakeTimers();
const composable = runComposable();
const scrollTo = vi.fn();
composable.scrollContainer.value = {
scrollTo,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
} as unknown as HTMLElement;
const button = document.createElement('button');
composable.scrollTabIntoView(button);
expect(scrollMocks.getElementVisibility).toHaveBeenCalled();
expect(scrollMocks.calculateScrollToElement).toHaveBeenCalled();
expect(scrollTo).toHaveBeenCalledWith({ left: 120, behavior: 'smooth' });
vi.useRealTimers();
});
it('restores saved scroll position', async () => {
const composable = runComposable();
const container = {
scrollLeft: 0,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
} as unknown as HTMLElement;
composable.scrollContainer.value = container;
composable.updateScrollMasks();
composable.scrollContainer.value!.scrollLeft = 0;
await composable.restoreScrollPosition();
expect(container.scrollLeft).toBe(50);
});
});