Skip to content

Commit 2cc93c9

Browse files
committed
tests.
1 parent a22ceaf commit 2cc93c9

File tree

2 files changed

+136
-80
lines changed

2 files changed

+136
-80
lines changed

src/__tests__/render-hook-sync.test.tsx

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as React from 'react';
33

44
import { deprecated_renderHookSync } from '../pure';
55

6-
test('gives committed result', () => {
6+
test('renders hook and returns committed result', () => {
77
const { result } = deprecated_renderHookSync(() => {
88
const [state, setState] = React.useState(1);
99

@@ -17,7 +17,45 @@ test('gives committed result', () => {
1717
expect(result.current).toEqual([2, expect.any(Function)]);
1818
});
1919

20-
test('allows rerendering', () => {
20+
test('works with wrapper option', () => {
21+
const Context = React.createContext('default');
22+
function Wrapper({ children }: { children: ReactNode }) {
23+
return <Context.Provider value="provided">{children}</Context.Provider>;
24+
}
25+
const { result } = deprecated_renderHookSync(
26+
() => {
27+
return React.useContext(Context);
28+
},
29+
{
30+
wrapper: Wrapper,
31+
},
32+
);
33+
34+
expect(result.current).toEqual('provided');
35+
});
36+
37+
test('works with initialProps option', () => {
38+
const { result, rerender } = deprecated_renderHookSync(
39+
(props: { branch: 'left' | 'right' }) => {
40+
const [left, setLeft] = React.useState('left');
41+
const [right, setRight] = React.useState('right');
42+
43+
switch (props.branch) {
44+
case 'left':
45+
return [left, setLeft];
46+
case 'right':
47+
return [right, setRight];
48+
default:
49+
throw new Error('No Props passed. This is a bug in the implementation');
50+
}
51+
},
52+
{ initialProps: { branch: 'left' } },
53+
);
54+
55+
expect(result.current).toEqual(['left', expect.any(Function)]);
56+
});
57+
58+
test('rerender updates hook with new props', () => {
2159
const { result, rerender } = deprecated_renderHookSync(
2260
(props: { branch: 'left' | 'right' }) => {
2361
const [left, setLeft] = React.useState('left');
@@ -41,21 +79,24 @@ test('allows rerendering', () => {
4179
expect(result.current).toEqual(['right', expect.any(Function)]);
4280
});
4381

44-
test('allows wrapper components', () => {
45-
const Context = React.createContext('default');
46-
function Wrapper({ children }: { children: ReactNode }) {
47-
return <Context.Provider value="provided">{children}</Context.Provider>;
82+
test('unmount triggers cleanup effects', () => {
83+
let cleanupCalled = false;
84+
85+
function useTestHook() {
86+
React.useEffect(() => {
87+
return () => {
88+
cleanupCalled = true;
89+
};
90+
}, []);
91+
92+
return 'test';
4893
}
49-
const { result } = deprecated_renderHookSync(
50-
() => {
51-
return React.useContext(Context);
52-
},
53-
{
54-
wrapper: Wrapper,
55-
},
56-
);
5794

58-
expect(result.current).toEqual('provided');
95+
const { unmount } = deprecated_renderHookSync(useTestHook);
96+
expect(cleanupCalled).toBe(false);
97+
98+
unmount();
99+
expect(cleanupCalled).toBe(true);
59100
});
60101

61102
function useMyHook<T>(param: T) {

src/__tests__/render-hook.test.tsx

Lines changed: 80 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ afterEach(() => {
1313
});
1414

1515
function useSuspendingHook(promise: Promise<string>) {
16-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
17-
// @ts-ignore: React 18 does not have `use` hook
1816
return React.use(promise);
1917
}
2018

21-
test('renderHook renders hook asynchronously', async () => {
19+
test('renders hook and returns committed result', async () => {
2220
const { result } = await renderHook(() => {
2321
const [state, setState] = React.useState(1);
2422

@@ -32,7 +30,39 @@ test('renderHook renders hook asynchronously', async () => {
3230
expect(result.current).toEqual(2);
3331
});
3432

35-
test('renderHook with wrapper option', async () => {
33+
test('handles hook with state updates during effects', async () => {
34+
function useTestHook() {
35+
const [count, setCount] = React.useState(0);
36+
37+
React.useEffect(() => {
38+
setCount((prev) => prev + 1);
39+
}, []);
40+
41+
return count;
42+
}
43+
44+
const { result } = await renderHook(useTestHook);
45+
expect(result.current).toBe(1);
46+
});
47+
48+
test('handles multiple state updates in effects', async () => {
49+
function useTestHook() {
50+
const [first, setFirst] = React.useState(1);
51+
const [second, setSecond] = React.useState(2);
52+
53+
React.useEffect(() => {
54+
setFirst(10);
55+
setSecond(20);
56+
}, []);
57+
58+
return { first, second };
59+
}
60+
61+
const { result } = await renderHook(useTestHook);
62+
expect(result.current).toEqual({ first: 10, second: 20 });
63+
});
64+
65+
test('works with wrapper option', async () => {
3666
const Context = React.createContext('default');
3767

3868
function useTestHook() {
@@ -47,7 +77,24 @@ test('renderHook with wrapper option', async () => {
4777
expect(result.current).toEqual('provided');
4878
});
4979

50-
test('rerender function updates hook asynchronously', async () => {
80+
test('works with initialProps option', async () => {
81+
function useTestHook(props: { value: number }) {
82+
const [state, setState] = React.useState(props.value);
83+
84+
React.useEffect(() => {
85+
setState(props.value * 2);
86+
}, [props.value]);
87+
88+
return state;
89+
}
90+
91+
const { result } = await renderHook(useTestHook, {
92+
initialProps: { value: 5 },
93+
});
94+
expect(result.current).toEqual(10);
95+
});
96+
97+
test('rerender updates hook with new props', async () => {
5198
function useTestHook(props: { value: number }) {
5299
const [state, setState] = React.useState(props.value);
53100

@@ -67,7 +114,7 @@ test('rerender function updates hook asynchronously', async () => {
67114
expect(result.current).toEqual(20);
68115
});
69116

70-
test('unmount function unmounts hook asynchronously', async () => {
117+
test('unmount triggers cleanup effects', async () => {
71118
let cleanupCalled = false;
72119

73120
function useTestHook() {
@@ -87,36 +134,41 @@ test('unmount function unmounts hook asynchronously', async () => {
87134
expect(cleanupCalled).toBe(true);
88135
});
89136

90-
test('handles hook with state updates during effects', async () => {
91-
function useTestHook() {
92-
const [count, setCount] = React.useState(0);
137+
test('handles hook with cleanup and re-initialization', async () => {
138+
let effectCount = 0;
139+
let cleanupCount = 0;
140+
141+
function useTestHook(props: { key: string }) {
142+
const [value, setValue] = React.useState(props.key);
93143

94144
React.useEffect(() => {
95-
setCount((prev) => prev + 1);
96-
}, []);
145+
effectCount++;
146+
setValue(`${props.key}-effect`);
97147

98-
return count;
99-
}
148+
return () => {
149+
cleanupCount++;
150+
};
151+
}, [props.key]);
100152

101-
const { result } = await renderHook(useTestHook);
102-
expect(result.current).toBe(1);
103-
});
153+
return value;
154+
}
104155

105-
test('handles multiple state updates in effects', async () => {
106-
function useTestHook() {
107-
const [first, setFirst] = React.useState(1);
108-
const [second, setSecond] = React.useState(2);
156+
const { result, rerender, unmount } = await renderHook(useTestHook, {
157+
initialProps: { key: 'initial' },
158+
});
109159

110-
React.useEffect(() => {
111-
setFirst(10);
112-
setSecond(20);
113-
}, []);
160+
expect(result.current).toBe('initial-effect');
161+
expect(effectCount).toBe(1);
162+
expect(cleanupCount).toBe(0);
114163

115-
return { first, second };
116-
}
164+
await rerender({ key: 'updated' });
165+
expect(result.current).toBe('updated-effect');
166+
expect(effectCount).toBe(2);
167+
expect(cleanupCount).toBe(1);
117168

118-
const { result } = await renderHook(useTestHook);
119-
expect(result.current).toEqual({ first: 10, second: 20 });
169+
await unmount();
170+
expect(effectCount).toBe(2);
171+
expect(cleanupCount).toBe(2);
120172
});
121173

122174
test('handles hook with suspense', async () => {
@@ -227,40 +279,3 @@ test('handles custom hooks with complex logic', async () => {
227279
});
228280
expect(result.current.count).toBe(4);
229281
});
230-
231-
test('handles hook with cleanup and re-initialization', async () => {
232-
let effectCount = 0;
233-
let cleanupCount = 0;
234-
235-
function useTestHook(props: { key: string }) {
236-
const [value, setValue] = React.useState(props.key);
237-
238-
React.useEffect(() => {
239-
effectCount++;
240-
setValue(`${props.key}-effect`);
241-
242-
return () => {
243-
cleanupCount++;
244-
};
245-
}, [props.key]);
246-
247-
return value;
248-
}
249-
250-
const { result, rerender, unmount } = await renderHook(useTestHook, {
251-
initialProps: { key: 'initial' },
252-
});
253-
254-
expect(result.current).toBe('initial-effect');
255-
expect(effectCount).toBe(1);
256-
expect(cleanupCount).toBe(0);
257-
258-
await rerender({ key: 'updated' });
259-
expect(result.current).toBe('updated-effect');
260-
expect(effectCount).toBe(2);
261-
expect(cleanupCount).toBe(1);
262-
263-
await unmount();
264-
expect(effectCount).toBe(2);
265-
expect(cleanupCount).toBe(2);
266-
});

0 commit comments

Comments
 (0)