import { describe, expect, it, vi } from 'vitest'; import { PhotoGallery, wrapIndex } from './photos'; const thumbnail = (id: string, order: number, alt: string): string => ` ${alt} `; const setup = () => { vi.stubGlobal('matchMedia', () => ({ matches: false, media: '(prefers-reduced-motion: reduce)', onchange: null, addEventListener: vi.fn(), removeEventListener: vi.fn(), addListener: vi.fn(), removeListener: vi.fn(), dispatchEvent: vi.fn(), })); window.HTMLElement.prototype.scrollIntoView = vi.fn(); document.body.innerHTML = `
${thumbnail('one', 1, 'First photo')} ${thumbnail('two', 2, 'Second photo')}
`; const gallery = document.querySelector('#gallery'); const frame = document.querySelector('#frame-content'); const toggle = document.querySelector('#toggle'); if (!gallery || !frame || !toggle) { throw new Error('Test DOM failed to initialize.'); } return { gallery, frame, toggle }; }; describe('wrapIndex', () => { it('wraps backward to the last item', () => { expect(wrapIndex(-1, 4)).toBe(3); }); it('wraps forward to the first item', () => { expect(wrapIndex(4, 4)).toBe(0); }); it('rejects empty collections', () => { expect(() => wrapIndex(0, 0)).toThrow('without items'); }); }); describe('PhotoGallery', () => { it('builds the frame from the clicked thumbnail and marks it current', () => { const { gallery, frame, toggle } = setup(); new PhotoGallery({ gallery, frame, toggle, autoAdvance: false }); gallery .querySelector('[data-photo-id="two"]') ?.dispatchEvent( new MouseEvent('click', { bubbles: true, cancelable: true }) ); const image = frame.querySelector('img'); expect(image?.alt).toBe('Second photo'); expect(image?.id).toBe('frame-image'); expect(image?.getAttribute('src')).toBe('static/photos/two-2400.jpg'); expect(frame.querySelector('figcaption')?.textContent).toBe('Second photo'); expect( gallery .querySelector('[data-photo-id="two"]') ?.getAttribute('aria-current') ).toBe('true'); }); it('wraps with arrow-key navigation', () => { const { gallery, frame, toggle } = setup(); new PhotoGallery({ gallery, frame, toggle, autoAdvance: false }); gallery.dispatchEvent( new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true, cancelable: true, }) ); expect(frame.querySelector('img')?.alt).toBe('Second photo'); }); });