preact-hooks-testing-library
preact-hooks-testing-library copied to clipboard
waitForNextUpdate times out with async function
import React from "preact/compat";
import { act, renderHook } from "@testing-library/preact-hooks";
// works:
// import React from "react";
// import { act, renderHook } from "@testing-library/react-hooks";
function useTest() {
let [state, setState] = React.useState(1);
return {
value: state,
async increment() {
await new Promise((res) => setTimeout(res, 100));
setState((i) => i + 1);
},
};
}
test("test", async () => {
let { result, waitForNextUpdate } = renderHook(() => useTest());
expect(result.current.value).toBe(1);
await act(async () => {
result.current.increment();
await waitForNextUpdate();
});
expect(result.current.value).toBe(2);
});
Without await waitForNextUpdate()
, the second assertion fails.
With that call, Jest times out (this works as expected when using React).
Same problem here, but with events:
import { useEffect, useState } from 'preact/hooks';
const useWindowFocus = () => {
const [visible, setVisible] = useState('visible');
useEffect(() => {
const handleVisibilityChange = () => {
setVisible(() => {
console.log('CALLED');
return document.visibilityState;
});
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, []);
return visible === 'visible';
};
export { useWindowFocus };
import { renderHook, act } from '@testing-library/preact-hooks';
import { useWindowFocus } from '../use-window-focus';
Object.defineProperty(document, 'visibilityState', { value: 'visible', configurable: true, writable: true });
describe('useWindowFocus', () => {
test('given that the visibilitychange event was triggered: should change its value accordingly', async () => {
const { result, waitForNextUpdate } = renderHook(() => useWindowFocus());
expect(result.current.isFocused).toBe(true);
document.visibilityState = 'hidden';
act(() => { document.dispatchEvent(new Event('visibilitychange')) });
await waitForNextUpdate();
expect(result.current.isFocused).toBe(false);
// document.visibilityState = 'visible';
// act(() => { document.dispatchEvent(new Event('visibilitychange')) });
// expect(result.current).toBe(true);
});
});
EDIT: If the hook returns an object instead of a value it works. Here's the new code:
import { useEffect, useState } from 'preact/hooks';
const useWindowFocus = () => {
const [visible, setVisible] = useState('visible');
useEffect(() => {
const handleVisibilityChange = () => setVisible(document.visibilityState);
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, []);
return { isFocused: visible === 'visible' };
};
describe('useWindowFocus', () => {
test('given that the visibilitychange event was triggered: should change its value accordingly', async () => {
const { result } = renderHook(() => useWindowFocus());
expect(result.current.isFocused).toBe(true);
document.visibilityState = 'hidden';
act(() => { document.dispatchEvent(new Event('visibilitychange')) });
expect(result.current.isFocused).toBe(false);
document.visibilityState = 'visible';
act(() => { document.dispatchEvent(new Event('visibilitychange')) });
expect(result.current.isFocused).toBe(true);
});
});