import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { render, fireEvent } from '@testing-library/react'; import { PixelSlideIn } from '../../animations/PixelSlideIn'; import { mockMatchMedia } from './matchmedia-mock'; /** * jsdom lacks native CSS animation support, so React registers the * vendor-prefixed `webkitAnimationEnd` event there. Dispatch both variants — * exactly one is registered, so the handler fires exactly once. */ function dispatchAnimationEnd(el: Element) { fireEvent.animationEnd(el); el.dispatchEvent(new Event('webkitAnimationEnd', { bubbles: true })); } describe('PixelSlideIn', () => { it('renders children inside the wrapper', () => { const { getByText } = render(slide me); expect(getByText('slide me')).toBeTruthy(); }); it('slides from "down" by default with the default duration', () => { const { container } = render(x); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toContain('pxl-slide-down'); expect(el.style.animation).toContain('350ms'); }); it.each(['up', 'down', 'left', 'right'] as const)( 'from="%s" picks the matching keyframe', (from) => { const { container } = render(x); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toContain(`pxl-slide-${from}`); }, ); it('reflects duration, delay, distance and repeat props', () => { const { container } = render( x, ); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toContain('500ms'); expect(el.style.animation).toContain('100ms'); expect(el.style.animation).toContain(' 2 '); expect(el.style.getPropertyValue('--pxl-slide-distance')).toBe('24px'); }); it('does not animate when trigger={false} (controlled off)', () => { const { container } = render(x); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toBe(''); }); it('trigger="click" only animates after a click', () => { const { container } = render(x); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toBe(''); fireEvent.click(el); expect(el.style.animation).toContain('pxl-slide-down'); }); it('fires onComplete when the animation ends on the wrapper', () => { const onComplete = vi.fn(); const { container } = render(x); dispatchAnimationEnd(container.firstElementChild as HTMLElement); expect(onComplete).toHaveBeenCalledTimes(1); }); it('renders children statically (fully visible, no animation) when the user prefers reduced motion', () => { const ctl = mockMatchMedia(true); try { const { container, getByText } = render(calm); const el = container.firstElementChild as HTMLElement; expect(el.style.animation).toBe(''); expect(getByText('calm')).toBeTruthy(); } finally { ctl.restore(); } }); it('forwards className and injects the shared keyframes stylesheet once', () => { const { container } = render(x); const el = container.firstElementChild as HTMLElement; expect(el.className).toContain('custom'); expect(document.querySelectorAll('#pxl-anims')).toHaveLength(1); }); });