Files
portainer/app/react/components/datatables/useTableStateFromUrl.test.ts
T
2026-04-26 16:48:45 +03:00

131 lines
3.8 KiB
TypeScript

import { renderHook, act } from '@testing-library/react-hooks';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { useTableStateFromUrl } from './useTableStateFromUrl';
const mockSetUrlState = vi.fn();
const mockSetStoredPageSize = vi.fn();
let mockUrlParams: Record<string, string | undefined> = {};
let mockStoredPageSize = 10;
vi.mock('@/react/hooks/useParamState', () => ({
useParamsState: (
parseParams: (params: Record<string, string | undefined>) => unknown
) => [parseParams(mockUrlParams), mockSetUrlState] as const,
}));
vi.mock('@/react/hooks/useLocalStorage', () => ({
useLocalStorage: () => [mockStoredPageSize, mockSetStoredPageSize],
}));
describe('useTableStateFromUrl', () => {
beforeEach(() => {
mockUrlParams = {};
mockStoredPageSize = 10;
mockSetUrlState.mockReset();
mockSetStoredPageSize.mockReset();
});
it('returns defaults when URL params are absent', () => {
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
expect(result.current.search).toBe('');
expect(result.current.sortBy).toEqual({ id: 'name', desc: false });
expect(result.current.page).toBe(0);
expect(result.current.pageSize).toBe(10);
});
it('setSearch updates search and resets page to 0', () => {
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
act(() => {
result.current.setSearch('hello');
});
expect(mockSetUrlState).toHaveBeenCalledWith({ search: 'hello', page: 0 });
});
it('setSortBy updates sort and order and resets page to 0', () => {
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
act(() => {
result.current.setSortBy('age', true);
});
expect(mockSetUrlState).toHaveBeenCalledWith({
sort: 'age',
order: 'desc',
page: 0,
});
});
it('setPage updates page only', () => {
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
act(() => {
result.current.setPage(3);
});
expect(mockSetUrlState).toHaveBeenCalledWith({ page: 3 });
});
it('setPageSize updates localStorage and URL pageSize, resets page to 0', () => {
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
act(() => {
result.current.setPageSize(25);
});
expect(mockSetStoredPageSize).toHaveBeenCalledWith(25);
expect(mockSetUrlState).toHaveBeenCalledWith({ pageSize: 25, page: 0 });
});
it('falls back to 0 for invalid page URL param', () => {
mockUrlParams = { page: 'abc' };
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
expect(result.current.page).toBe(0);
});
it('falls back to localStorage pageSize for invalid pageSize URL param', () => {
mockUrlParams = { pageSize: 'abc' };
mockStoredPageSize = 20;
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort: 'name' })
);
expect(result.current.pageSize).toBe(20);
});
it('sanitizes out-of-range URL params to safe defaults', () => {
mockUrlParams = { page: '-3', pageSize: '0', order: 'sideways' };
mockStoredPageSize = 15;
const defaultSort = 'sorting';
const { result } = renderHook(() =>
useTableStateFromUrl({ localStorageKey: 'test', defaultSort })
);
expect(result.current.page).toBe(0);
expect(result.current.pageSize).toBe(15);
expect(result.current.sortBy?.desc).toBe(false);
expect(result.current.search).toBe('');
expect(result.current.sortBy?.id).toBe(defaultSort);
});
});