You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
9.5 KiB
291 lines
9.5 KiB
import {act, renderHook} from '@testing-library/react';
|
|
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
import {useResponsiveChartSize} from '@src/hooks/useResponsiveChartSize';
|
|
|
|
describe('useResponsiveChartSize', () => {
|
|
let mockInnerWidth: number;
|
|
|
|
beforeEach(() => {
|
|
mockInnerWidth = 1200;
|
|
|
|
// Mock window.innerWidth
|
|
Object.defineProperty(window, 'innerWidth', {
|
|
writable: true,
|
|
configurable: true,
|
|
value: mockInnerWidth
|
|
});
|
|
|
|
// Mock addEventListener and removeEventListener
|
|
window.addEventListener = vi.fn();
|
|
window.removeEventListener = vi.fn();
|
|
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterEach(function () {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('initializes with medium size by default', () => {
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
expect(result.current.isSmall).toBe(false);
|
|
expect(result.current.isMedium).toBe(true);
|
|
expect(result.current.isLarge).toBe(false);
|
|
});
|
|
|
|
it('returns small size for widths below sm breakpoint', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 800});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('sm');
|
|
expect(result.current.isSmall).toBe(true);
|
|
expect(result.current.isMedium).toBe(false);
|
|
expect(result.current.isLarge).toBe(false);
|
|
});
|
|
|
|
it('returns medium size for widths between sm and md breakpoints', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1150});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
expect(result.current.isSmall).toBe(false);
|
|
expect(result.current.isMedium).toBe(true);
|
|
expect(result.current.isLarge).toBe(false);
|
|
});
|
|
|
|
it('returns large size for widths above md breakpoint', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1400});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('lg');
|
|
expect(result.current.isSmall).toBe(false);
|
|
expect(result.current.isMedium).toBe(false);
|
|
expect(result.current.isLarge).toBe(true);
|
|
});
|
|
|
|
it('uses custom breakpoints when provided', () => {
|
|
const customBreakpoints = {
|
|
sm: 500,
|
|
md: 800,
|
|
lg: 1000
|
|
};
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 600});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize({breakpoints: customBreakpoints})
|
|
);
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
});
|
|
|
|
it('handles edge cases at exact breakpoint values', () => {
|
|
// Test at exact sm breakpoint (should be md)
|
|
Object.defineProperty(window, 'innerWidth', {value: 1080});
|
|
|
|
const {result: result1} = renderHook(() => useResponsiveChartSize());
|
|
expect(result1.current.chartSize).toBe('md');
|
|
|
|
// Test at exact md breakpoint (should be lg)
|
|
Object.defineProperty(window, 'innerWidth', {value: 1280});
|
|
|
|
const {result: result2} = renderHook(() => useResponsiveChartSize());
|
|
expect(result2.current.chartSize).toBe('lg');
|
|
});
|
|
|
|
it('responds to window resize events', () => {
|
|
let resizeHandler: () => void;
|
|
|
|
// Capture the resize handler to test behavior
|
|
window.addEventListener = vi.fn((event, handler) => {
|
|
if (event === 'resize') {
|
|
resizeHandler = handler as () => void;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 1200});
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
|
|
// Test that the hook actually responds to resize events
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 800});
|
|
resizeHandler();
|
|
});
|
|
|
|
expect(result.current.chartSize).toBe('sm');
|
|
});
|
|
|
|
it('cleans up properly when unmounted', () => {
|
|
let resizeHandler: () => void;
|
|
|
|
window.addEventListener = vi.fn((event, handler) => {
|
|
if (event === 'resize') {
|
|
resizeHandler = handler as () => void;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 1200});
|
|
const {result, unmount} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
const originalSize = result.current.chartSize;
|
|
|
|
// Unmount the hook
|
|
unmount();
|
|
|
|
// Behavior test: hook should stop responding to resize events after unmount
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 800});
|
|
// If cleanup worked, calling the old handler shouldn't cause issues
|
|
expect(() => resizeHandler()).not.toThrow();
|
|
});
|
|
|
|
// The hook result should remain unchanged after unmount (no longer reactive)
|
|
expect(result.current.chartSize).toBe(originalSize);
|
|
});
|
|
|
|
it('updates boolean flags correctly when size changes', () => {
|
|
let resizeHandler: () => void;
|
|
|
|
window.addEventListener = vi.fn((event, handler) => {
|
|
if (event === 'resize') {
|
|
resizeHandler = handler as () => void;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 1200});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
// Initial state - medium
|
|
expect(result.current.isSmall).toBe(false);
|
|
expect(result.current.isMedium).toBe(true);
|
|
expect(result.current.isLarge).toBe(false);
|
|
|
|
// Resize to large
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1400});
|
|
resizeHandler();
|
|
});
|
|
|
|
expect(result.current.isSmall).toBe(false);
|
|
expect(result.current.isMedium).toBe(false);
|
|
expect(result.current.isLarge).toBe(true);
|
|
|
|
// Resize to small
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 800});
|
|
resizeHandler();
|
|
});
|
|
|
|
expect(result.current.isSmall).toBe(true);
|
|
expect(result.current.isMedium).toBe(false);
|
|
expect(result.current.isLarge).toBe(false);
|
|
});
|
|
|
|
it('handles multiple resize events correctly', () => {
|
|
let resizeHandler: () => void;
|
|
|
|
window.addEventListener = vi.fn((event, handler) => {
|
|
if (event === 'resize') {
|
|
resizeHandler = handler as () => void;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 1200});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
|
|
// Multiple rapid resizes
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 800});
|
|
resizeHandler();
|
|
});
|
|
expect(result.current.chartSize).toBe('sm');
|
|
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1400});
|
|
resizeHandler();
|
|
});
|
|
expect(result.current.chartSize).toBe('lg');
|
|
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1100});
|
|
resizeHandler();
|
|
});
|
|
expect(result.current.chartSize).toBe('md');
|
|
});
|
|
|
|
it('works with custom breakpoints and resize events', () => {
|
|
let resizeHandler: () => void;
|
|
|
|
window.addEventListener = vi.fn((event, handler) => {
|
|
if (event === 'resize') {
|
|
resizeHandler = handler as () => void;
|
|
}
|
|
});
|
|
|
|
const customBreakpoints = {
|
|
sm: 600,
|
|
md: 900,
|
|
lg: 1200
|
|
};
|
|
|
|
Object.defineProperty(window, 'innerWidth', {value: 700});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize({breakpoints: customBreakpoints})
|
|
);
|
|
|
|
expect(result.current.chartSize).toBe('md');
|
|
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 500});
|
|
resizeHandler();
|
|
});
|
|
|
|
expect(result.current.chartSize).toBe('sm');
|
|
|
|
act(() => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1300});
|
|
resizeHandler();
|
|
});
|
|
|
|
expect(result.current.chartSize).toBe('lg');
|
|
});
|
|
|
|
it('uses default breakpoints when no custom breakpoints provided', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 1000});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize({}));
|
|
|
|
// Should use default breakpoints: sm: 1080, md: 1280, lg: 1360
|
|
// 1000 < 1080, so should be 'sm'
|
|
expect(result.current.chartSize).toBe('sm');
|
|
});
|
|
|
|
it('handles very small screen sizes', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 320});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('sm');
|
|
expect(result.current.isSmall).toBe(true);
|
|
});
|
|
|
|
it('handles very large screen sizes', () => {
|
|
Object.defineProperty(window, 'innerWidth', {value: 2000});
|
|
|
|
const {result} = renderHook(() => useResponsiveChartSize());
|
|
|
|
expect(result.current.chartSize).toBe('lg');
|
|
expect(result.current.isLarge).toBe(true);
|
|
});
|
|
}); |