test(unit): expand unit tests and fix stress test robustness
- Add comprehensive useFocusTrap tests (edge cases, disabled elements, empty containers) - Add useSwipeGesture tests (haptic feedback, touch events, disabled state, effect deps) - Enhance animations.test.tsx with Framer Motion mock and component tests - Fix stress-test.js body.length undefined error when requests fail - Fix home-content-v14.tsx for consistency - Clean up generated performance test summary files
This commit is contained in:
+237
-5
@@ -4,7 +4,7 @@ import '@testing-library/jest-dom';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, initial, animate, variants, className, whileHover, whileTap, ...props }: any) => (
|
||||
div: ({ children, initial, animate, variants, className, whileHover, whileTap, transition, ...props }: any) => (
|
||||
<div
|
||||
data-testid="motion-div"
|
||||
data-initial={JSON.stringify(initial)}
|
||||
@@ -12,6 +12,7 @@ jest.mock('framer-motion', () => ({
|
||||
data-variants={JSON.stringify(variants)}
|
||||
data-while-hover={JSON.stringify(whileHover)}
|
||||
data-while-tap={JSON.stringify(whileTap)}
|
||||
data-transition={JSON.stringify(transition)}
|
||||
className={className}
|
||||
{...props}
|
||||
>
|
||||
@@ -30,11 +31,13 @@ jest.mock('framer-motion', () => ({
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
span: ({ children, className, animate, ...props }: any) => (
|
||||
span: ({ children, className, animate, initial, transition, ...props }: any) => (
|
||||
<span
|
||||
data-testid="motion-span"
|
||||
className={className}
|
||||
data-animate={JSON.stringify(animate)}
|
||||
data-initial={JSON.stringify(initial)}
|
||||
data-transition={JSON.stringify(transition)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -51,10 +54,36 @@ jest.mock('framer-motion', () => ({
|
||||
path: ({ variants, ...props }: any) => (
|
||||
<path data-testid="motion-path" data-variants={JSON.stringify(variants)} {...props} />
|
||||
),
|
||||
a: ({ children, className, ...props }: any) => (
|
||||
<a data-testid="motion-a" className={className} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
h1: ({ children, className, ...props }: any) => (
|
||||
<h1 data-testid="motion-h1" className={className} {...props}>
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ children, className, ...props }: any) => (
|
||||
<h2 data-testid="motion-h2" className={className} {...props}>
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
p: ({ children, className, ...props }: any) => (
|
||||
<p data-testid="motion-p" className={className} {...props}>
|
||||
{children}
|
||||
</p>
|
||||
),
|
||||
},
|
||||
AnimatePresence: ({ children }: any) => <>{children}</>,
|
||||
useInView: jest.fn(() => true),
|
||||
useSpring: jest.fn((value) => value),
|
||||
useTransform: jest.fn((value) => value),
|
||||
useMotionValue: jest.fn((initial) => ({
|
||||
get: () => initial,
|
||||
set: jest.fn(),
|
||||
onChange: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('Animation Variants', () => {
|
||||
@@ -533,19 +562,222 @@ describe('Animation Components', () => {
|
||||
it('should accept bounce effect', async () => {
|
||||
const { CounterWithEffect } = await import('./animations');
|
||||
render(<CounterWithEffect end={100} effect="bounce" />);
|
||||
expect(screen.getByTestId('motion-span')).toBeInTheDocument();
|
||||
const element = screen.getByTestId('motion-span');
|
||||
expect(element).toBeInTheDocument();
|
||||
const animate = JSON.parse(element.getAttribute('data-animate') || '{}');
|
||||
expect(animate).toEqual({ y: [0, -10, 0] });
|
||||
});
|
||||
|
||||
it('should accept slide effect', async () => {
|
||||
const { CounterWithEffect } = await import('./animations');
|
||||
render(<CounterWithEffect end={100} effect="slide" />);
|
||||
expect(screen.getByTestId('motion-span')).toBeInTheDocument();
|
||||
const element = screen.getByTestId('motion-span');
|
||||
expect(element).toBeInTheDocument();
|
||||
const animate = JSON.parse(element.getAttribute('data-animate') || '{}');
|
||||
expect(animate).toEqual({ y: 0, opacity: 1 });
|
||||
});
|
||||
|
||||
it('should accept flip effect', async () => {
|
||||
const { CounterWithEffect } = await import('./animations');
|
||||
render(<CounterWithEffect end={100} effect="flip" />);
|
||||
expect(screen.getByTestId('motion-span')).toBeInTheDocument();
|
||||
const element = screen.getByTestId('motion-span');
|
||||
expect(element).toBeInTheDocument();
|
||||
const animate = JSON.parse(element.getAttribute('data-animate') || '{}');
|
||||
expect(animate).toEqual({ rotateX: 0 });
|
||||
});
|
||||
|
||||
it('should render initial count value', async () => {
|
||||
const { CounterWithEffect } = await import('./animations');
|
||||
render(<CounterWithEffect end={42} />);
|
||||
// Component renders with end value, then useEffect resets to 0
|
||||
// due to useInView mock returning true
|
||||
const element = screen.getByTestId('motion-span');
|
||||
expect(element).toBeInTheDocument();
|
||||
expect(element.textContent).toBe('0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Enhanced Component Tests', () => {
|
||||
describe('CountUp', () => {
|
||||
it('should render with custom duration', async () => {
|
||||
const { CountUp } = await import('./animations');
|
||||
render(<CountUp end={1000} duration={3000} />);
|
||||
const element = screen.getByTestId('motion-span');
|
||||
expect(element).toBeInTheDocument();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
describe('RippleButton', () => {
|
||||
it('should create ripple on click', async () => {
|
||||
const { RippleButton } = await import('./animations');
|
||||
render(<RippleButton>Click Me</RippleButton>);
|
||||
|
||||
const button = screen.getByTestId('motion-button');
|
||||
fireEvent.click(button);
|
||||
|
||||
// Ripple creates a motion.span
|
||||
expect(screen.getByTestId('motion-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle multiple clicks', 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);
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(handleClick).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should apply custom rippleColor', async () => {
|
||||
const { RippleButton } = await import('./animations');
|
||||
render(<RippleButton rippleColor="rgba(0, 0, 255, 0.5)">Click</RippleButton>);
|
||||
|
||||
const button = screen.getByTestId('motion-button');
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(screen.getByText('Click')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('RotatingBorder', () => {
|
||||
it('should render with custom borderWidth', async () => {
|
||||
const { RotatingBorder } = await import('./animations');
|
||||
render(<RotatingBorder borderWidth={4}>Test</RotatingBorder>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with custom duration', async () => {
|
||||
const { RotatingBorder } = await import('./animations');
|
||||
render(<RotatingBorder duration={8}>Test</RotatingBorder>);
|
||||
const motionDiv = screen.getAllByTestId('motion-div')[0]!;
|
||||
const animate = JSON.parse(motionDiv.getAttribute('data-animate') || '{}');
|
||||
expect(animate).toEqual({ rotate: 360 });
|
||||
});
|
||||
|
||||
it('should have infinite repeat transition', async () => {
|
||||
const { RotatingBorder } = await import('./animations');
|
||||
render(<RotatingBorder duration={4}>Test</RotatingBorder>);
|
||||
const motionDiv = screen.getAllByTestId('motion-div')[0]!;
|
||||
const transitionAttr = motionDiv.getAttribute('data-transition') || '';
|
||||
// JSON.stringify(Infinity) returns null, so check string representation
|
||||
expect(transitionAttr).toContain('"repeat"');
|
||||
expect(transitionAttr).toContain('"duration"');
|
||||
expect(transitionAttr).toContain('4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('SplitText', () => {
|
||||
it('should render with custom delay', async () => {
|
||||
const { SplitText } = await import('./animations');
|
||||
render(<SplitText text="ABC" delay={0.5} />);
|
||||
expect(screen.getByText('A')).toBeInTheDocument();
|
||||
expect(screen.getByText('B')).toBeInTheDocument();
|
||||
expect(screen.getByText('C')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('WaveText', () => {
|
||||
it('should render with custom delay', async () => {
|
||||
const { WaveText } = await import('./animations');
|
||||
render(<WaveText text="ABC" delay={0.5} />);
|
||||
const spans = screen.getAllByTestId('motion-span');
|
||||
expect(spans.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Typewriter', () => {
|
||||
it('should render with custom speed', async () => {
|
||||
const { Typewriter } = await import('./animations');
|
||||
render(<Typewriter text="Hello" speed={100} />);
|
||||
const cursor = screen.getByText('|');
|
||||
expect(cursor).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GradientText', () => {
|
||||
it('should render with custom colors', async () => {
|
||||
const { GradientText } = await import('./animations');
|
||||
render(<GradientText colors={['#ff0000', '#00ff00', '#0000ff']}>Test</GradientText>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with animation duration', async () => {
|
||||
const { GradientText } = await import('./animations');
|
||||
render(<GradientText duration={5}>Test</GradientText>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ShimmerButton', () => {
|
||||
it('should render with animation', async () => {
|
||||
const { ShimmerButton } = await import('./animations');
|
||||
render(<ShimmerButton>Shimmer</ShimmerButton>);
|
||||
const motionDiv = screen.getAllByTestId('motion-div')[0]!;
|
||||
const animate = JSON.parse(motionDiv.getAttribute('data-animate') || '{}');
|
||||
expect(animate).toHaveProperty('backgroundPosition');
|
||||
});
|
||||
});
|
||||
|
||||
describe('MagneticButton', () => {
|
||||
it('should render with custom strength', async () => {
|
||||
const { MagneticButton } = await import('./animations');
|
||||
render(<MagneticButton strength={0.5}>Test</MagneticButton>);
|
||||
expect(screen.getByText('Test')).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 with custom delay', async () => {
|
||||
const { BlurReveal } = await import('./animations');
|
||||
render(<BlurReveal delay={0.5}>Test</BlurReveal>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GlitchText', () => {
|
||||
it('should render text correctly', async () => {
|
||||
const { GlitchText } = await import('./animations');
|
||||
render(<GlitchText text="Test" />);
|
||||
const elements = screen.getAllByText('Test');
|
||||
expect(elements.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('FloatingElement', () => {
|
||||
it('should render with custom duration', async () => {
|
||||
const { FloatingElement } = await import('./animations');
|
||||
render(<FloatingElement duration={5}>Test</FloatingElement>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('PulseElement', () => {
|
||||
it('should render with custom duration', async () => {
|
||||
const { PulseElement } = await import('./animations');
|
||||
render(<PulseElement duration={3}>Test</PulseElement>);
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user