/** * Component: Sticky Pagination Tests * Documentation: documentation/frontend/components.md */ // @vitest-environment jsdom import React from 'react'; import { act, fireEvent, render, screen } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { StickyPagination } from '@/components/ui/StickyPagination'; type ObserverEntry = { isIntersecting: boolean; intersectionRatio: number; target: Element; }; describe('StickyPagination', () => { const observers: { callback: IntersectionObserverCallback }[] = []; beforeEach(() => { observers.length = 0; class MockIntersectionObserver { callback: IntersectionObserverCallback; observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); takeRecords = vi.fn(); constructor(callback: IntersectionObserverCallback) { this.callback = callback; observers.push(this); } } (global as any).IntersectionObserver = MockIntersectionObserver; }); it('returns null when there is only one page', () => { const sectionRef = { current: document.createElement('div') }; const { container } = render( ); expect(container.firstChild).toBeNull(); }); it('shows and hides based on section and footer visibility', () => { const sectionRef = { current: document.createElement('div') }; const footerRef = { current: document.createElement('div') }; const { container } = render( ); const root = container.querySelector('div.fixed') as HTMLElement; expect(root).toHaveClass('opacity-0'); act(() => { observers[0].callback( [ { isIntersecting: true, intersectionRatio: 0.2, target: sectionRef.current as Element, } as ObserverEntry, ], observers[0] as unknown as IntersectionObserver ); }); expect(root).toHaveClass('opacity-100'); act(() => { observers[1].callback( [ { isIntersecting: true, intersectionRatio: 0.2, target: footerRef.current as Element, } as ObserverEntry, ], observers[1] as unknown as IntersectionObserver ); }); expect(root).toHaveClass('opacity-0'); }); it('handles navigation and jump input updates', () => { const sectionRef = { current: document.createElement('div') }; const onPageChange = vi.fn(); render( ); fireEvent.click(screen.getByLabelText('Next page')); expect(onPageChange).toHaveBeenCalledWith(3); fireEvent.click(screen.getByLabelText('Previous page')); expect(onPageChange).toHaveBeenCalledWith(1); const input = screen.getByLabelText('Current page') as HTMLInputElement; fireEvent.change(input, { target: { value: '4' } }); fireEvent.blur(input); expect(onPageChange).toHaveBeenCalledWith(4); fireEvent.change(input, { target: { value: '99' } }); fireEvent.blur(input); expect(input.value).toBe('2'); }); });