Skip to content

Commit 251ea70

Browse files
juhanakristiannobraynermerodirotigerabrodiJacobMGEvans
authoredDec 15, 2020
feat: Convert to TypeScript (#520)
* Added tsconfig.json. Modified eslint config * Convert src/cleanup.js to TypeScript * Change src/cleanup.ts to use inline types * revert eslintrc * disable eslint for cleanup import this can be reverted when `pure.js` is converted to typescript * convert index to typescript just a rename 😅 * BREAKING CHANGE: Worked on typing asyncUtils. Removed deprecated wait. Disabled import/no-unresolved for now * Fix incorrect cleanup callback type * asyncUtils has been updated. Two lines are disabled for eslint. * remove unnecessary eslint disable * Prettier was stripping try catch types - see: https://prettier.io/blog/2020/08/24/2.1.0.html\#type-annotations-on-catch-clauses-8805httpsgithubcomprettierprettierpull8805-by-fiskerhttpsgithubcomfisker - Updated prettier in local devDeps to resolve directly to newest supported version * Type for callback handle generic input & undefined handled by nullish operator TS expecting explicit return of undefined from arrow function with type Expected to return a value at the end of arrow function.eslintconsistent-return resolved by passing return in catch with undefined, same behavior more explicit * comments for review * VoidFunction in place for void until decided behavior for waitFor() * Utilizing OR operator with generic Types allows for desired behavior and previous tests pass * mistakenly left out linter ignores in last commit * Minimum types started for Pure file - File needs better, improved typing and Refactoring for Linter Disables to be removed IF POSSIBLE * removed comments -- answered in PR - Types and OR check should handle expected behavior * Generic HTML types for initialProps * Generic HTML types for initialProps * Generic type for callback and initialProps * Generics added and CB toplevel same generic pattern added * force rebuild with unbound method eslint ignore * parser issue -- attempt to fix by removing specific TS eslint rule * Newer versions of ESLint might resolve the parser issue * Added configs to get started on test conversion * Generic type for resultContainer this should allow typescript to infer the type of result.current further improvments needed to add type guards * convert tests that require no changes renamed tests that didn't require code changes to the tests * add types to cleanup test * Test TS Overhaul - Amr, Tiger and myself worked on these commits - Other Raid members in chat assisted - All tests are strongly typed with minimal types to allow for working and made sure tests types were easily usable with types in Pure and Utils file, allow for good UX & DX * Amr updated types useEffect * Jens suggestion for more generic number key type * Remove wait reference from docs * Add nobrayner to contributors * Add JacobMGEvans to contributors * Update src/pure.tsx * Add tigerabrodi to contributors * Add Amr, Juhana, and Jens to contributors * update suspenseHook, cache type and the type of the error in catch. * cleanup.ts, update the way addCleanup adds another callback to cleanupCallbacks. * Made generics more descriptive, made TestHook generic * Remove some eslint disables that didn't do anything * Remove DefinitelyTyped reference in CONTRIBUTING.md * chore: disable declaration for tests * Removes createTimeoutError. Adds constructor to TimeoutError. Adds typeing to waitForValueToChange options * Remove conditional in TestHook for hookProps * Replace old types defs with referenced types in dependencies * Remove destructuring of `testRenderer` * Disabled floating promise lint rule globally * Refactor TestHook catch to not disable lint rules * Disabled eslint error for while(true) * Cleaned up some line warnings from tests * Added "typecheck" kcd-script to improve "validate" script * Clean up ThrowError type in errorHook tests * Replace VoidFunction with () => void * Replace CallableFunction with a more explicit function type Co-authored-by: Braydon Hall <[email protected]> Co-authored-by: Amr Gad <[email protected]> Co-authored-by: tigerabrodi <[email protected]> Co-authored-by: Jacob Evans <[email protected]> Co-authored-by: Jacob M-G Evans <[email protected]> Co-authored-by: marcosvega91 <[email protected]> Co-authored-by: Michael Peyper <[email protected]>
1 parent c53b56b commit 251ea70

30 files changed

+373
-383
lines changed
 

‎.all-contributorsrc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,64 @@
212212
"contributions": [
213213
"code"
214214
]
215+
},
216+
{
217+
"login": "nobrayner",
218+
"name": "Braydon Hall",
219+
"avatar_url": "https://avatars2.githubusercontent.com/u/40751395?v=4",
220+
"profile": "https://github.com/nobrayner",
221+
"contributions": [
222+
"code"
223+
]
224+
},
225+
{
226+
"login": "JacobMGEvans",
227+
"name": "Jacob M-G Evans",
228+
"avatar_url": "https://avatars1.githubusercontent.com/u/27247160?v=4",
229+
"profile": "https://dev.to/jacobmgevans",
230+
"contributions": [
231+
"code",
232+
"test"
233+
]
234+
},
235+
{
236+
"login": "tigerabrodi",
237+
"name": "Tiger Abrodi",
238+
"avatar_url": "https://avatars1.githubusercontent.com/u/49603590?v=4",
239+
"profile": "https://tigerabrodi.dev/",
240+
"contributions": [
241+
"code",
242+
"test"
243+
]
244+
},
245+
{
246+
"login": "merodiro",
247+
"name": "Amr A.Mohammed",
248+
"avatar_url": "https://avatars1.githubusercontent.com/u/17033502?v=4",
249+
"profile": "https://github.com/merodiro",
250+
"contributions": [
251+
"code",
252+
"test"
253+
]
254+
},
255+
{
256+
"login": "juhanakristian",
257+
"name": "Juhana Jauhiainen",
258+
"avatar_url": "https://avatars1.githubusercontent.com/u/544386?v=4",
259+
"profile": "https://github.com/juhanakristian",
260+
"contributions": [
261+
"code"
262+
]
263+
},
264+
{
265+
"login": "jensmeindertsma",
266+
"name": "Jens Meindertsma",
267+
"avatar_url": "https://avatars3.githubusercontent.com/u/64677517?v=4",
268+
"profile": "https://github.com/jensmeindertsma",
269+
"contributions": [
270+
"code",
271+
"test"
272+
]
215273
}
216274
],
217275
"commitConvention": "none"

‎.eslintrc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
{
2-
"extends": "./node_modules/kcd-scripts/eslint.js",
2+
"extends": ["./node_modules/kcd-scripts/eslint.js"],
33
"rules": {
44
"max-lines-per-function": "off",
55
"no-constant-condition": "off",
66
"no-await-in-loop": "off",
7+
"no-console": "off",
8+
"import/no-unresolved": "off",
79
"react-hooks/rules-of-hooks": "off",
8-
"no-console": "off"
10+
"@typescript-eslint/no-floating-promises": "off",
11+
"@typescript-eslint/no-unnecessary-condition": "off"
12+
},
13+
"parserOptions": {
14+
"project": ["./tsconfig.json", "./test/tsconfig.json"]
915
}
1016
}

‎CONTRIBUTING.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ select the added contribution type.
2727
Please make sure to run the tests before you commit your changes. You can do so by running
2828
`npm test`.
2929

30-
### Update Typings
31-
32-
The TypeScript type definitions can be found in the
33-
[DefinitelyTyped repo](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/testing-library__react-hooks).
34-
3530
## Help needed
3631

3732
Please check out the

‎README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,14 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
192192
<td align="center"><a href="https://github.com/joshuaellis"><img src="https://avatars0.githubusercontent.com/u/37798644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Josh</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=joshuaellis" title="Documentation">📖</a></td>
193193
<td align="center"><a href="https://github.com/Goldziher"><img src="https://avatars1.githubusercontent.com/u/30733348?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Na'aman Hirschfeld</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=Goldziher" title="Code">💻</a></td>
194194
</tr>
195+
<tr>
196+
<td align="center"><a href="https://github.com/nobrayner"><img src="https://avatars2.githubusercontent.com/u/40751395?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Braydon Hall</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=nobrayner" title="Code">💻</a></td>
197+
<td align="center"><a href="https://dev.to/jacobmgevans"><img src="https://avatars1.githubusercontent.com/u/27247160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob M-G Evans</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Tests">⚠️</a></td>
198+
<td align="center"><a href="https://tigerabrodi.dev/"><img src="https://avatars1.githubusercontent.com/u/49603590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tiger Abrodi</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Tests">⚠️</a></td>
199+
<td align="center"><a href="https://github.com/merodiro"><img src="https://avatars1.githubusercontent.com/u/17033502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amr A.Mohammed</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=merodiro" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=merodiro" title="Tests">⚠️</a></td>
200+
<td align="center"><a href="https://github.com/juhanakristian"><img src="https://avatars1.githubusercontent.com/u/544386?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juhana Jauhiainen</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=juhanakristian" title="Code">💻</a></td>
201+
<td align="center"><a href="https://github.com/jensmeindertsma"><img src="https://avatars3.githubusercontent.com/u/64677517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jens Meindertsma</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=jensmeindertsma" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=jensmeindertsma" title="Tests">⚠️</a></td>
202+
</tr>
195203
</table>
196204

197205
<!-- markdownlint-restore -->

‎docs/api-reference.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -259,28 +259,3 @@ The maximum amount of time in milliseconds (ms) to wait. By default, no timeout
259259
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
260260
If this option is set to `false`, any errors that occur while waiting cause the promise to be
261261
rejected. By default, errors are not suppressed for this utility.
262-
263-
### `wait`
264-
265-
_(DEPRECATED, use [`waitFor`](/reference/api#waitfor) instead)_
266-
267-
```js
268-
function wait(callback: function(): boolean|void, options?: {
269-
timeout?: number,
270-
suppressErrors?: boolean
271-
}): Promise<void>
272-
```
273-
274-
Returns a `Promise` that resolves if the provided callback executes without exception and returns a
275-
truthy or `undefined` value. It is safe to use the [`result` of `renderHook`](/reference/api#result)
276-
in the callback to perform assertion or to test values.
277-
278-
#### `timeout`
279-
280-
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
281-
282-
#### `suppressErrors`
283-
284-
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
285-
If this option is set to `false`, any errors that occur while waiting cause the promise to be
286-
rejected. By default, errors are suppressed for this utility.

‎jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
// eslint-disable-next-line
12
const { jest: jestConfig } = require('kcd-scripts/config')
23

34
module.exports = Object.assign(jestConfig, {
45
roots: ['<rootDir>/src', '<rootDir>/test'],
5-
testMatch: ['<rootDir>/test/*.js']
6+
testMatch: ['<rootDir>/test/*.(ts|tsx|js)']
67
})

‎package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "0.0.0-semantically-released",
44
"description": "Simple and complete React hooks testing utilities that encourage good testing practices.",
55
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
67
"keywords": [
78
"testing",
89
"react",
@@ -27,29 +28,34 @@
2728
"validate": "kcd-scripts validate",
2829
"prepare": "npm run build",
2930
"build": "kcd-scripts build --out-dir lib",
31+
"test": "kcd-scripts test",
32+
"typecheck": "kcd-scripts typecheck",
3033
"lint": "kcd-scripts lint",
3134
"format": "kcd-scripts format",
3235
"coverage": "codecov",
33-
"test": "kcd-scripts test",
3436
"docs:dev": "docz dev",
3537
"docs:build": "docz build",
3638
"contributors:add": "all-contributors add"
3739
},
3840
"dependencies": {
3941
"@babel/runtime": "^7.12.5",
40-
"@types/testing-library__react-hooks": "^3.4.0"
42+
"@types/react": ">=16.9.0",
43+
"@types/react-test-renderer": ">=16.9.0"
4144
},
4245
"devDependencies": {
46+
"@typescript-eslint/eslint-plugin": "^4.9.1",
47+
"@typescript-eslint/parser": "^4.9.1",
4348
"all-contributors-cli": "6.19.0",
4449
"codecov": "3.8.1",
4550
"docz": "2.3.1",
4651
"docz-theme-default": "1.2.0",
4752
"docz-utils": "2.3.0",
53+
"eslint": "7.15.0",
4854
"kcd-scripts": "7.5.2",
55+
"prettier": "^2.2.1",
4956
"react": "17.0.1",
5057
"react-test-renderer": "17.0.1",
51-
"typescript": "4.1.2",
52-
"eslint": "7.15.0"
58+
"typescript": "4.1.2"
5359
},
5460
"peerDependencies": {
5561
"react": ">=16.9.0",

‎src/asyncUtils.js

Lines changed: 0 additions & 123 deletions
This file was deleted.

‎src/asyncUtils.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { act } from 'react-test-renderer'
2+
3+
export interface WaitOptions {
4+
interval?: number
5+
timeout?: number
6+
suppressErrors?: boolean
7+
}
8+
9+
class TimeoutError extends Error {
10+
constructor(utilName: string, { timeout }: Pick<WaitOptions, 'timeout'>) {
11+
super(`Timed out in ${utilName} after ${timeout as number}ms.`)
12+
}
13+
}
14+
15+
function resolveAfter(ms: number) {
16+
return new Promise((resolve) => {
17+
setTimeout(resolve, ms)
18+
})
19+
}
20+
21+
function asyncUtils(addResolver: (callback: () => void) => void) {
22+
let nextUpdatePromise: Promise<void> | null = null
23+
24+
const waitForNextUpdate = async (options: Pick<WaitOptions, 'timeout'> = {}) => {
25+
if (!nextUpdatePromise) {
26+
nextUpdatePromise = new Promise((resolve, reject) => {
27+
let timeoutId: ReturnType<typeof setTimeout>
28+
if (options.timeout && options.timeout > 0) {
29+
timeoutId = setTimeout(
30+
() => reject(new TimeoutError('waitForNextUpdate', options)),
31+
options.timeout
32+
)
33+
}
34+
addResolver(() => {
35+
clearTimeout(timeoutId)
36+
nextUpdatePromise = null
37+
resolve()
38+
})
39+
})
40+
await act(() => nextUpdatePromise as Promise<void>)
41+
}
42+
await nextUpdatePromise
43+
}
44+
45+
const waitFor = async <T>(
46+
callback: () => T | Promise<T>,
47+
{ interval, timeout, suppressErrors = true }: WaitOptions = {}
48+
) => {
49+
const checkResult = () => {
50+
try {
51+
const callbackResult = callback()
52+
return callbackResult || callbackResult === undefined
53+
} catch (error: unknown) {
54+
if (!suppressErrors) {
55+
throw error as Error
56+
}
57+
return undefined
58+
}
59+
}
60+
61+
const waitForResult = async () => {
62+
const initialTimeout = timeout
63+
while (true) {
64+
const startTime = Date.now()
65+
try {
66+
const nextCheck = interval
67+
? Promise.race([waitForNextUpdate({ timeout }), resolveAfter(interval)])
68+
: waitForNextUpdate({ timeout })
69+
70+
await nextCheck
71+
72+
if (checkResult()) {
73+
return
74+
}
75+
} catch (error: unknown) {
76+
if (error instanceof TimeoutError) {
77+
throw new TimeoutError('waitFor', { timeout: initialTimeout })
78+
}
79+
throw error as Error
80+
}
81+
if (timeout) timeout -= Date.now() - startTime
82+
}
83+
}
84+
85+
if (!checkResult()) {
86+
await waitForResult()
87+
}
88+
}
89+
90+
const waitForValueToChange = async (selector: () => unknown, options: WaitOptions = {}) => {
91+
const initialValue = selector()
92+
try {
93+
await waitFor(() => selector() !== initialValue, {
94+
suppressErrors: false,
95+
...options
96+
})
97+
} catch (error: unknown) {
98+
if (error instanceof TimeoutError) {
99+
throw new TimeoutError('waitForValueToChange', options)
100+
}
101+
throw error as Error
102+
}
103+
}
104+
105+
return {
106+
waitFor,
107+
waitForNextUpdate,
108+
waitForValueToChange
109+
}
110+
}
111+
112+
export default asyncUtils

‎src/cleanup.js renamed to ‎src/cleanup.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
let cleanupCallbacks = []
1+
let cleanupCallbacks: (() => Promise<void> | void)[] = []
22

33
async function cleanup() {
44
for (const callback of cleanupCallbacks) {
@@ -7,12 +7,12 @@ async function cleanup() {
77
cleanupCallbacks = []
88
}
99

10-
function addCleanup(callback) {
11-
cleanupCallbacks.unshift(callback)
10+
function addCleanup(callback: () => Promise<void> | void) {
11+
cleanupCallbacks = [callback, ...cleanupCallbacks]
1212
return () => removeCleanup(callback)
1313
}
1414

15-
function removeCleanup(callback) {
15+
function removeCleanup(callback: () => Promise<void> | void) {
1616
cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
1717
}
1818

File renamed without changes.

‎src/pure.js

Lines changed: 0 additions & 105 deletions
This file was deleted.

‎src/pure.tsx

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import React, { ReactElement, ReactNode, Suspense } from 'react'
2+
import { act, create, ReactTestRenderer } from 'react-test-renderer'
3+
import asyncUtils from './asyncUtils'
4+
import { cleanup, addCleanup, removeCleanup } from './cleanup'
5+
6+
function isPromise<T>(value: unknown): boolean {
7+
return typeof (value as PromiseLike<T>).then === 'function'
8+
}
9+
10+
type TestHookProps<TProps, TResult> = {
11+
callback: (props: TProps) => TResult
12+
hookProps: TProps | undefined
13+
onError: (error: Error) => void
14+
children: (value: TResult) => void
15+
}
16+
17+
function TestHook<TProps, TResult>({
18+
callback,
19+
hookProps,
20+
onError,
21+
children
22+
}: TestHookProps<TProps, TResult>) {
23+
try {
24+
// coerce undefined into TProps, so it maintains the previous behaviour
25+
children(callback(hookProps as TProps))
26+
} catch (err: unknown) {
27+
if (isPromise(err)) {
28+
throw err
29+
} else {
30+
onError(err as Error)
31+
}
32+
}
33+
return null
34+
}
35+
36+
function Fallback() {
37+
return null
38+
}
39+
40+
function resultContainer<TValue>() {
41+
const results: Array<{ value?: TValue; error?: Error }> = []
42+
const resolvers: Array<() => void> = []
43+
44+
const result = {
45+
get all() {
46+
return results.map(({ value, error }) => error ?? value)
47+
},
48+
get current() {
49+
const { value, error } = results[results.length - 1]
50+
if (error) {
51+
throw error
52+
}
53+
return value as TValue
54+
},
55+
get error() {
56+
const { error } = results[results.length - 1]
57+
return error
58+
}
59+
}
60+
61+
const updateResult = (value?: TValue, error?: Error) => {
62+
results.push({ value, error })
63+
resolvers.splice(0, resolvers.length).forEach((resolve) => resolve())
64+
}
65+
66+
return {
67+
result,
68+
addResolver: (resolver: () => void) => {
69+
resolvers.push(resolver)
70+
},
71+
setValue: (value: TValue) => updateResult(value),
72+
setError: (error: Error) => updateResult(undefined, error)
73+
}
74+
}
75+
76+
function renderHook<TProps, TResult>(
77+
callback: (props: TProps) => TResult,
78+
{ initialProps, wrapper }: { initialProps?: TProps; wrapper?: React.ComponentType<TProps> } = {}
79+
) {
80+
const { result, setValue, setError, addResolver } = resultContainer<TResult>()
81+
const hookProps = { current: initialProps }
82+
83+
const wrapUiIfNeeded = (innerElement: ReactNode) =>
84+
wrapper ? React.createElement(wrapper, hookProps.current, innerElement) : innerElement
85+
86+
const toRender = () =>
87+
wrapUiIfNeeded(
88+
<Suspense fallback={<Fallback />}>
89+
<TestHook callback={callback} hookProps={hookProps.current} onError={setError}>
90+
{setValue}
91+
</TestHook>
92+
</Suspense>
93+
) as ReactElement
94+
95+
let testRenderer: ReactTestRenderer
96+
act(() => {
97+
testRenderer = create(toRender())
98+
})
99+
100+
function rerenderHook(newProps: typeof initialProps = hookProps.current) {
101+
hookProps.current = newProps
102+
act(() => {
103+
testRenderer.update(toRender())
104+
})
105+
}
106+
107+
function unmountHook() {
108+
act(() => {
109+
removeCleanup(unmountHook)
110+
testRenderer.unmount()
111+
})
112+
}
113+
114+
addCleanup(unmountHook)
115+
116+
return {
117+
result,
118+
rerender: rerenderHook,
119+
unmount: unmountHook,
120+
...asyncUtils(addResolver)
121+
}
122+
}
123+
124+
export { renderHook, cleanup, addCleanup, removeCleanup, act }

‎test/asyncHook.js renamed to ‎test/asyncHook.ts

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect } from 'react'
22
import { renderHook } from '../src'
33

44
describe('async hook tests', () => {
5-
const useSequence = (...values) => {
5+
const useSequence = (...values: string[]) => {
66
const [first, ...otherValues] = values
77
const [value, setValue] = useState(first)
88
const index = useRef(0)
@@ -266,92 +266,4 @@ describe('async hook tests', () => {
266266

267267
expect(result.current).toBe('third')
268268
})
269-
270-
test('should wait for expectation to pass (deprecated)', async () => {
271-
const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
272-
273-
expect(result.current).toBe('first')
274-
275-
let complete = false
276-
await wait(() => {
277-
expect(result.current).toBe('third')
278-
complete = true
279-
})
280-
expect(complete).toBe(true)
281-
})
282-
283-
test('should not hang if expectation is already passing (deprecated)', async () => {
284-
const { result, wait } = renderHook(() => useSequence('first', 'second'))
285-
286-
expect(result.current).toBe('first')
287-
288-
let complete = false
289-
await wait(() => {
290-
expect(result.current).toBe('first')
291-
complete = true
292-
})
293-
expect(complete).toBe(true)
294-
})
295-
296-
test('should reject if callback throws error (deprecated)', async () => {
297-
const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
298-
299-
expect(result.current).toBe('first')
300-
301-
await expect(
302-
wait(
303-
() => {
304-
if (result.current === 'second') {
305-
throw new Error('Something Unexpected')
306-
}
307-
return result.current === 'third'
308-
},
309-
{
310-
suppressErrors: false
311-
}
312-
)
313-
).rejects.toThrow(Error('Something Unexpected'))
314-
})
315-
316-
test('should reject if callback immediately throws error (deprecated)', async () => {
317-
const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
318-
319-
expect(result.current).toBe('first')
320-
321-
await expect(
322-
wait(
323-
() => {
324-
throw new Error('Something Unexpected')
325-
},
326-
{
327-
suppressErrors: false
328-
}
329-
)
330-
).rejects.toThrow(Error('Something Unexpected'))
331-
})
332-
333-
test('should wait for truthy value (deprecated)', async () => {
334-
const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
335-
336-
expect(result.current).toBe('first')
337-
338-
await wait(() => result.current === 'third')
339-
340-
expect(result.current).toBe('third')
341-
})
342-
343-
test('should reject if timeout exceeded when waiting for expectation to pass (deprecated)', async () => {
344-
const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
345-
346-
expect(result.current).toBe('first')
347-
348-
await expect(
349-
wait(
350-
() => {
351-
expect(result.current).toBe('third')
352-
},
353-
{ timeout: 75 }
354-
)
355-
).rejects.toThrow(Error('Timed out in wait after 75ms.'))
356-
})
357269
})

‎test/autoCleanup.disabled.js renamed to ‎test/autoCleanup.disabled.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { useEffect } from 'react'
44
// then we DON'T auto-wire up the afterEach for folks
55
describe('skip auto cleanup (disabled) tests', () => {
66
let cleanupCalled = false
7-
let renderHook
7+
let renderHook: (arg0: () => void) => void
88

99
beforeAll(() => {
1010
process.env.RHTL_SKIP_AUTO_CLEANUP = 'true'
11+
// eslint-disable-next-line
1112
renderHook = require('../src').renderHook
1213
})
1314

‎test/autoCleanup.noAfterEach.js renamed to ‎test/autoCleanup.noAfterEach.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import { useEffect } from 'react'
44
// then we DON'T auto-wire up the afterEach for folks
55
describe('skip auto cleanup (no afterEach) tests', () => {
66
let cleanupCalled = false
7-
let renderHook
7+
let renderHook: (arg0: () => void) => void
88

99
beforeAll(() => {
10+
// @ts-expect-error Turning off AfterEach -- ignore Jest LifeCycle Type
1011
// eslint-disable-next-line no-global-assign
1112
afterEach = false
13+
// eslint-disable-next-line
1214
renderHook = require('../').renderHook
1315
})
1416

File renamed without changes.

‎test/cleanup.js renamed to ‎test/cleanup.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ describe('cleanup tests', () => {
2121
})
2222

2323
test('should cleanup all rendered hooks', async () => {
24-
const cleanupCalled = []
25-
const hookWithCleanup = (id) => {
24+
const cleanupCalled: boolean[] = []
25+
const hookWithCleanup = (id: number) => {
2626
useEffect(() => {
2727
return () => {
2828
cleanupCalled[id] = true
@@ -40,7 +40,7 @@ describe('cleanup tests', () => {
4040
})
4141

4242
test('should call cleanups in reverse order', async () => {
43-
const callSequence = []
43+
const callSequence: string[] = []
4444
addCleanup(() => {
4545
callSequence.push('cleanup')
4646
})
@@ -62,7 +62,7 @@ describe('cleanup tests', () => {
6262
})
6363

6464
test('should wait for async cleanup', async () => {
65-
const callSequence = []
65+
const callSequence: string[] = []
6666
addCleanup(() => {
6767
callSequence.push('cleanup')
6868
})
@@ -85,7 +85,7 @@ describe('cleanup tests', () => {
8585
})
8686

8787
test('should remove cleanup using removeCleanup', async () => {
88-
const callSequence = []
88+
const callSequence: string[] = []
8989
addCleanup(() => {
9090
callSequence.push('cleanup')
9191
})
@@ -110,7 +110,7 @@ describe('cleanup tests', () => {
110110
})
111111

112112
test('should remove cleanup using returned handler', async () => {
113-
const callSequence = []
113+
const callSequence: string[] = []
114114
addCleanup(() => {
115115
callSequence.push('cleanup')
116116
})
File renamed without changes.

‎test/errorHook.js renamed to ‎test/errorHook.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@ import { useState, useEffect } from 'react'
22
import { renderHook } from '../src'
33

44
describe('error hook tests', () => {
5-
function useError(throwError) {
5+
function useError(throwError: boolean) {
66
if (throwError) {
77
throw new Error('expected')
88
}
99
return true
1010
}
1111

12-
function useAsyncError(throwError) {
13-
const [value, setValue] = useState()
12+
function useAsyncError(throwError: boolean) {
13+
const [value, setValue] = useState<boolean>()
1414
useEffect(() => {
1515
const timeout = setTimeout(() => setValue(throwError), 100)
1616
return () => clearTimeout(timeout)
1717
}, [throwError])
1818
return useError(value)
1919
}
2020

21-
function useEffectError(throwError) {
21+
function useEffectError(throwError: boolean) {
2222
useEffect(() => {
2323
useError(throwError)
2424
}, [throwError])
File renamed without changes.

‎test/suspenseHook.js renamed to ‎test/suspenseHook.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { renderHook } from '../src'
22

33
describe('suspense hook tests', () => {
4-
const cache = {}
5-
const fetchName = (isSuccessful) => {
4+
const cache: { value?: Promise<string | Error> | string | Error } = {}
5+
const fetchName = (isSuccessful: boolean) => {
66
if (!cache.value) {
7-
cache.value = new Promise((resolve, reject) => {
7+
cache.value = new Promise<string>((resolve, reject) => {
88
setTimeout(() => {
99
if (isSuccessful) {
1010
resolve('Bob')
@@ -14,15 +14,15 @@ describe('suspense hook tests', () => {
1414
}, 50)
1515
})
1616
.then((value) => (cache.value = value))
17-
.catch((e) => (cache.value = e))
17+
.catch((e: Error) => (cache.value = e))
1818
}
1919
return cache.value
2020
}
2121

2222
const useFetchName = (isSuccessful = true) => {
2323
const name = fetchName(isSuccessful)
24-
if (typeof name.then === 'function' || name instanceof Error) {
25-
throw name
24+
if (name instanceof Promise || name instanceof Error) {
25+
throw name as unknown
2626
}
2727
return name
2828
}

‎test/tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"declaration": false
5+
},
6+
"exclude": [],
7+
"include": ["."]
8+
}

‎test/useContext.js renamed to ‎test/useContext.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('useContext tests', () => {
1515
test('should get value from context provider', () => {
1616
const TestContext = createContext('foo')
1717

18-
const wrapper = ({ children }) => (
18+
const wrapper: React.FC = ({ children } ) => (
1919
<TestContext.Provider value="bar">{children}</TestContext.Provider>
2020
)
2121

@@ -29,7 +29,7 @@ describe('useContext tests', () => {
2929

3030
const value = { current: 'bar' }
3131

32-
const wrapper = ({ children }) => (
32+
const wrapper: React.FC = ({ children }) => (
3333
<TestContext.Provider value={value.current}>{children}</TestContext.Provider>
3434
)
3535

@@ -45,7 +45,8 @@ describe('useContext tests', () => {
4545
test('should update value in context when props are updated', () => {
4646
const TestContext = createContext('foo')
4747

48-
const wrapper = ({ current, children }) => (
48+
49+
const wrapper: React.FC<{current: string}> = ({ current, children }) => (
4950
<TestContext.Provider value={current}>{children}</TestContext.Provider>
5051
)
5152

‎test/useEffect.js renamed to ‎test/useEffect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { renderHook } from '../src'
33

44
describe('useEffect tests', () => {
55
test('should handle useEffect hook', () => {
6-
const sideEffect = { 1: false, 2: false }
6+
const sideEffect: { [key: number]: boolean } = { 1: false, 2: false }
77

88
const { rerender, unmount } = renderHook(
99
({ id }) => {
@@ -32,7 +32,7 @@ describe('useEffect tests', () => {
3232
})
3333

3434
test('should handle useLayoutEffect hook', () => {
35-
const sideEffect = { 1: false, 2: false }
35+
const sideEffect: { [key: number]: boolean } = { 1: false, 2: false }
3636

3737
const { rerender, unmount } = renderHook(
3838
({ id }) => {
File renamed without changes.

‎test/useReducer.js renamed to ‎test/useReducer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { renderHook, act } from '../src'
33

44
describe('useReducer tests', () => {
55
test('should handle useReducer hook', () => {
6-
const reducer = (state, action) => (action.type === 'inc' ? state + 1 : state)
6+
const reducer = (state: number, action: { type: string }) =>
7+
action.type === 'inc' ? state + 1 : state
78
const { result } = renderHook(() => useReducer(reducer, 0))
89

910
const [initialState, dispatch] = result.current

‎test/useRef.js renamed to ‎test/useRef.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('useHook tests', () => {
1313

1414
test('should handle useImperativeHandle hook', () => {
1515
const { result } = renderHook(() => {
16-
const ref = useRef()
16+
const ref = useRef<Record<string, () => boolean>>({})
1717
useImperativeHandle(ref, () => ({
1818
fakeImperativeMethod: () => true
1919
}))
File renamed without changes.

‎tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
3+
"compilerOptions": {
4+
"allowJs": true,
5+
"target": "ES6"
6+
},
7+
"exclude": ["./test"]
8+
}

0 commit comments

Comments
 (0)
Please sign in to comment.