Skip to content

Commit 5bf647d

Browse files
Ephemtimdorr
authored andcommitted
Add first SSR integration-tests (#1197)
* Added integration test-folder and first basic server-rendering test * Added tests for dispatching actions serverside
1 parent 162b81a commit 5bf647d

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

test/install-test-deps.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ readdirSync(join(__dirname, 'react')).forEach(version => {
1212
console.log(`skipping ${version}, ${reactVersion} was specified`)
1313
return
1414
}
15-
const tests = [join(__dirname, 'components'), join(__dirname, 'utils')]
15+
const tests = [
16+
join(__dirname, 'components'),
17+
join(__dirname, 'integration'),
18+
join(__dirname, 'utils')
19+
]
1620
const srcs = [
1721
join(__dirname, '..', 'src', 'components'),
1822
join(__dirname, '..', 'src', 'connect'),
1923
join(__dirname, '..', 'src', 'utils')
2024
]
2125
const dest = [
2226
join(__dirname, 'react', version, 'test', 'components'),
27+
join(__dirname, 'react', version, 'test', 'integration'),
2328
join(__dirname, 'react', version, 'test', 'utils')
2429
]
2530
const srcDest = [
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*eslint-disable react/prop-types*/
2+
3+
import React from 'react'
4+
import { renderToString } from 'react-dom/server'
5+
import { createStore } from 'redux'
6+
import { Provider, connect } from '../../src/index.js'
7+
8+
describe('React', () => {
9+
describe('server rendering', () => {
10+
function greetingReducer(state = { greeting: 'Hello' }, action) {
11+
return action && action.payload ? action.payload : state
12+
}
13+
14+
const Greeting = ({ greeting, greeted }) => greeting + ' ' + greeted
15+
const ConnectedGreeting = connect(state => state)(Greeting)
16+
17+
const Greeter = props => (
18+
<div>
19+
<ConnectedGreeting {...props} />
20+
</div>
21+
)
22+
23+
it('should be able to render connected component with props and state from store', () => {
24+
const store = createStore(greetingReducer)
25+
26+
const markup = renderToString(
27+
<Provider store={store}>
28+
<Greeter greeted="world" />
29+
</Provider>
30+
)
31+
32+
expect(markup).toContain('Hello world')
33+
})
34+
35+
it('should render with updated state if actions are dispatched before render', () => {
36+
const store = createStore(greetingReducer)
37+
38+
store.dispatch({ type: 'Update', payload: { greeting: 'Hi' } })
39+
40+
const markup = renderToString(
41+
<Provider store={store}>
42+
<Greeter greeted="world" />
43+
</Provider>
44+
)
45+
46+
expect(markup).toContain('Hi world')
47+
expect(store.getState().greeting).toContain('Hi')
48+
})
49+
50+
it('should render children with original state even if actions are dispatched in ancestor', () => {
51+
/*
52+
Dispatching during construct, render or willMount is
53+
almost always a bug with SSR (or otherwise)
54+
55+
This behaviour is undocumented and is likely to change between
56+
implementations, this test only verifies current behaviour
57+
*/
58+
const store = createStore(greetingReducer)
59+
60+
class Dispatcher extends React.Component {
61+
constructor(props) {
62+
super(props)
63+
props.dispatch(props.action)
64+
}
65+
UNSAFE_componentWillMount() {
66+
this.props.dispatch(this.props.action)
67+
}
68+
render() {
69+
this.props.dispatch(this.props.action)
70+
71+
return <Greeter greeted={this.props.greeted} />
72+
}
73+
}
74+
const ConnectedDispatcher = connect()(Dispatcher)
75+
76+
const action = { type: 'Update', payload: { greeting: 'Hi' } }
77+
78+
const markup = renderToString(
79+
<Provider store={store}>
80+
<ConnectedDispatcher action={action} greeted="world" />
81+
</Provider>
82+
)
83+
84+
expect(markup).toContain('Hello world')
85+
expect(store.getState().greeting).toContain('Hi')
86+
})
87+
88+
it('should render children with changed state if actions are dispatched in ancestor and new Provider wraps children', () => {
89+
/*
90+
Dispatching during construct, render or willMount is
91+
almost always a bug with SSR (or otherwise)
92+
93+
This behaviour is undocumented and is likely to change between
94+
implementations, this test only verifies current behaviour
95+
*/
96+
const store = createStore(greetingReducer)
97+
98+
class Dispatcher extends React.Component {
99+
constructor(props) {
100+
super(props)
101+
if (props.constructAction) {
102+
props.dispatch(props.constructAction)
103+
}
104+
}
105+
UNSAFE_componentWillMount() {
106+
if (this.props.willMountAction) {
107+
this.props.dispatch(this.props.willMountAction)
108+
}
109+
}
110+
render() {
111+
if (this.props.renderAction) {
112+
this.props.dispatch(this.props.renderAction)
113+
}
114+
115+
return (
116+
<Provider store={store}>
117+
<Greeter greeted={this.props.greeted} />
118+
</Provider>
119+
)
120+
}
121+
}
122+
const ConnectedDispatcher = connect()(Dispatcher)
123+
124+
const constructAction = { type: 'Update', payload: { greeting: 'Hi' } }
125+
const willMountAction = { type: 'Update', payload: { greeting: 'Hiya' } }
126+
const renderAction = { type: 'Update', payload: { greeting: 'Hey' } }
127+
128+
const markup = renderToString(
129+
<Provider store={store}>
130+
<ConnectedDispatcher
131+
constructAction={constructAction}
132+
greeted="world"
133+
/>
134+
<ConnectedDispatcher
135+
willMountAction={willMountAction}
136+
greeted="world"
137+
/>
138+
<ConnectedDispatcher renderAction={renderAction} greeted="world" />
139+
</Provider>
140+
)
141+
142+
expect(markup).toContain('Hi world')
143+
expect(markup).toContain('Hiya world')
144+
expect(markup).toContain('Hey world')
145+
expect(store.getState().greeting).toContain('Hey')
146+
})
147+
})
148+
})

0 commit comments

Comments
 (0)