-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
react-redux.js
106 lines (94 loc) 路 2.94 KB
/
react-redux.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React from 'react'
import {createStore} from 'redux'
import {Provider, connect} from 'react-redux'
import {render, fireEvent, cleanup} from 'react-testing-library'
// counter.js
class Counter extends React.Component {
increment = () => {
this.props.dispatch({type: 'INCREMENT'})
}
decrement = () => {
this.props.dispatch({type: 'DECREMENT'})
}
render() {
return (
<div>
<h2>Counter</h2>
<div>
<button onClick={this.decrement}>-</button>
<span data-testid="count-value">{this.props.count}</span>
<button onClick={this.increment}>+</button>
</div>
</div>
)
}
}
// normally this would be:
// export default connect(state => ({count: state.count}))(Counter)
// but for this test we'll give it a variable name
// because we're doing this all in one file
const ConnectedCounter = connect(state => ({count: state.count}))(Counter)
// app.js
function reducer(state = {count: 0}, action) {
switch (action.type) {
case 'INCREMENT':
return {
count: state.count + 1,
}
case 'DECREMENT':
return {
count: state.count - 1,
}
default:
return state
}
}
// normally here you'd do:
// const store = createStore(reducer)
// ReactDOM.render(
// <Provider store={store}>
// <Counter />
// </Provider>,
// document.getElementById('root'),
// )
// but for this test we'll umm... not do that :)
// Now here's what your test will look like:
afterEach(cleanup)
// this is a handy function that I normally make available for all my tests
// that deal with connected components.
// you can provide initialState or the entire store that the ui is rendered with
function renderWithRedux(
ui,
{initialState, store = createStore(reducer, initialState)} = {},
) {
return {
...render(<Provider store={store}>{ui}</Provider>),
// adding `store` to the returned utilities to allow us
// to reference it in our tests (just try to avoid using
// this to test implementation details).
store,
}
}
test('can render with redux with defaults', () => {
const {getByTestId, getByText} = renderWithRedux(<ConnectedCounter />)
fireEvent.click(getByText('+'))
expect(getByTestId('count-value').textContent).toBe('1')
})
test('can render with redux with custom initial state', () => {
const {getByTestId, getByText} = renderWithRedux(<ConnectedCounter />, {
initialState: {count: 3},
})
fireEvent.click(getByText('-'))
expect(getByTestId('count-value').textContent).toBe('2')
})
test('can render with redux with custom store', () => {
// this is a silly store that can never be changed
const store = createStore(() => ({count: 1000}))
const {getByTestId, getByText} = renderWithRedux(<ConnectedCounter />, {
store,
})
fireEvent.click(getByText('+'))
expect(getByTestId('count-value').textContent).toBe('1000')
fireEvent.click(getByText('-'))
expect(getByTestId('count-value').textContent).toBe('1000')
})