reactjs - Testa anpassad hook med SetTimeout och useEffect med Jest
Jag försöker testa en relativt enkel egen hook som använder useEffect och setTimeout. Men mitt test misslyckas, och jag kan inte lista ut vad som är fel.
Här är själva hooken (useTokenExpirationCheck.ts)
import { useEffect } from 'react';
import { logout } from '../features/profile/profileSlice';
import { useAppDispatch } from '../store/hooks';
export default function useTokenExpirationCheck(exp: number): void {
const dispatch = useAppDispatch();
useEffect(() => {
if (exp) {
const timeToLogout = exp * 1000 - Date.now();
setTimeout(() => {
dispatch(logout());
}, timeToLogout);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [exp]);
}
och min testfil:
import { act, renderHook } from '@testing-library/react-hooks';
import useTokenExpirationCheck from './useTokenExpirationCheck';
jest.mock('../features/profile/profileSlice');
const logout = jest.fn();
const exp = Date.now() + 6000;
describe('Expiration token', () => {
test('should logout user', async () => {
jest.useFakeTimers();
act(() => {
renderHook(() => {
useTokenExpirationCheck(exp);
});
});
expect(logout).toHaveBeenCalledTimes(0);
jest.advanceTimersByTime(60000);
expect(logout).toHaveBeenCalledTimes(1);
});
});
Det jag vet är att exp-variabeln på något sätt inte skickas till useTokenExpirationCheck-funktionen (console.log visade mig 0 inuti funktionen när den kördes). Så i princip kommer jag inte ens till useEffect själv... några idéer om vad som kan gå fel?
Svar #1
Här är min teststrategi:
- Jag kommer att använda redux-mock-store för att skapa en mock-store
Den simulerade butiken kommer att skapa en lista över skickade åtgärder som fungerar som en åtgärdslogg för tester.
Så att jag kan hämta och bekräfta de skickade åtgärderna med store.getActions()-metoden.
Jag kommer att mocka
Date.now()-metoden med ett mockat returvärde så att testerna inte längre beror på systemdatum. Systemdatum kan vara olika för olika tidszoner och olika CI/CD-servrar.Använd Props för att uppdatera indata (beroenden för
useEffect) och återrendera hooken så att vi kan testa fallet: Omexpändras.
useTokenExpirationCheck.ts:
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
const logout = () => ({ type: 'LOGOUT' });
export default function useTokenExpirationCheck(exp: number): void {
const dispatch = useDispatch();
useEffect(() => {
if (exp) {
console.log('exp: ', exp);
const timeToLogout = exp * 1000 - Date.now();
setTimeout(() => {
dispatch(logout());
}, timeToLogout);
}
}, [exp]);
}
useTokenExpirationCheck.test.tsx:
import { renderHook } from '@testing-library/react-hooks';
import React from 'react';
import { Provider } from 'react-redux';
import createMockStore from 'redux-mock-store';
import useTokenExpirationCheck from './useTokenExpirationCheck';
describe('useTokenExpirationCheck', () => {
test('should dispatch logout action after delay', async () => {
let exp = 6000;
jest.spyOn(Date, 'now').mockReturnValue(5900 * 1000);
const mockStore = createMockStore([]);
const store = mockStore({});
jest.useFakeTimers();
const { rerender } = renderHook(() => useTokenExpirationCheck(exp), {
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});
jest.advanceTimersByTime(100 * 1000);
expect(store.getActions()).toEqual([{ type: 'LOGOUT' }]);
exp = 6100;
rerender();
jest.advanceTimersByTime(200 * 1000);
expect(store.getActions()).toEqual([{ type: 'LOGOUT' }, { type: 'LOGOUT' }]);
});
});
testresultat:
PASS examples/69967414/useTokenExpirationCheck.test.tsx (8.329 s)
useTokenExpirationCheck
✓ should pass (39 ms)
console.log
exp: 6000
at examples/69967414/useTokenExpirationCheck.ts:10:15
console.log
exp: 6100
at examples/69967414/useTokenExpirationCheck.ts:10:15
------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------------|---------|----------|---------|---------|-------------------
All files | 100 | 50 | 100 | 100 |
...nExpirationCheck.ts | 100 | 50 | 100 | 100 | 9
------------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.885 s, estimated 10 s
Ran all test suites related to changed files.
