Skip to content

Commit 3d9ff87

Browse files
committed
Replace core code with testHook from react-testing-library
1 parent 8aa015f commit 3d9ff87

10 files changed

+406
-323
lines changed

package-lock.json

Lines changed: 286 additions & 168 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-hooks-testing-library",
3-
"version": "0.2.4",
3+
"version": "0.3.0",
44
"description": "Simple component wrapper for testing React hooks",
55
"main": "lib/index.js",
66
"author": "Michael Peyper",
@@ -17,31 +17,29 @@
1717
"contributors:add": "all-contributors add"
1818
},
1919
"dependencies": {
20-
"invariant": "^2.2.4",
21-
"react-testing-library": "^5.5.0",
22-
"uuid-v4": "^0.1.0"
20+
"react-testing-library": "^5.8.0"
2321
},
2422
"devDependencies": {
2523
"@babel/cli": "^7.2.3",
26-
"@babel/core": "^7.2.2",
24+
"@babel/core": "^7.3.3",
2725
"@babel/plugin-proposal-object-rest-spread": "^7.3.2",
2826
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
2927
"@babel/preset-env": "^7.3.1",
3028
"@babel/preset-react": "^7.0.0",
31-
"all-contributors-cli": "^5.11.0",
29+
"all-contributors-cli": "^6.1.1",
3230
"babel-eslint": "^10.0.1",
33-
"babel-plugin-module-resolver": "^3.1.3",
34-
"eslint": "^5.13.0",
31+
"babel-plugin-module-resolver": "^3.2.0",
32+
"eslint": "^5.14.0",
3533
"eslint-config-prettier": "^4.0.0",
3634
"eslint-plugin-prettier": "^3.0.1",
3735
"husky": "^1.3.1",
3836
"jest": "^24.1.0",
39-
"lint-staged": "^8.1.3",
37+
"lint-staged": "^8.1.4",
4038
"prettier": "^1.16.4",
4139
"prettier-eslint": "^8.8.2",
4240
"prettier-eslint-cli": "^4.7.1",
43-
"react": "^16.8.0",
44-
"react-dom": "^16.8.0"
41+
"react": "^16.8.2",
42+
"react-dom": "^16.8.2"
4543
},
4644
"peerDependencies": {
4745
"react": "^16.8.0",

src/index.js

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,37 @@
11
import React from 'react'
2-
import { act } from 'react-dom/test-utils'
3-
import { render, cleanup } from 'react-testing-library'
4-
import invariant from 'invariant'
5-
import uuid from 'uuid-v4'
2+
import { render, cleanup, act } from 'react-testing-library'
63

7-
export const useHook = (hook, ...props) => {
8-
const context = {
9-
id: uuid(),
10-
resolveComponent: (Component) => Component,
11-
rendered: false,
12-
props
13-
}
14-
15-
const HookHarness = () => {
16-
context.currentValue = hook(...context.props)
17-
return <div data-testid={context.id} />
18-
}
19-
20-
const renderHook = () => {
21-
const { queryByTestId, rerender } = render(context.resolveComponent(<HookHarness />))
22-
const container = queryByTestId(context.id)
23-
24-
invariant(container !== null, 'Failed to render wrapper component')
25-
26-
context.rendered = true
27-
context.rerender = () => rerender(context.resolveComponent(<HookHarness />))
28-
}
29-
30-
const getCurrentValue = () => {
31-
act(() => {
32-
if (!context.rendered) {
33-
renderHook()
34-
} else {
35-
context.rerender()
36-
}
37-
})
38-
return context.currentValue
39-
}
40-
41-
const setProps = (...newProps) => {
42-
context.props = newProps
43-
}
4+
function TestHook({ callback, hookProps, children }) {
5+
children(callback(hookProps))
6+
return null
7+
}
448

45-
const addContextProvider = (ContextProvider, contextProps) => {
46-
const Provider = ContextProvider.Provider || ContextProvider
47-
const { resolveComponent } = context
48-
const updateContext = (newContextProps) => {
49-
contextProps = newContextProps
50-
}
51-
context.resolveComponent = (Component) => (
52-
<Provider {...contextProps}>{resolveComponent(Component)}</Provider>
9+
function testHook(callback, options = {}) {
10+
const result = { current: null }
11+
const hookProps = { current: options.initialProps }
12+
13+
const toRender = () => {
14+
const hookRender = (
15+
<TestHook callback={callback} hookProps={hookProps.current}>
16+
{(res) => {
17+
result.current = res
18+
}}
19+
</TestHook>
5320
)
54-
return { updateContext }
55-
}
5621

57-
const flushEffects = () => {
58-
getCurrentValue()
22+
return options.wrapper ? React.createElement(options.wrapper, null, hookRender) : hookRender
5923
}
6024

25+
const { unmount, rerender: rerenderComponent } = render(toRender())
26+
6127
return {
62-
getCurrentValue,
63-
getCurrentValues: getCurrentValue,
64-
flushEffects,
65-
setProps,
66-
addContextProvider,
67-
act
28+
result,
29+
unmount,
30+
rerender: (newProps = hookProps.current) => {
31+
hookProps.current = newProps
32+
rerenderComponent(toRender())
33+
}
6834
}
6935
}
7036

71-
export { cleanup }
37+
export { testHook, cleanup, act }

test/customHook.test.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import React from 'react'
12
import { useState, createContext, useContext, useMemo } from 'react'
2-
import { useHook, cleanup } from 'src'
3+
import { testHook, cleanup, act } from 'src'
34

45
describe('custom hook tests', () => {
56
const themes = {
@@ -21,23 +22,23 @@ describe('custom hook tests', () => {
2122
afterEach(cleanup)
2223

2324
test('should get initial theme from custom hook', () => {
24-
const { getCurrentValue } = useHook(() => useTheme('light'))
25+
const { result } = testHook(() => useTheme('light'))
2526

26-
const theme = getCurrentValue()
27+
const theme = result.current
2728

2829
expect(theme.primaryLight).toBe('#FFFFFF')
2930
expect(theme.primaryDark).toBe('#000000')
3031
expect(typeof theme.changeTheme).toBe('function')
3132
})
3233

3334
test('should update theme using custom hook', () => {
34-
const { getCurrentValue, act } = useHook(() => useTheme('light'))
35+
const { result } = testHook(() => useTheme('light'))
3536

36-
const { changeTheme } = getCurrentValue()
37+
const { changeTheme } = result.current
3738

3839
act(() => changeTheme())
3940

40-
const theme = getCurrentValue()
41+
const theme = result.current
4142

4243
expect(theme.primaryLight).toBe('#000000')
4344
expect(theme.primaryDark).toBe('#FFFFFF')
@@ -50,11 +51,13 @@ describe('custom hook tests', () => {
5051
dark: { primaryLight: '#CCBBAA', primaryDark: '#AABBCC' }
5152
}
5253

53-
const { getCurrentValue, addContextProvider } = useHook(() => useTheme('light'))
54+
const wrapper = ({ children }) => (
55+
<ThemesContext.Provider value={customThemes}>{children}</ThemesContext.Provider>
56+
)
5457

55-
addContextProvider(ThemesContext, { value: customThemes })
58+
const { result } = testHook(() => useTheme('light'), { wrapper })
5659

57-
const theme = getCurrentValue()
60+
const theme = result.current
5861

5962
expect(theme.primaryLight).toBe('#AABBCC')
6063
expect(theme.primaryDark).toBe('#CCBBAA')

test/useContext.test.js

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,71 @@
1+
import React from 'react'
12
import { createContext, useContext } from 'react'
2-
import { useHook, cleanup } from 'src'
3+
import { testHook, cleanup } from 'src'
34

45
describe('useContext tests', () => {
56
afterEach(cleanup)
67

78
test('should get default value from context', () => {
89
const TestContext = createContext('foo')
910

10-
const { getCurrentValue } = useHook(() => useContext(TestContext))
11+
const { result } = testHook(() => useContext(TestContext))
1112

12-
const value = getCurrentValue()
13+
const value = result.current
1314

1415
expect(value).toBe('foo')
1516
})
1617

1718
test('should get default value from context provider', () => {
1819
const TestContext = createContext('foo')
1920

20-
const { getCurrentValue } = useHook(() => useContext(TestContext))
21+
const { result } = testHook(() => useContext(TestContext))
2122

22-
const value = getCurrentValue()
23+
const value = result.current
2324

2425
expect(value).toBe('foo')
2526
})
2627

2728
test('should get value from context', () => {
2829
const TestContext = createContext('foo')
2930

30-
const { getCurrentValue, addContextProvider } = useHook(() => useContext(TestContext))
31+
const wrapper = ({ children }) => (
32+
<TestContext.Provider value="bar">{children}</TestContext.Provider>
33+
)
3134

32-
addContextProvider(TestContext, { value: 'bar' })
35+
const { result } = testHook(() => useContext(TestContext), { wrapper })
3336

34-
const value = getCurrentValue()
37+
const value = result.current
3538

3639
expect(value).toBe('bar')
3740
})
3841

3942
test('should get value from context provider', () => {
4043
const TestContext = createContext('foo')
4144

42-
const { getCurrentValue, addContextProvider } = useHook(() => useContext(TestContext))
45+
const wrapper = ({ children }) => (
46+
<TestContext.Provider value="bar">{children}</TestContext.Provider>
47+
)
4348

44-
addContextProvider(TestContext.Provider, { value: 'bar' })
49+
const { result } = testHook(() => useContext(TestContext), { wrapper })
4550

46-
const value = getCurrentValue()
47-
48-
expect(value).toBe('bar')
51+
expect(result.current).toBe('bar')
4952
})
5053

5154
test('should update value in context', () => {
5255
const TestContext = createContext('foo')
5356

54-
const { getCurrentValue, addContextProvider } = useHook(() => useContext(TestContext))
55-
56-
const { updateContext } = addContextProvider(TestContext, { value: 'bar' })
57-
58-
updateContext({ value: 'baz' })
59-
60-
const value = getCurrentValue()
61-
62-
expect(value).toBe('baz')
63-
})
64-
65-
test('should update value in context provider', () => {
66-
const TestContext = createContext('foo')
57+
const value = { current: 'bar' }
6758

68-
const { getCurrentValue, addContextProvider } = useHook(() => useContext(TestContext))
59+
const wrapper = ({ children }) => (
60+
<TestContext.Provider value={value.current}>{children}</TestContext.Provider>
61+
)
6962

70-
const { updateContext } = addContextProvider(TestContext.Provider, { value: 'bar' })
63+
const { result, rerender } = testHook(() => useContext(TestContext), { wrapper })
7164

72-
updateContext({ value: 'baz' })
65+
value.current = 'baz'
7366

74-
const value = getCurrentValue()
67+
rerender()
7568

76-
expect(value).toBe('baz')
69+
expect(result.current).toBe('baz')
7770
})
7871
})

test/useEffect.test.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { useEffect, useLayoutEffect } from 'react'
2-
import { useHook, cleanup } from 'src'
2+
import { testHook, cleanup } from 'src'
33

44
describe('useEffect tests', () => {
55
afterEach(cleanup)
66

77
test('should handle useEffect hook', () => {
88
const sideEffect = { [1]: false, [2]: false }
99

10-
const { flushEffects, setProps } = useHook(
10+
const { rerender, unmount } = testHook(
1111
({ id }) => {
1212
useEffect(() => {
1313
sideEffect[id] = true
@@ -16,45 +16,49 @@ describe('useEffect tests', () => {
1616
}
1717
}, [id])
1818
},
19-
{ id: 1 }
19+
{ initialProps: { id: 1 } }
2020
)
2121

22-
flushEffects()
23-
2422
expect(sideEffect[1]).toBe(true)
2523
expect(sideEffect[2]).toBe(false)
2624

27-
setProps({ id: 2 })
28-
flushEffects()
25+
rerender({ id: 2 })
2926

3027
expect(sideEffect[1]).toBe(false)
3128
expect(sideEffect[2]).toBe(true)
29+
30+
unmount()
31+
32+
expect(sideEffect[1]).toBe(false)
33+
expect(sideEffect[2]).toBe(false)
3234
})
3335

3436
test('should handle useLayoutEffect hook', () => {
3537
const sideEffect = { [1]: false, [2]: false }
3638

37-
const { flushEffects, setProps } = useHook(
39+
const { rerender, unmount } = testHook(
3840
({ id }) => {
39-
useLayoutEffect(() => {
41+
useEffect(() => {
4042
sideEffect[id] = true
4143
return () => {
4244
sideEffect[id] = false
4345
}
4446
}, [id])
4547
},
46-
{ id: 1 }
48+
{ initialProps: { id: 1 } }
4749
)
4850

49-
flushEffects()
50-
5151
expect(sideEffect[1]).toBe(true)
5252
expect(sideEffect[2]).toBe(false)
5353

54-
setProps({ id: 2 })
55-
flushEffects()
54+
rerender({ id: 2 })
5655

5756
expect(sideEffect[1]).toBe(false)
5857
expect(sideEffect[2]).toBe(true)
58+
59+
unmount()
60+
61+
expect(sideEffect[1]).toBe(false)
62+
expect(sideEffect[2]).toBe(false)
5963
})
6064
})

0 commit comments

Comments
 (0)