Skip to content

Commit 01aa2e7

Browse files
committed
Simplified internals. More tests
1 parent 6bf8228 commit 01aa2e7

15 files changed

+445
-228
lines changed

src/createContext.js

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

src/flush.js

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

src/index.js

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,86 @@
1-
import createContext from './createContext'
2-
import useHookAdvanced from './useHookAdvanced'
1+
import React from 'react'
2+
import { render, cleanup } from 'react-testing-library'
3+
import invariant from 'invariant'
4+
import uuid from 'uuid-v4'
35

4-
export { cleanup } from 'react-testing-library'
6+
export const useHook = (hook, ...props) => {
7+
const context = {
8+
id: uuid(),
9+
resolveComponent: (Component) => Component,
10+
rendered: false,
11+
props
12+
}
513

6-
export const useHook = (hook) => useHookAdvanced(hook, createContext())
14+
const HookHarness = () => {
15+
context.currentValue = hook(...context.props)
16+
return <div data-testid={context.id} />
17+
}
18+
19+
const renderHook = () => {
20+
const { queryByTestId, rerender } = render(context.resolveComponent(<HookHarness />))
21+
const container = queryByTestId(context.id)
22+
23+
invariant(container !== null, 'Failed to render wrapper component')
24+
25+
context.rendered = true
26+
context.rerender = () => rerender(context.resolveComponent(<HookHarness />))
27+
}
28+
29+
const getCurrentValue = () => {
30+
if (!context.rendered) {
31+
renderHook()
32+
} else {
33+
context.rerender()
34+
}
35+
return context.currentValue
36+
}
37+
38+
const setProps = (...newProps) => {
39+
context.props = newProps
40+
}
41+
42+
const addContextProvider = (ContextProvider, contextProps) => {
43+
const Provider = ContextProvider.Provider || ContextProvider
44+
const { resolveComponent } = context
45+
const updateContext = (newContextProps) => {
46+
contextProps = newContextProps
47+
}
48+
context.resolveComponent = (Component) => (
49+
<Provider {...contextProps}>{resolveComponent(Component)}</Provider>
50+
)
51+
return { updateContext }
52+
}
53+
54+
const flushEffects = (minTimes = 1, maxTimes = Math.max(minTimes + 1, 100)) => {
55+
invariant(
56+
minTimes > 0 && minTimes <= maxTimes,
57+
`minTimes (${minTimes}) must me a positive number that is less than maxTimes (${maxTimes})`
58+
)
59+
invariant(maxTimes > 0, `maxTimes (${maxTimes}) must me a positive number`)
60+
61+
let lastValue
62+
let currentValue
63+
let flushCount = 0
64+
65+
while ((currentValue !== lastValue || flushCount < minTimes) && flushCount < maxTimes) {
66+
lastValue = currentValue
67+
currentValue = getCurrentValue()
68+
flushCount++
69+
}
70+
71+
invariant(
72+
flushCount < Math.max(minTimes, maxTimes),
73+
`Hook values have not resolved after recalculating ${maxTimes} times`
74+
)
75+
}
76+
77+
return {
78+
getCurrentValue,
79+
getCurrentValues: getCurrentValue,
80+
flushEffects,
81+
setProps,
82+
addContextProvider
83+
}
84+
}
85+
86+
export { cleanup }

src/update.js

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

src/use.js

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

src/useHookAdvanced.js

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

src/withContextProvider.js

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

test/customHook.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { useState, createContext, useContext, useMemo } from 'react'
2+
import { useHook, cleanup } from 'src'
3+
4+
describe('custom hook tests', () => {
5+
const themes = {
6+
light: { primaryLight: '#FFFFFF', primaryDark: '#000000' },
7+
dark: { primaryLight: '#000000', primaryDark: '#FFFFFF' }
8+
}
9+
10+
const ThemesContext = createContext(themes)
11+
12+
const useTheme = (initialTheme) => {
13+
const themes = useContext(ThemesContext)
14+
const [theme, setTheme] = useState(initialTheme)
15+
const changeTheme = () => {
16+
setTheme(theme === 'light' ? 'dark' : 'light')
17+
}
18+
return useMemo(() => ({ ...themes[theme], changeTheme }), [theme])
19+
}
20+
21+
afterEach(cleanup)
22+
23+
test('should get initial theme from custom hook', () => {
24+
const { getCurrentValue } = useHook(() => useTheme('light'))
25+
26+
const theme = getCurrentValue()
27+
28+
expect(theme.primaryLight).toBe('#FFFFFF')
29+
expect(theme.primaryDark).toBe('#000000')
30+
expect(typeof theme.changeTheme).toBe('function')
31+
})
32+
33+
test('should update theme using custom hook', () => {
34+
const { getCurrentValue } = useHook(() => useTheme('light'))
35+
36+
const { changeTheme } = getCurrentValue()
37+
38+
changeTheme()
39+
40+
const theme = getCurrentValue()
41+
42+
expect(theme.primaryLight).toBe('#000000')
43+
expect(theme.primaryDark).toBe('#FFFFFF')
44+
expect(typeof theme.changeTheme).toBe('function')
45+
})
46+
})

test/integration.test.js

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

test/setState.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useState } from 'react'
2+
import { useHook, cleanup } from 'src'
3+
4+
describe('useState tests', () => {
5+
afterEach(cleanup)
6+
7+
test('should use setState value', () => {
8+
const { getCurrentValue } = useHook(() => useState('foo'))
9+
10+
const [value] = getCurrentValue()
11+
12+
expect(value).toBe('foo')
13+
})
14+
15+
test('should update setState value using setter', () => {
16+
const { getCurrentValues } = useHook(() => useState('foo'))
17+
18+
const [_, setValue] = getCurrentValues()
19+
20+
setValue('bar')
21+
22+
const [value] = getCurrentValues()
23+
24+
expect(value).toBe('bar')
25+
})
26+
})

0 commit comments

Comments
 (0)