Skip to content

Add useCachedState unit tests #5320

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

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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