540 lines
20 KiB
TypeScript
540 lines
20 KiB
TypeScript
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) => (
|
|
<div
|
|
data-testid="motion-div"
|
|
data-initial={JSON.stringify(initial)}
|
|
data-animate={JSON.stringify(animate)}
|
|
data-variants={JSON.stringify(variants)}
|
|
data-while-hover={JSON.stringify(whileHover)}
|
|
data-while-tap={JSON.stringify(whileTap)}
|
|
className={className}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</div>
|
|
),
|
|
button: ({ children, onClick, className, whileHover, whileTap, ...props }: any) => (
|
|
<button
|
|
data-testid="motion-button"
|
|
onClick={onClick}
|
|
className={className}
|
|
data-while-hover={JSON.stringify(whileHover)}
|
|
data-while-tap={JSON.stringify(whileTap)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</button>
|
|
),
|
|
span: ({ children, className, animate, ...props }: any) => (
|
|
<span
|
|
data-testid="motion-span"
|
|
className={className}
|
|
data-animate={JSON.stringify(animate)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</span>
|
|
),
|
|
svg: ({ children, className, ...props }: any) => (
|
|
<svg data-testid="motion-svg" className={className} {...props}>
|
|
{children}
|
|
</svg>
|
|
),
|
|
circle: ({ variants, ...props }: any) => (
|
|
<circle data-testid="motion-circle" data-variants={JSON.stringify(variants)} {...props} />
|
|
),
|
|
path: ({ variants, ...props }: any) => (
|
|
<path data-testid="motion-path" data-variants={JSON.stringify(variants)} {...props} />
|
|
),
|
|
},
|
|
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.transition as any;
|
|
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.transition as any;
|
|
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.transition as any;
|
|
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(<InkReveal>Test Content</InkReveal>);
|
|
expect(screen.getByText('Test Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { InkReveal } = await import('./animations');
|
|
render(<InkReveal className="custom-class">Test</InkReveal>);
|
|
const element = screen.getByTestId('motion-div');
|
|
expect(element).toHaveClass('custom-class');
|
|
});
|
|
|
|
it('should use inkVariants', async () => {
|
|
const { InkReveal, inkVariants } = await import('./animations');
|
|
render(<InkReveal>Test</InkReveal>);
|
|
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(<SealStamp>Seal Content</SealStamp>);
|
|
expect(screen.getByText('Seal Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { SealStamp } = await import('./animations');
|
|
render(<SealStamp className="seal-class">Test</SealStamp>);
|
|
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(<FadeUp>Fade Content</FadeUp>);
|
|
expect(screen.getByText('Fade Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom duration', async () => {
|
|
const { FadeUp } = await import('./animations');
|
|
render(<FadeUp duration={1.2}>Test</FadeUp>);
|
|
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(<FadeUp delay={0.3}>Test</FadeUp>);
|
|
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(
|
|
<StaggerContainer>
|
|
<div>Item 1</div>
|
|
<div>Item 2</div>
|
|
</StaggerContainer>
|
|
);
|
|
expect(screen.getByText('Item 1')).toBeInTheDocument();
|
|
expect(screen.getByText('Item 2')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom staggerDelay', async () => {
|
|
const { StaggerContainer } = await import('./animations');
|
|
render(<StaggerContainer staggerDelay={0.2}>Test</StaggerContainer>);
|
|
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(<StaggerItem>Item Content</StaggerItem>);
|
|
expect(screen.getByText('Item Content')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('RippleButton', () => {
|
|
it('should render children correctly', async () => {
|
|
const { RippleButton } = await import('./animations');
|
|
render(<RippleButton>Click Me</RippleButton>);
|
|
expect(screen.getByText('Click Me')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle click events', async () => {
|
|
const { RippleButton } = await import('./animations');
|
|
const handleClick = jest.fn();
|
|
render(<RippleButton onClick={handleClick}>Click Me</RippleButton>);
|
|
|
|
const button = screen.getByTestId('motion-button');
|
|
fireEvent.click(button);
|
|
|
|
expect(handleClick).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { RippleButton } = await import('./animations');
|
|
render(<RippleButton className="custom-button">Test</RippleButton>);
|
|
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(<InkCard>Card Content</InkCard>);
|
|
expect(screen.getByText('Card Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom hoverScale', async () => {
|
|
const { InkCard } = await import('./animations');
|
|
render(<InkCard hoverScale={1.1}>Test</InkCard>);
|
|
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(<CountUp end={100} prefix="$" suffix="%" />);
|
|
expect(screen.getByText(/\$/)).toBeInTheDocument();
|
|
expect(screen.getByText(/%/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { CountUp } = await import('./animations');
|
|
render(<CountUp end={100} className="counter-class" />);
|
|
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(<Typewriter text="Hello" />);
|
|
const cursor = screen.getByText('|');
|
|
expect(cursor).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { Typewriter } = await import('./animations');
|
|
render(<Typewriter text="Test" className="typewriter-class" />);
|
|
const container = screen.getByText('|').closest('.typewriter-class');
|
|
expect(container).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('FloatingElement', () => {
|
|
it('should render children correctly', async () => {
|
|
const { FloatingElement } = await import('./animations');
|
|
render(<FloatingElement>Floating Content</FloatingElement>);
|
|
expect(screen.getByText('Floating Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom amplitude', async () => {
|
|
const { FloatingElement } = await import('./animations');
|
|
render(<FloatingElement amplitude={20}>Test</FloatingElement>);
|
|
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(<PulseElement>Pulse Content</PulseElement>);
|
|
expect(screen.getByText('Pulse Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom scale', async () => {
|
|
const { PulseElement } = await import('./animations');
|
|
render(<PulseElement scale={1.1}>Test</PulseElement>);
|
|
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(<GradientText>Gradient Text</GradientText>);
|
|
expect(screen.getByText('Gradient Text')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom colors', async () => {
|
|
const { GradientText } = await import('./animations');
|
|
render(<GradientText colors={['#ff0000', '#00ff00', '#0000ff']}>Test</GradientText>);
|
|
const element = screen.getByTestId('motion-span');
|
|
expect(element).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('SplitText', () => {
|
|
it('should render text correctly', async () => {
|
|
const { SplitText } = await import('./animations');
|
|
render(<SplitText text="Hi" />);
|
|
expect(screen.getByText('H')).toBeInTheDocument();
|
|
expect(screen.getByText('i')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { SplitText } = await import('./animations');
|
|
render(<SplitText text="Test" className="split-class" />);
|
|
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(<GlitchText text="Glitch" />);
|
|
const glitchElements = screen.getAllByText('Glitch');
|
|
expect(glitchElements.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { GlitchText } = await import('./animations');
|
|
render(<GlitchText text="Test" className="glitch-class" />);
|
|
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(<MagneticButton>Magnetic</MagneticButton>);
|
|
expect(screen.getByText('Magnetic')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle click events', async () => {
|
|
const { MagneticButton } = await import('./animations');
|
|
const handleClick = jest.fn();
|
|
render(<MagneticButton onClick={handleClick}>Click</MagneticButton>);
|
|
|
|
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(<BlurReveal>Blur Content</BlurReveal>);
|
|
expect(screen.getByText('Blur Content')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { BlurReveal } = await import('./animations');
|
|
render(<BlurReveal className="blur-class">Test</BlurReveal>);
|
|
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(<WaveText text="Hi" />);
|
|
expect(screen.getByText('H')).toBeInTheDocument();
|
|
expect(screen.getByText('i')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('ShimmerButton', () => {
|
|
it('should render children correctly', async () => {
|
|
const { ShimmerButton } = await import('./animations');
|
|
render(<ShimmerButton>Shimmer</ShimmerButton>);
|
|
expect(screen.getByText('Shimmer')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle click events', async () => {
|
|
const { ShimmerButton } = await import('./animations');
|
|
const handleClick = jest.fn();
|
|
render(<ShimmerButton onClick={handleClick}>Click</ShimmerButton>);
|
|
|
|
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(<InkDropSVG />);
|
|
expect(screen.getByTestId('motion-svg')).toBeInTheDocument();
|
|
expect(screen.getByTestId('motion-circle')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom className', async () => {
|
|
const { InkDropSVG } = await import('./animations');
|
|
render(<InkDropSVG className="ink-drop-class" />);
|
|
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(<InkSplash />);
|
|
expect(screen.getByTestId('motion-svg')).toBeInTheDocument();
|
|
expect(screen.getByTestId('motion-path')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should apply custom color', async () => {
|
|
const { InkSplash } = await import('./animations');
|
|
render(<InkSplash color="#ff0000" />);
|
|
const path = screen.getByTestId('motion-path');
|
|
expect(path).toHaveAttribute('fill', '#ff0000');
|
|
});
|
|
|
|
it('should apply custom size', async () => {
|
|
const { InkSplash } = await import('./animations');
|
|
render(<InkSplash size={200} />);
|
|
const svg = screen.getByTestId('motion-svg');
|
|
expect(svg).toHaveAttribute('width', '200');
|
|
expect(svg).toHaveAttribute('height', '200');
|
|
});
|
|
});
|
|
});
|