Testing Library

Testing Library

  • Docs
  • Recipes
  • Help
  • Blog

›Examples

Guides

  • Recipes
  • Which query should I use?
  • Appearance and Disappearance
  • Considerations for fireEvent

Examples

  • Codesandbox Examples
  • Input Event
  • Update Props
  • React Context
  • useReducer
  • React Intl
  • React Redux
  • React Router
  • Reach Router
  • React Transition Group
  • Modals
  • External Examples

Help

  • Learning Material
  • Contributing
Edit

React Redux

// counter.js
import React from 'react'
import { connect } from 'react-redux'

const Counter = ({ dispatch, count }) => {
  const increment = () => {
    dispatch({ type: 'INCREMENT' })
  }

  const decrement = () => {
    dispatch({ type: 'DECREMENT' })
  }

  return (
    <div>
      <h2>Counter</h2>
      <div>
        <button onClick={decrement}>-</button>
        <span data-testid="count-value">{count}</span>
        <button onClick={increment}>+</button>
      </div>
    </div>
  )
}

export default connect(state => ({ count: state.count }))(Counter)

For this example, we'll have a simple reducer that tracks and updates count:

// reducer.js
export const initialState = {
  count: 0,
}

export function reducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + 1,
      }
    case 'DECREMENT':
      return {
        count: state.count - 1,
      }
    default:
      return state
  }
}

To test our connected component we can create a custom render function using the wrapper option as explained in the setup page.
Our custom render function can look like this:

// test-utils.js
import React from 'react'
import { render as rtlRender } from '@testing-library/react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { initialState as reducerInitialState, reducer } from './reducer'

function render(
  ui,
  {
    initialState = reducerInitialState,
    store = createStore(reducer, initialState),
    ...renderOptions
  } = {}
) {
  function Wrapper({ children }) {
    return <Provider store={store}>{children}</Provider>
  }
  return rtlRender(ui, { wrapper: Wrapper, ...renderOptions })
}

// re-export everything
export * from '@testing-library/react'

// override render method
export { render }
// counter.test.js
import React from 'react'
import { createStore } from 'redux'
// We're using our own custom render function and not RTL's render
// our custom utils also re-export everything from RTL
// so we can import fireEvent and screen here as well
import { render, fireEvent, screen } from './test-utils'
import '@testing-library/jest-dom/extend-expect'
import Counter from './counter'

test('can render with redux with defaults', () => {
  render(<Counter />)
  fireEvent.click(screen.getByText('+'))
  expect(screen.getByTestId('count-value')).toHaveTextContent('1')
})

test('can render with redux with custom initial state', () => {
  render(<Counter />, {
    initialState: { count: 3 },
  })
  fireEvent.click(screen.getByText('-'))
  expect(screen.getByTestId('count-value')).toHaveTextContent('2')
})

test('can render with redux with custom store', () => {
  // this is a silly store that can never be changed
  const store = createStore(() => ({ count: 1000 }))
  render(<Counter />, {
    store,
  })
  fireEvent.click(screen.getByText('+'))
  expect(screen.getByTestId('count-value')).toHaveTextContent('1000')
  fireEvent.click(screen.getByText('-'))
  expect(screen.getByTestId('count-value')).toHaveTextContent('1000')
})
Last updated on 4/7/2020
← React IntlReact Router →
Testing Library
Docs
Getting StartedExamplesAPIHelp
Community
BlogStack OverflowDiscord
More
StarGitHubEdit Docs on GitHubHosted by Netlify
Copyright © 2018-2020 Kent C. Dodds and contributors