Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useCachedState unit tests #5320

Draft
wants to merge 9 commits into
base: production
Choose a base branch
from
126 changes: 126 additions & 0 deletions specifyweb/frontend/js_src/lib/hooks/__tests__/useCachedState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { act, renderHook } from '@testing-library/react';

import { cacheEvents, getCache, setCache } from '../../utils/cache';
import { useCachedState } from '../useCachedState';

let eventHandler: (payload: { category: string; key: string }) => void;

// Mock cache utility functions
jest.mock('../../utils/cache', () => ({
getCache: jest.fn(),
setCache: jest.fn(),
cacheEvents: {
on: jest.fn((eventName: string, handler: (payload: any) => void) => {
if (eventName === 'change') {
eventHandler = handler;
}
return jest.fn();
}),
trigger: jest.fn(),
},
}));

test('Initialize state from cache', () => {
(getCache as jest.Mock).mockReturnValue(true);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(true);
expect(getCache).toHaveBeenCalledWith('header', 'isCollapsed');
});

test('Update state and cache when setCachedState is called', () => {
(getCache as jest.Mock).mockReturnValue(true); // Returns true
(setCache as jest.Mock).mockReturnValue(false); // Cache should get updated to false
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(true);

// Update the state using the second value from result (setCachedState)
act(() => {
result.current[1](false);
});

expect(result.current[0]).toBe(false);
expect(setCache).toHaveBeenCalledWith('header', 'isCollapsed', false, true);
});

test('Do not update state if cache value is the same', () => {
(getCache as jest.Mock).mockReturnValueOnce(true);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(true);

(getCache as jest.Mock).mockReturnValueOnce(true);

act(() => {
(cacheEvents.on as jest.Mock).mock.calls[0][1]({
category: 'header',
key: 'isCollapsed',
});
});

expect(result.current[0]).toBe(true);
expect(setCache).not.toHaveBeenCalled();
});

test('Do not update state if setCachedState is called with undefined', () => {
(getCache as jest.Mock).mockReturnValue(true);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(true);

act(() => {
result.current[1](undefined); // Call with undefined
});

expect(result.current[0]).toBe(true);
expect(setCache).not.toHaveBeenCalled();
});

test('Update cache when setCachedState is called after cacheEvents change', () => {
(getCache as jest.Mock).mockReturnValueOnce(true);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(true);

(getCache as jest.Mock).mockReturnValueOnce(false);

act(() => {
eventHandler({ category: 'header', key: 'isCollapsed' });
});

expect(setCache).toHaveBeenCalledWith('header', 'isCollapsed', false, false);
});

//fails
test('should update state correctly', async () => {
(getCache as jest.Mock).mockReturnValueOnce(false);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));
await act(async () => {
console.log('calling setCachedState with true', result.current[0]);
await result.current[1](true);
console.log('calling setCachedState with true', result.current[0]);
});
});



//fails
// wip: checked that state does indeed update to true, but the test is not reflecting that? returning undefined. maybe bc async state updates
test('Collapsing the header updates both the state and cache', () => {
(getCache as jest.Mock).mockReturnValue(false);
const { result } = renderHook(() => useCachedState('header', 'isCollapsed'));

expect(result.current[0]).toBe(false);

act(() => {
console.log('before setter: ', result.current[0]); // Returns false
result.current[1](() => true);
console.log('after setter: ', result.current[0]); // Returns false; may be running default getcache?
});

console.log('after act: ', result.current); // Returns undefined
expect(result.current[0]).toBe(true);

// expect(setCache).toHaveBeenCalledWith('header', 'isCollapsed', true, true);
});
Loading