Add comprehensive unit tests for homepage components and utilities
- Introduced unit tests for homepage components: `QuickStartCode`, `Header`, `DemoCredentialsModal`, `AnimatedTerminal`, `CTASection`, and `StatsSection`. - Added utility tests for `chart-colors` including opacity, palettes, and gradient validation. - Mocked dependencies (`framer-motion`, `react-syntax-highlighter`, `DemoCredentialsModal`) for isolated testing. - Verified accessibility features, animations, and interactive behaviors across components.
This commit is contained in:
178
frontend/tests/hooks/usePrefersReducedMotion.test.ts
Normal file
178
frontend/tests/hooks/usePrefersReducedMotion.test.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Tests for usePrefersReducedMotion hook
|
||||
* Tests media query detection for accessibility preferences
|
||||
*/
|
||||
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { usePrefersReducedMotion } from '@/hooks/usePrefersReducedMotion';
|
||||
|
||||
describe('usePrefersReducedMotion', () => {
|
||||
let mockMatchMedia: jest.Mock;
|
||||
let mockListeners: ((event: MediaQueryListEvent) => void)[];
|
||||
|
||||
beforeEach(() => {
|
||||
mockListeners = [];
|
||||
|
||||
mockMatchMedia = jest.fn().mockImplementation((query: string) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addEventListener: jest.fn((event: string, listener: (event: MediaQueryListEvent) => void) => {
|
||||
if (event === 'change') {
|
||||
mockListeners.push(listener);
|
||||
}
|
||||
}),
|
||||
removeEventListener: jest.fn((event: string, listener: (event: MediaQueryListEvent) => void) => {
|
||||
if (event === 'change') {
|
||||
const index = mockListeners.indexOf(listener);
|
||||
if (index > -1) {
|
||||
mockListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}),
|
||||
dispatchEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: mockMatchMedia,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns false when user does not prefer reduced motion', () => {
|
||||
mockMatchMedia.mockImplementation((query: string) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
expect(mockMatchMedia).toHaveBeenCalledWith('(prefers-reduced-motion: reduce)');
|
||||
});
|
||||
|
||||
it('returns true when user prefers reduced motion', () => {
|
||||
mockMatchMedia.mockImplementation((query: string) => ({
|
||||
matches: true,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
const { result } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('updates when media query preference changes to true', () => {
|
||||
const mockMediaQuery = {
|
||||
matches: false,
|
||||
media: '(prefers-reduced-motion: reduce)',
|
||||
onchange: null,
|
||||
addEventListener: jest.fn((event: string, listener: (event: MediaQueryListEvent) => void) => {
|
||||
if (event === 'change') {
|
||||
mockListeners.push(listener);
|
||||
}
|
||||
}),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
};
|
||||
|
||||
mockMatchMedia.mockReturnValue(mockMediaQuery);
|
||||
|
||||
const { result } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
// Simulate media query change
|
||||
act(() => {
|
||||
mockListeners.forEach(listener => {
|
||||
listener({ matches: true } as MediaQueryListEvent);
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('updates when media query preference changes to false', () => {
|
||||
const mockMediaQuery = {
|
||||
matches: true,
|
||||
media: '(prefers-reduced-motion: reduce)',
|
||||
onchange: null,
|
||||
addEventListener: jest.fn((event: string, listener: (event: MediaQueryListEvent) => void) => {
|
||||
if (event === 'change') {
|
||||
mockListeners.push(listener);
|
||||
}
|
||||
}),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
};
|
||||
|
||||
mockMatchMedia.mockReturnValue(mockMediaQuery);
|
||||
|
||||
const { result } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
|
||||
// Simulate media query change
|
||||
act(() => {
|
||||
mockListeners.forEach(listener => {
|
||||
listener({ matches: false } as MediaQueryListEvent);
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('cleans up event listener on unmount', () => {
|
||||
const removeEventListenerSpy = jest.fn();
|
||||
|
||||
const mockMediaQuery = {
|
||||
matches: false,
|
||||
media: '(prefers-reduced-motion: reduce)',
|
||||
onchange: null,
|
||||
addEventListener: jest.fn((event: string, listener: (event: MediaQueryListEvent) => void) => {
|
||||
if (event === 'change') {
|
||||
mockListeners.push(listener);
|
||||
}
|
||||
}),
|
||||
removeEventListener: removeEventListenerSpy,
|
||||
dispatchEvent: jest.fn(),
|
||||
};
|
||||
|
||||
mockMatchMedia.mockReturnValue(mockMediaQuery);
|
||||
|
||||
const { unmount } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
expect(mockMediaQuery.addEventListener).toHaveBeenCalledWith('change', expect.any(Function));
|
||||
|
||||
unmount();
|
||||
|
||||
expect(removeEventListenerSpy).toHaveBeenCalledWith('change', expect.any(Function));
|
||||
});
|
||||
|
||||
it('handles SSR environment safely', () => {
|
||||
const originalWindow = global.window;
|
||||
|
||||
// @ts-ignore - Simulating SSR
|
||||
delete global.window;
|
||||
|
||||
const { result } = renderHook(() => usePrefersReducedMotion());
|
||||
|
||||
// Should return false in SSR environment
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
// Restore window
|
||||
global.window = originalWindow;
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user