@@ -8,27 +8,25 @@ title: React Redux
88import React from ' react'
99import { connect } from ' react-redux'
1010
11- class Counter extends React . Component {
12- increment = () => {
13- this . props . dispatch ({ type: ' INCREMENT' })
11+ const Counter = ({ dispatch, count }) => {
12+ const increment = () => {
13+ dispatch ({ type: ' INCREMENT' })
1414 }
1515
16- decrement = () => {
17- this . props . dispatch ({ type: ' DECREMENT' })
16+ const decrement = () => {
17+ dispatch ({ type: ' DECREMENT' })
1818 }
1919
20- render () {
21- return (
20+ return (
21+ < div>
22+ < h2> Counter< / h2>
2223 < div>
23- < h2> Counter< / h2>
24- < div>
25- < button onClick= {this .decrement }> - < / button>
26- < span data- testid= " count-value" > {this .props .count }< / span>
27- < button onClick= {this .increment }> + < / button>
28- < / div>
24+ < button onClick= {this .decrement }> - < / button>
25+ < span data- testid= " count-value" > {count}< / span>
26+ < button onClick= {this .increment }> + < / button>
2927 < / div>
30- )
31- }
28+ < / div >
29+ )
3230}
3331
3432export default connect (state => ({ count: state .count }))(Counter)
@@ -58,58 +56,76 @@ export function reducer(state = initialState, action) {
5856}
5957```
6058
61- Now here's what your test will look like:
59+ To test our connected component we can create a custom ` render ` function using
60+ the ` wrapper ` option as explained in the
61+ [ setup] ( ./react-testing-library/setup.md ) page.
62+ Our custom ` render ` function can look like this:
6263
63- ``` jsx
64- // counter. test.js
64+ ``` js
65+ // test-utils .js
6566import React from ' react'
67+ import { render as rtlRender } from ' @testing-library/react'
6668import { createStore } from ' redux'
6769import { Provider } from ' react-redux'
68- import { render , fireEvent } from ' @testing-library/react'
69- import ' @testing-library/jest-dom/extend-expect'
70- import { initialState , reducer } from ' ./reducer.js'
71- import Counter from ' ./counter.js'
72-
7370
74- // this is a handy function that I normally make available for all my tests
75- // that deal with connected components.
76- // you can provide initialState for the entire store that the ui is rendered with
77- function renderWithRedux (
71+ function render (
7872 ui ,
79- { initialState, store = createStore (reducer, initialState) } = {}
73+ {
74+ initialState,
75+ store = createStore (reducer, initialState),
76+ ... renderOptions
77+ } = {}
8078) {
81- return {
82- ... render (< Provider store= {store}> {ui}< / Provider> ),
83- // adding `store` to the returned utilities to allow us
84- // to reference it in our tests (just try to avoid using
85- // this to test implementation details).
86- store,
79+ function Wrapper ({ children }) {
80+ return < Provider store= {store}> {children}< / Provider>
8781 }
82+ return rtlRender (ui, { wrapper: Wrapper, ... renderOptions })
8883}
8984
85+ // re-export everything
86+ export * from ' @testing-library/react'
87+
88+ // override render method
89+ export { render }
90+ ```
91+
92+ ``` jsx
93+ // counter.test.js
94+ import React from ' react'
95+ import { createStore } from ' redux'
96+ import { Provider } from ' react-redux'
97+ import { } from ' @testing-library/react'
98+ // We're using our own custom render function and not RTL's render
99+ // our custom utils also re-export everything from RTL
100+ // so we can import fireEvent and screen here as well
101+ import { render , fireEvent , screen } from ' ./test-utils.js
102+ import ' @testing-library/jest-dom/extend-expect'
103+ import { initialState, reducer } from ' ./reducer.js'
104+ import Counter from ' ./counter.js'
105+
90106test(' can render with redux with defaults' , () => {
91- const { getByTestId , getByText } = renderWithRedux (< Counter / > )
92- fireEvent .click (getByText (' +' ))
93- expect (getByTestId (' count-value' )).toHaveTextContent (' 1' )
107+ renderWithRedux(<Counter />)
108+ fireEvent.click(screen. getByText(' +' ))
109+ expect(screen. getByTestId(' count-value' )).toHaveTextContent(' 1' )
94110})
95111
96112test(' can render with redux with custom initial state' , () => {
97- const { getByTestId , getByText } = renderWithRedux (< Counter / > , {
113+ renderWithRedux(<Counter />, {
98114 initialState: { count: 3 },
99115 })
100- fireEvent .click (getByText (' -' ))
101- expect (getByTestId (' count-value' )).toHaveTextContent (' 2' )
116+ fireEvent.click(screen. getByText(' -' ))
117+ expect(screen. getByTestId(' count-value' )).toHaveTextContent(' 2' )
102118})
103119
104120test(' can render with redux with custom store' , () => {
105121 // this is a silly store that can never be changed
106122 const store = createStore(() => ({ count: 1000 }))
107- const { getByTestId , getByText } = renderWithRedux (< Counter / > , {
123+ renderWithRedux(<Counter />, {
108124 store,
109125 })
110- fireEvent .click (getByText (' +' ))
111- expect (getByTestId (' count-value' )).toHaveTextContent (' 1000' )
112- fireEvent .click (getByText (' -' ))
113- expect (getByTestId (' count-value' )).toHaveTextContent (' 1000' )
126+ fireEvent.click(screen. getByText(' +' ))
127+ expect(screen. getByTestId(' count-value' )).toHaveTextContent(' 1000' )
128+ fireEvent.click(screen. getByText(' -' ))
129+ expect(screen. getByTestId(' count-value' )).toHaveTextContent(' 1000' )
114130})
115131```
0 commit comments