Skip to content

Commit

Permalink
Use react-hooks-testing-library to test hooks (#1259)
Browse files Browse the repository at this point in the history
* Use react-hooks-testing-library to test hooks

* Disable react/display-name rule with nested .eslintrc file
  • Loading branch information
mpeyper authored and timdorr committed Apr 25, 2019
1 parent 92baa04 commit 756ae49
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 169 deletions.
21 changes: 21 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -74,6 +74,8 @@
"prettier": "^1.16.4",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-hooks-testing-library": "^0.5.0",
"react-test-renderer": "^16.8.6",
"react-testing-library": "^5.9.0",
"redux": "^4.0.1",
"rimraf": "^2.6.3",
Expand Down
5 changes: 5 additions & 0 deletions test/hooks/.eslintrc
@@ -0,0 +1,5 @@
{
"rules": {
"react/display-name": 0
}
}
131 changes: 36 additions & 95 deletions test/hooks/useActions.spec.js
@@ -1,6 +1,6 @@
import React from 'react'
import { createStore } from 'redux'
import * as rtl from 'react-testing-library'
import { renderHook } from 'react-hooks-testing-library'
import { Provider as ProviderMock, useActions } from '../../src/index.js'

describe('React', () => {
Expand Down Expand Up @@ -28,58 +28,29 @@ describe('React', () => {
dispatchedActions = []
})

afterEach(() => rtl.cleanup())

it('supports a single action creator', () => {
const Comp = () => {
const inc1 = useActions(() => ({ type: 'inc1' }))

return (
<>
<button id="bInc1" onClick={inc1} />
</>
)
}

const { container } = rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
const { result } = renderHook(
() => useActions(() => ({ type: 'inc1' })),
{ wrapper: props => <ProviderMock {...props} store={store} /> }
)

const bInc1 = container.querySelector('#bInc1')

rtl.fireEvent.click(bInc1)
result.current()

expect(dispatchedActions).toEqual([{ type: 'inc1' }])
})

it('supports an object of action creators', () => {
const Comp = () => {
const { inc1, inc2 } = useActions({
inc1: () => ({ type: 'inc1' }),
inc2: () => ({ type: 'inc', amount: 2 })
})

return (
<>
<button id="bInc1" onClick={inc1} />
<button id="bInc2" onClick={inc2} />
</>
)
}

const { container } = rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
const { result } = renderHook(
() =>
useActions({
inc1: () => ({ type: 'inc1' }),
inc2: () => ({ type: 'inc', amount: 2 })
}),
{ wrapper: props => <ProviderMock {...props} store={store} /> }
)

const bInc1 = container.querySelector('#bInc1')
const bInc2 = container.querySelector('#bInc2')

rtl.fireEvent.click(bInc1)
rtl.fireEvent.click(bInc2)
result.current.inc1()
result.current.inc2()

expect(dispatchedActions).toEqual([
{ type: 'inc1' },
Expand All @@ -88,31 +59,17 @@ describe('React', () => {
})

it('supports an array of action creators', () => {
const Comp = () => {
const [inc1, inc2] = useActions([
() => ({ type: 'inc1' }),
() => ({ type: 'inc', amount: 2 })
])

return (
<>
<button id="bInc1" onClick={inc1} />
<button id="bInc2" onClick={inc2} />
</>
)
}

const { container } = rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
const { result } = renderHook(
() =>
useActions([
() => ({ type: 'inc1' }),
() => ({ type: 'inc', amount: 2 })
]),
{ wrapper: props => <ProviderMock {...props} store={store} /> }
)

const bInc1 = container.querySelector('#bInc1')
const bInc2 = container.querySelector('#bInc2')

rtl.fireEvent.click(bInc1)
rtl.fireEvent.click(bInc2)
result.current[0]()
result.current[1]()

expect(dispatchedActions).toEqual([
{ type: 'inc1' },
Expand All @@ -133,37 +90,21 @@ describe('React', () => {
const store = createStore(reducer)
dispatchedActions = []

const Comp = () => {
const { adjust } = useActions({
adjust: (amount, isAdd = true) => ({
type: 'adjust',
amount,
isAdd
})
})

return (
<>
<button id="bInc1" onClick={() => adjust(1)} />
<button id="bInc2" onClick={() => adjust(2)} />
<button id="bDec1" onClick={() => adjust(1, false)} />
</>
)
}

const { container } = rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
const { result } = renderHook(
() =>
useActions({
adjust: (amount, isAdd = true) => ({
type: 'adjust',
amount,
isAdd
})
}),
{ wrapper: props => <ProviderMock {...props} store={store} /> }
)

const bInc1 = container.querySelector('#bInc1')
const bInc2 = container.querySelector('#bInc2')
const bDec1 = container.querySelector('#bDec1')

rtl.fireEvent.click(bInc1)
rtl.fireEvent.click(bInc2)
rtl.fireEvent.click(bDec1)
result.current.adjust(1)
result.current.adjust(2)
result.current.adjust(1, false)

expect(dispatchedActions).toEqual([
{ type: 'adjust', amount: 1, isAdd: true },
Expand Down
21 changes: 5 additions & 16 deletions test/hooks/useDispatch.spec.js
@@ -1,30 +1,19 @@
import React from 'react'
import { createStore } from 'redux'
import * as rtl from 'react-testing-library'
import { renderHook } from 'react-hooks-testing-library'
import { Provider as ProviderMock, useDispatch } from '../../src/index.js'

const store = createStore(c => c + 1)

describe('React', () => {
describe('hooks', () => {
describe('useDispatch', () => {
afterEach(() => rtl.cleanup())

it("returns the store's dispatch function", () => {
let dispatch

const Comp = () => {
dispatch = useDispatch()
return <div />
}

rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
)
const { result } = renderHook(() => useDispatch(), {
wrapper: props => <ProviderMock {...props} store={store} />
})

expect(dispatch).toBe(store.dispatch)
expect(result.current).toBe(store.dispatch)
})
})
})
Expand Down
39 changes: 14 additions & 25 deletions test/hooks/useRedux.spec.js
Expand Up @@ -2,49 +2,38 @@

import React from 'react'
import { createStore } from 'redux'
import * as rtl from 'react-testing-library'
import { renderHook, act } from 'react-hooks-testing-library'
import { Provider as ProviderMock, useRedux } from '../../src/index.js'

describe('React', () => {
describe('hooks', () => {
describe('useRedux', () => {
let store
let renderedItems = []

beforeEach(() => {
store = createStore(({ count } = { count: -1 }) => ({
count: count + 1
}))
renderedItems = []
})

afterEach(() => rtl.cleanup())

it('selects the state and binds action creators', () => {
const Comp = () => {
const [count, { inc }] = useRedux(s => s.count, {
inc: () => ({ type: '' })
})
renderedItems.push(count)
return (
<>
<div>{count}</div>
<button id="bInc" onClick={inc} />
</>
)
}

const { container } = rtl.render(
<ProviderMock store={store}>
<Comp />
</ProviderMock>
const { result } = renderHook(
() =>
useRedux(s => s.count, {
inc: () => ({ type: '' })
}),
{
wrapper: props => <ProviderMock {...props} store={store} />
}
)

const bInc = container.querySelector('#bInc')
expect(result.current[0]).toEqual(0)

rtl.fireEvent.click(bInc)
act(() => {
result.current[1].inc()
})

expect(renderedItems).toEqual([0, 1])
expect(result.current[0]).toEqual(1)
})
})
})
Expand Down
12 changes: 3 additions & 9 deletions test/hooks/useReduxContext.spec.js
@@ -1,21 +1,15 @@
import React from 'react'
import * as rtl from 'react-testing-library'
import { renderHook } from 'react-hooks-testing-library'
import { useReduxContext } from '../../src/hooks/useReduxContext'

describe('React', () => {
describe('hooks', () => {
describe('useReduxContext', () => {
afterEach(() => rtl.cleanup())

it('throws if component is not wrapped in provider', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {})

const Comp = () => {
useReduxContext()
return <div />
}
const { result } = renderHook(() => useReduxContext())

expect(() => rtl.render(<Comp />)).toThrow(
expect(result.error.message).toMatch(
/could not find react-redux context value/
)

Expand Down

0 comments on commit 756ae49

Please sign in to comment.