Skip to content

Commit be7cfaf

Browse files
committed
Remove the @testing-library/react-hooks dev dependency.
1 parent 0dfcac9 commit be7cfaf

18 files changed

Lines changed: 2432 additions & 2197 deletions

Provider.test.mjs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,20 @@ export default (tests) => {
8282
strictEqual(results[0].cacheContextValue, cache);
8383
assertInstanceOf(results[0].loadingContextValue, Loading);
8484

85-
testRenderer.update(
86-
React.createElement(
87-
Provider,
88-
{
89-
// @ts-ignore Force the component to re-render by setting a new
90-
// arbitrary prop.
91-
a: true,
92-
cache,
93-
},
94-
React.createElement(TestComponent)
95-
)
96-
);
85+
ReactTestRenderer.act(() => {
86+
testRenderer.update(
87+
React.createElement(
88+
Provider,
89+
{
90+
// @ts-ignore Force the component to re-render by setting a new
91+
// arbitrary prop.
92+
a: true,
93+
cache,
94+
},
95+
React.createElement(TestComponent)
96+
)
97+
);
98+
});
9799

98100
strictEqual(results.length, 2);
99101
strictEqual(

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Patch
1010

1111
- Updated dev dependencies.
12+
- Removed the [`@testing-library/react-hooks`](https://npm.im/@testing-library/react-hooks) dev dependency and rewrote React hook tests using [`react-test-renderer`](https://npm.im/react-test-renderer), a new test utility function `createReactTestRenderer`, and a custom React component `ReactHookTest`.
1213
- Removed the [`fetch-blob`](https://npm.im/fetch-blob) and [`formdata-node`](https://npm.im/formdata-node) dev dependencies. Instead, `File` and `FormData` are imported from [`node-fetch`](https://npm.im/node-fetch).
1314
- Updated `jsconfig.json` `compilerOptions.module` to `nodenext`.
1415
- Updated GitHub Actions CI config:

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
"react-waterfall-render": "^4.0.0"
107107
},
108108
"devDependencies": {
109-
"@testing-library/react-hooks": "^7.0.2",
110109
"@types/node": "^17.0.45",
111110
"@types/react": "^17.0.47",
112111
"@types/react-dom": "^17.0.17",

test/ReactHookTest.mjs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// @ts-check
2+
3+
import useForceUpdate from "../useForceUpdate.mjs";
4+
5+
/**
6+
* React component for testing a React hook.
7+
* @template {() => HookReturnType} Hook React hook type.
8+
* @template HookReturnType React hook return type.
9+
* @param {object} props Props.
10+
* @param {Hook} props.useHook React hook.
11+
* @param {Array<ReactHookResult<HookReturnType>>} props.results React hook
12+
* render results.
13+
*/
14+
export default function ReactHookTest({ useHook, results }) {
15+
const rerender = useForceUpdate();
16+
17+
/** @type {ReactHookResult<HookReturnType>} */
18+
let result;
19+
20+
try {
21+
const returned = useHook();
22+
23+
result = { rerender, returned };
24+
} catch (threw) {
25+
result = { rerender, threw };
26+
}
27+
28+
results.push(result);
29+
30+
return null;
31+
}
32+
33+
/**
34+
* React hook render result.
35+
* @template [HookReturnType=unknown]
36+
* @typedef {Readonly<
37+
* ReactHookResultReturned<HookReturnType>
38+
* > | Readonly<
39+
* ReactHookResultThrew
40+
* >} ReactHookResult
41+
*/
42+
43+
/**
44+
* Result if the React hook returned.
45+
* @template [HookReturnType=unknown]
46+
* @typedef {object} ReactHookResultReturned
47+
* @prop {() => void} rerender Forces the component to re-render.
48+
* @prop {HookReturnType} returned What the hook returned.
49+
*/
50+
51+
/**
52+
* Result if the React hook threw.
53+
* @typedef {object} ReactHookResultThrew
54+
* @prop {() => void} rerender Forces the component to re-render.
55+
* @prop {unknown} threw What the hook threw.
56+
*/

test/createReactTestRenderer.mjs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @ts-check
2+
3+
import ReactTestRenderer from "react-test-renderer";
4+
5+
/**
6+
* Creates a React test renderer.
7+
* @param {import("react").ReactNode} reactRoot Root React node to render.
8+
*/
9+
export default function createReactTestRenderer(reactRoot) {
10+
/** @type {import("react-test-renderer").ReactTestRenderer | undefined} */
11+
let testRenderer;
12+
13+
ReactTestRenderer.act(() => {
14+
testRenderer = ReactTestRenderer.create(
15+
// @ts-ignore The React types are incorrect.
16+
reactRoot
17+
);
18+
});
19+
20+
return /** @type {import("react-test-renderer").ReactTestRenderer} */ (
21+
testRenderer
22+
);
23+
}

useAutoAbortLoad.test.mjs

Lines changed: 90 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
// @ts-check
22

3-
import { cleanup, renderHook } from "@testing-library/react-hooks/lib/pure.js";
4-
import { notStrictEqual, strictEqual, throws } from "assert";
3+
import { notStrictEqual, ok, strictEqual, throws } from "assert";
54
import React from "react";
5+
import ReactTestRenderer from "react-test-renderer";
66

77
import Cache from "./Cache.mjs";
88
import CacheContext from "./CacheContext.mjs";
99
import Loading from "./Loading.mjs";
1010
import LoadingCacheValue from "./LoadingCacheValue.mjs";
1111
import assertBundleSize from "./test/assertBundleSize.mjs";
1212
import assertTypeOf from "./test/assertTypeOf.mjs";
13+
import createReactTestRenderer from "./test/createReactTestRenderer.mjs";
14+
import ReactHookTest from "./test/ReactHookTest.mjs";
1315
import useAutoAbortLoad from "./useAutoAbortLoad.mjs";
1416

1517
/**
@@ -84,95 +86,104 @@ export default (tests) => {
8486
return loadingCacheValue;
8587
}
8688

87-
/** @param {{ children?: React.ReactNode }} props Props. */
88-
const wrapper = ({ children }) =>
89-
React.createElement(CacheContext.Provider, { value: cache }, children);
90-
91-
try {
92-
const { result, rerender, unmount } = renderHook(
93-
({ load }) => useAutoAbortLoad(load),
94-
{
95-
wrapper,
96-
initialProps: {
97-
load: loadA,
98-
},
99-
}
100-
);
89+
/** @type {Array<import("./test/ReactHookTest.mjs").ReactHookResult>} */
90+
const results = [];
91+
92+
const testRenderer = createReactTestRenderer(
93+
React.createElement(
94+
CacheContext.Provider,
95+
{ value: cache },
96+
React.createElement(ReactHookTest, {
97+
useHook: () => useAutoAbortLoad(loadA),
98+
results,
99+
})
100+
)
101+
);
101102

102-
strictEqual(result.all.length, 1);
103-
assertTypeOf(result.current, "function");
104-
strictEqual(result.error, undefined);
105-
strictEqual(loadCalls.length, 0);
103+
strictEqual(results.length, 1);
104+
ok("returned" in results[0]);
105+
assertTypeOf(results[0].returned, "function");
106+
strictEqual(loadCalls.length, 0);
106107

107-
// Test that the returned auto abort load function is memoized.
108-
rerender();
108+
// Test that the returned auto abort load function is memoized.
109+
ReactTestRenderer.act(() => {
110+
results[0].rerender();
111+
});
109112

110-
strictEqual(result.all.length, 2);
111-
strictEqual(result.current, result.all[0]);
112-
strictEqual(result.error, undefined);
113-
strictEqual(loadCalls.length, 0);
113+
strictEqual(results.length, 2);
114+
strictEqual(loadCalls.length, 0);
114115

115-
// Start the first loading.
116-
result.current();
116+
// Start the first loading.
117+
results[0].returned();
117118

118-
strictEqual(loadCalls.length, 1);
119-
strictEqual(loadCalls[0].loader, loadA);
120-
strictEqual(loadCalls[0].hadArgs, false);
121-
strictEqual(
122-
loadCalls[0].loadingCacheValue.abortController.signal.aborted,
123-
false
124-
);
119+
strictEqual(loadCalls.length, 1);
120+
strictEqual(loadCalls[0].loader, loadA);
121+
strictEqual(loadCalls[0].hadArgs, false);
122+
strictEqual(
123+
loadCalls[0].loadingCacheValue.abortController.signal.aborted,
124+
false
125+
);
125126

126-
// Start the second loading, before the first ends. This should abort the
127-
// first.
128-
result.current();
127+
// Start the second loading, before the first ends. This should abort the
128+
// first.
129+
results[0].returned();
129130

130-
strictEqual(loadCalls.length, 2);
131-
strictEqual(
132-
loadCalls[0].loadingCacheValue.abortController.signal.aborted,
133-
true
134-
);
135-
strictEqual(loadCalls[1].hadArgs, false);
136-
strictEqual(loadCalls[1].loader, loadA);
137-
strictEqual(
138-
loadCalls[1].loadingCacheValue.abortController.signal.aborted,
139-
false
140-
);
131+
strictEqual(loadCalls.length, 2);
132+
strictEqual(
133+
loadCalls[0].loadingCacheValue.abortController.signal.aborted,
134+
true
135+
);
136+
strictEqual(loadCalls[1].hadArgs, false);
137+
strictEqual(loadCalls[1].loader, loadA);
138+
strictEqual(
139+
loadCalls[1].loadingCacheValue.abortController.signal.aborted,
140+
false
141+
);
141142

142-
// Test that changing the loader causes the returned memoized auto abort
143-
// load function to change, and the last loading to abort.
144-
rerender({ load: loadB });
145-
146-
strictEqual(result.all.length, 3);
147-
assertTypeOf(result.current, "function");
148-
notStrictEqual(result.current, result.all[1]);
149-
strictEqual(result.error, undefined);
150-
strictEqual(loadCalls.length, 2);
151-
strictEqual(
152-
loadCalls[1].loadingCacheValue.abortController.signal.aborted,
153-
true
143+
// Test that changing the loader causes the returned memoized auto abort
144+
// load function to change, and the last loading to abort.
145+
ReactTestRenderer.act(() => {
146+
testRenderer.update(
147+
React.createElement(
148+
CacheContext.Provider,
149+
{ value: cache },
150+
React.createElement(ReactHookTest, {
151+
useHook: () => useAutoAbortLoad(loadB),
152+
results,
153+
})
154+
)
154155
);
156+
});
157+
158+
strictEqual(results.length, 3);
159+
ok("returned" in results[2]);
160+
assertTypeOf(results[2].returned, "function");
161+
notStrictEqual(results[2].returned, results[1]);
162+
strictEqual(loadCalls.length, 2);
163+
strictEqual(
164+
loadCalls[1].loadingCacheValue.abortController.signal.aborted,
165+
true
166+
);
155167

156-
// Test that the returned newly memoized abort load function works.
157-
result.current();
168+
// Test that the returned newly memoized abort load function works.
169+
results[2].returned();
158170

159-
strictEqual(loadCalls.length, 3);
160-
strictEqual(loadCalls[2].loader, loadB);
161-
strictEqual(loadCalls[2].hadArgs, false);
162-
strictEqual(
163-
loadCalls[2].loadingCacheValue.abortController.signal.aborted,
164-
false
165-
);
171+
strictEqual(loadCalls.length, 3);
172+
strictEqual(loadCalls[2].loader, loadB);
173+
strictEqual(loadCalls[2].hadArgs, false);
174+
strictEqual(
175+
loadCalls[2].loadingCacheValue.abortController.signal.aborted,
176+
false
177+
);
166178

167-
// Test that the last loading is aborted on unmount.
168-
unmount();
179+
// Test that the last loading is aborted on unmount.
180+
ReactTestRenderer.act(() => {
181+
testRenderer.unmount();
182+
});
169183

170-
strictEqual(
171-
loadCalls[2].loadingCacheValue.abortController.signal.aborted,
172-
true
173-
);
174-
} finally {
175-
cleanup();
176-
}
184+
strictEqual(
185+
loadCalls[2].loadingCacheValue.abortController.signal.aborted,
186+
true
187+
);
177188
});
178189
};

0 commit comments

Comments
 (0)