Mi anzuelo es;
function useInterval() { const ref: MutableRefObject<NodeJS.Timer | null > = useRef(null); function set(callback: () => void, delay: number) { ref.current = setInterval(callback, delay) } function clear() { if (ref.current) { clearInterval(ref.current) ref.current = null } } return { set, clear } }Mi prueba es;
it("set: This should be called 10 times", () => { var callback = jest.fn(); jest.useFakeTimers() const { result } = renderHook(() => hooks.useInterval()) act(() => { result.current.set(() => { callback }, 100) jest.advanceTimersByTime(1000); }) expect(callback).toHaveBeenCalledTimes(10); jest.useRealTimers() }) renderHook() y act() provienen de "@testing-library/react-hooks": "^7.0.2"
El resultado que sigo obteniendo es 0 de mi llamada expect() . Parece que no puedo entender por qué.
Si solo uso setInterval() expect() obtiene el valor correcto
it("setInterval", () => { var callback = jest.fn(); jest.useFakeTimers() setInterval(callback, 100) jest.advanceTimersByTime(1000); expect(callback).toHaveBeenCalledTimes(10); jest.useRealTimers() })He intentado reordenar las líneas de todas las formas lógicas posibles que se me ocurren.
He notado que obtengo el mismo resultado con o sin act() , extrañamente.
Agregar timers: "fake" o cualquiera de sus variaciones (moderno/heredado) a jest.config.ts no parece tener ningún efecto.
Obviamente, testing-library/react-hooks alguna manera enmascara setInterval() de jest.useFakeTimers() de alguna manera, pero no entiendo cómo y, por lo tanto, no puedo lograr el resultado que estoy buscando.
Una parte de mí piensa que mi gancho no está siendo golpeado por jest.useFakeTimers() porque los temporizadores falsos no se reemplazan globalmente, pero no sé cómo hacerlo.
Además, estoy usando Typescript. No es que crea que eso hace la diferencia.
Pasó una función anónima al método set en lugar de la callback de llamada simulada. Entonces, la macrotarea puesta en cola por setInterval llamará a la función anónima. Es por eso que la afirmación falla. Nada a Jest Config, TypeScript.
p.ej
useInterval.ts :
import { MutableRefObject, useRef } from 'react'; export function useInterval() { const ref: MutableRefObject<ReturnType<typeof setInterval> | null> = useRef(null); function set(callback: () => void, delay: number) { ref.current = setInterval(callback, delay); } function clear() { if (ref.current) { clearInterval(ref.current); ref.current = null; } } return { set, clear }; } useInterval.test.ts :
import { renderHook } from '@testing-library/react-hooks'; import { useInterval } from './useInterval'; describe('70276930', () => { beforeAll(() => { jest.useFakeTimers(); }); afterAll(() => { jest.useRealTimers(); }); test('should call callback interval', () => { const callback = jest.fn(); const { result } = renderHook(useInterval); result.current.set(callback, 100); jest.advanceTimersByTime(1000); expect(callback).toBeCalledTimes(10); }); test('should clear interval', () => { const callback = jest.fn(); const { result } = renderHook(useInterval); result.current.set(callback, 100); jest.advanceTimersByTime(100); expect(callback).toBeCalledTimes(1); result.current.clear(); jest.advanceTimersByTime(100); expect(callback).toBeCalledTimes(1); }); });resultado de la prueba:
PASS examples/70276930/useInterval.test.ts (7.541 s) 70276930 ✓ should call callback interval (16 ms) ✓ should clear interval (1 ms) ----------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------------|---------|----------|---------|---------|------------------- All files | 100 | 50 | 100 | 100 | useInterval.ts | 100 | 50 | 100 | 100 | 9 ----------------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 8.294 s, estimated 9 sversiones del paquete:
"react": "^16.14.0", "@testing-library/react": "^11.2.2", "jest": "^26.6.3",