import { describe, it, expect, jest } from '@jest/globals'; import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom'; jest.mock('framer-motion', () => ({ motion: { div: ({ children, initial, animate, variants, className, whileHover, whileTap, ...props }: any) => (
{children}
), button: ({ children, onClick, className, whileHover, whileTap, ...props }: any) => ( ), span: ({ children, className, animate, ...props }: any) => ( {children} ), svg: ({ children, className, ...props }: any) => ( {children} ), circle: ({ variants, ...props }: any) => ( ), path: ({ variants, ...props }: any) => ( ), }, useInView: jest.fn(() => true), useSpring: jest.fn((value) => value), useTransform: jest.fn((value) => value), })); describe('Animation Variants', () => { describe('inkVariants', () => { it('should have correct hidden state', async () => { const { inkVariants } = await import('./animations'); expect(inkVariants.hidden).toEqual({ opacity: 0, scale: 0.8, filter: 'blur(10px)', }); }); it('should have correct visible state', async () => { const { inkVariants } = await import('./animations'); expect(inkVariants.visible).toHaveProperty('opacity', 1); expect(inkVariants.visible).toHaveProperty('scale', 1); expect(inkVariants.visible).toHaveProperty('filter', 'blur(0px)'); }); it('should have correct transition configuration', async () => { const { inkVariants } = await import('./animations'); const transition = (inkVariants.visible as any)?.transition; expect(transition.duration).toBe(0.8); expect(transition.ease).toEqual([0.16, 1, 0.3, 1]); }); }); describe('sealStampVariants', () => { it('should have correct hidden state', async () => { const { sealStampVariants } = await import('./animations'); expect(sealStampVariants.hidden).toEqual({ opacity: 0, scale: 1.5, rotate: -15, }); }); it('should have correct visible state', async () => { const { sealStampVariants } = await import('./animations'); expect(sealStampVariants.visible).toHaveProperty('opacity', 1); expect(sealStampVariants.visible).toHaveProperty('scale', 1); expect(sealStampVariants.visible).toHaveProperty('rotate', 0); }); it('should use spring animation', async () => { const { sealStampVariants } = await import('./animations'); const transition = (sealStampVariants.visible as any)?.transition; expect(transition.type).toBe('spring'); expect(transition.stiffness).toBe(300); expect(transition.damping).toBe(20); }); }); describe('brushStrokeVariants', () => { it('should have correct hidden state', async () => { const { brushStrokeVariants } = await import('./animations'); expect(brushStrokeVariants.hidden).toEqual({ pathLength: 0, opacity: 0, }); }); it('should have correct visible state', async () => { const { brushStrokeVariants } = await import('./animations'); expect(brushStrokeVariants.visible).toHaveProperty('pathLength', 1); expect(brushStrokeVariants.visible).toHaveProperty('opacity', 1); }); }); describe('fadeUpVariants', () => { it('should have correct hidden state', async () => { const { fadeUpVariants } = await import('./animations'); expect(fadeUpVariants.hidden).toEqual({ opacity: 0, y: 30, }); }); it('should have correct visible state', async () => { const { fadeUpVariants } = await import('./animations'); expect(fadeUpVariants.visible).toHaveProperty('opacity', 1); expect(fadeUpVariants.visible).toHaveProperty('y', 0); }); }); describe('staggerContainerVariants', () => { it('should have staggerChildren configured', async () => { const { staggerContainerVariants } = await import('./animations'); const transition = (staggerContainerVariants.visible as any)?.transition; expect(transition.staggerChildren).toBe(0.1); expect(transition.delayChildren).toBe(0.1); }); }); describe('staggerItemVariants', () => { it('should have correct hidden state', async () => { const { staggerItemVariants } = await import('./animations'); expect(staggerItemVariants.hidden).toEqual({ opacity: 0, y: 20, scale: 0.95, }); }); it('should have correct visible state', async () => { const { staggerItemVariants } = await import('./animations'); expect(staggerItemVariants.visible).toHaveProperty('opacity', 1); expect(staggerItemVariants.visible).toHaveProperty('y', 0); expect(staggerItemVariants.visible).toHaveProperty('scale', 1); }); }); }); describe('Animation Components', () => { describe('InkReveal', () => { it('should render children correctly', async () => { const { InkReveal } = await import('./animations'); render(Test Content); expect(screen.getByText('Test Content')).toBeInTheDocument(); }); it('should apply custom className', async () => { const { InkReveal } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); expect(element).toHaveClass('custom-class'); }); it('should use inkVariants', async () => { const { InkReveal, inkVariants } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const variants = JSON.parse(element.getAttribute('data-variants') || '{}'); expect(variants).toEqual(inkVariants); }); }); describe('SealStamp', () => { it('should render children correctly', async () => { const { SealStamp } = await import('./animations'); render(Seal Content); expect(screen.getByText('Seal Content')).toBeInTheDocument(); }); it('should apply custom className', async () => { const { SealStamp } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); expect(element).toHaveClass('seal-class'); }); }); describe('FadeUp', () => { it('should render children correctly', async () => { const { FadeUp } = await import('./animations'); render(Fade Content); expect(screen.getByText('Fade Content')).toBeInTheDocument(); }); it('should apply custom duration', async () => { const { FadeUp } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const variants = JSON.parse(element.getAttribute('data-variants') || '{}'); expect(variants.visible.transition.duration).toBe(1.2); }); it('should apply delay prop', async () => { const { FadeUp } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const variants = JSON.parse(element.getAttribute('data-variants') || '{}'); expect(variants.visible.transition.delay).toBe(0.3); }); }); describe('StaggerContainer', () => { it('should render children correctly', async () => { const { StaggerContainer } = await import('./animations'); render(
Item 1
Item 2
); expect(screen.getByText('Item 1')).toBeInTheDocument(); expect(screen.getByText('Item 2')).toBeInTheDocument(); }); it('should apply custom staggerDelay', async () => { const { StaggerContainer } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const variants = JSON.parse(element.getAttribute('data-variants') || '{}'); expect(variants.visible.transition.staggerChildren).toBe(0.2); }); }); describe('StaggerItem', () => { it('should render children correctly', async () => { const { StaggerItem } = await import('./animations'); render(Item Content); expect(screen.getByText('Item Content')).toBeInTheDocument(); }); }); describe('RippleButton', () => { it('should render children correctly', async () => { const { RippleButton } = await import('./animations'); render(Click Me); expect(screen.getByText('Click Me')).toBeInTheDocument(); }); it('should handle click events', async () => { const { RippleButton } = await import('./animations'); const handleClick = jest.fn(); render(Click Me); const button = screen.getByTestId('motion-button'); fireEvent.click(button); expect(handleClick).toHaveBeenCalled(); }); it('should apply custom className', async () => { const { RippleButton } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-button'); expect(element).toHaveClass('custom-button'); }); }); describe('InkCard', () => { it('should render children correctly', async () => { const { InkCard } = await import('./animations'); render(Card Content); expect(screen.getByText('Card Content')).toBeInTheDocument(); }); it('should apply custom hoverScale', async () => { const { InkCard } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const whileHover = JSON.parse(element.getAttribute('data-while-hover') || '{}'); expect(whileHover.scale).toBe(1.1); }); }); describe('CountUp', () => { it('should render with prefix and suffix', async () => { const { CountUp } = await import('./animations'); render(); expect(screen.getByText(/\$/)).toBeInTheDocument(); expect(screen.getByText(/%/)).toBeInTheDocument(); }); it('should apply custom className', async () => { const { CountUp } = await import('./animations'); render(); const element = screen.getByTestId('motion-span'); expect(element).toHaveClass('counter-class'); }); }); describe('Typewriter', () => { it('should render component correctly', async () => { const { Typewriter } = await import('./animations'); render(); const cursor = screen.getByText('|'); expect(cursor).toBeInTheDocument(); }); it('should apply custom className', async () => { const { Typewriter } = await import('./animations'); render(); const container = screen.getByText('|').closest('.typewriter-class'); expect(container).toBeInTheDocument(); }); }); describe('FloatingElement', () => { it('should render children correctly', async () => { const { FloatingElement } = await import('./animations'); render(Floating Content); expect(screen.getByText('Floating Content')).toBeInTheDocument(); }); it('should apply custom amplitude', async () => { const { FloatingElement } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const animate = JSON.parse(element.getAttribute('data-animate') || '{}'); expect(animate.y).toEqual([-20, 20, -20]); }); }); describe('PulseElement', () => { it('should render children correctly', async () => { const { PulseElement } = await import('./animations'); render(Pulse Content); expect(screen.getByText('Pulse Content')).toBeInTheDocument(); }); it('should apply custom scale', async () => { const { PulseElement } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); const animate = JSON.parse(element.getAttribute('data-animate') || '{}'); expect(animate.scale).toEqual([1, 1.1, 1]); }); }); describe('GradientText', () => { it('should render children correctly', async () => { const { GradientText } = await import('./animations'); render(Gradient Text); expect(screen.getByText('Gradient Text')).toBeInTheDocument(); }); it('should apply custom colors', async () => { const { GradientText } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-span'); expect(element).toBeInTheDocument(); }); }); describe('SplitText', () => { it('should render text correctly', async () => { const { SplitText } = await import('./animations'); render(); expect(screen.getByText('H')).toBeInTheDocument(); expect(screen.getByText('i')).toBeInTheDocument(); }); it('should apply custom className', async () => { const { SplitText } = await import('./animations'); render(); const elements = screen.getAllByTestId('motion-span'); const parentElement = elements.find(el => el.classList.contains('split-class')); expect(parentElement).toBeDefined(); }); }); describe('GlitchText', () => { it('should render text correctly', async () => { const { GlitchText } = await import('./animations'); render(); const glitchElements = screen.getAllByText('Glitch'); expect(glitchElements.length).toBeGreaterThan(0); }); it('should apply custom className', async () => { const { GlitchText } = await import('./animations'); render(); const testElements = screen.getAllByText('Test'); const container = testElements[0]?.closest('.glitch-class'); expect(container).toBeInTheDocument(); }); }); describe('MagneticButton', () => { it('should render children correctly', async () => { const { MagneticButton } = await import('./animations'); render(Magnetic); expect(screen.getByText('Magnetic')).toBeInTheDocument(); }); it('should handle click events', async () => { const { MagneticButton } = await import('./animations'); const handleClick = jest.fn(); render(Click); const element = screen.getByText('Click'); fireEvent.click(element); expect(handleClick).toHaveBeenCalled(); }); }); describe('BlurReveal', () => { it('should render children correctly', async () => { const { BlurReveal } = await import('./animations'); render(Blur Content); expect(screen.getByText('Blur Content')).toBeInTheDocument(); }); it('should apply custom className', async () => { const { BlurReveal } = await import('./animations'); render(Test); const element = screen.getByTestId('motion-div'); expect(element).toHaveClass('blur-class'); }); }); describe('WaveText', () => { it('should render text correctly', async () => { const { WaveText } = await import('./animations'); render(); expect(screen.getByText('H')).toBeInTheDocument(); expect(screen.getByText('i')).toBeInTheDocument(); }); }); describe('ShimmerButton', () => { it('should render children correctly', async () => { const { ShimmerButton } = await import('./animations'); render(Shimmer); expect(screen.getByText('Shimmer')).toBeInTheDocument(); }); it('should handle click events', async () => { const { ShimmerButton } = await import('./animations'); const handleClick = jest.fn(); render(Click); const button = screen.getByTestId('motion-button'); fireEvent.click(button); expect(handleClick).toHaveBeenCalled(); }); }); }); describe('Animation Hooks', () => { describe('useParallax', () => { it('should be defined', async () => { const { useParallax } = await import('./animations'); expect(useParallax).toBeDefined(); }); }); describe('useSmoothSpring', () => { it('should be defined', async () => { const { useSmoothSpring } = await import('./animations'); expect(useSmoothSpring).toBeDefined(); }); }); }); describe('SVG Components', () => { describe('InkDropSVG', () => { it('should render SVG correctly', async () => { const { InkDropSVG } = await import('./animations'); render(); expect(screen.getByTestId('motion-svg')).toBeInTheDocument(); expect(screen.getByTestId('motion-circle')).toBeInTheDocument(); }); it('should apply custom className', async () => { const { InkDropSVG } = await import('./animations'); render(); const element = screen.getByTestId('motion-svg'); expect(element).toHaveClass('ink-drop-class'); }); }); describe('InkSplash', () => { it('should render SVG correctly', async () => { const { InkSplash } = await import('./animations'); render(); expect(screen.getByTestId('motion-svg')).toBeInTheDocument(); expect(screen.getByTestId('motion-path')).toBeInTheDocument(); }); it('should apply custom color', async () => { const { InkSplash } = await import('./animations'); render(); const path = screen.getByTestId('motion-path'); expect(path).toHaveAttribute('fill', '#ff0000'); }); it('should apply custom size', async () => { const { InkSplash } = await import('./animations'); render(); const svg = screen.getByTestId('motion-svg'); expect(svg).toHaveAttribute('width', '200'); expect(svg).toHaveAttribute('height', '200'); }); }); });