Skip to content

Commit f1adbd0

Browse files
author
Jeff Jia
committed
Add some async api calls to redux.
1 parent b72e0b3 commit f1adbd0

File tree

9 files changed

+100
-25
lines changed

9 files changed

+100
-25
lines changed

app/__tests__/index-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ describe('Index', ()=> {
1111

1212
var mockStore;
1313
beforeEach(()=> {
14-
mockStore = new MockStore();
14+
mockStore = new MockStore({text:'text'});
1515
sinon.stub(StoreFactory, 'create').returns(mockStore)
1616
});
1717

app/__tests__/main-test.js

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const {View,Text,TouchableHighlight} = React;
22
import StoreFactory from '../storeFactory'
33
import {Provider} from 'react-redux'
44
import ActionTypes from '../actions/actionTypes'
5+
import Actions from '../actions/actions'
56
import WrappedMain, {Main} from '../main.js';
67

78
describe('Wrapped Main View', ()=> {
@@ -12,16 +13,19 @@ describe('Wrapped Main View', ()=> {
1213
stateText = 'Wrapper text';
1314
store = StoreFactory.create();
1415
sinon.stub(store, 'getState').returns({text: stateText});
15-
sinon.spy(store, 'dispatch');
16+
sinon.stub(store, 'dispatch');
17+
18+
sinon.spy(Actions, 'getAPIText');
1619
var mainWrapper = mount(<Provider store={store}><WrappedMain/></Provider>);
1720
main = mainWrapper.find(Main);
1821
});
1922

2023
afterEach(()=> {
24+
Actions.getAPIText.restore();
2125
store.getState.restore();
2226
store.dispatch.restore();
2327
});
24-
28+
2529
it('It translates correct store state to properties', ()=> {
2630
expect(main.prop('text')).to.eql(stateText);
2731
});
@@ -38,7 +42,15 @@ describe('Wrapped Main View', ()=> {
3842
var dispatch = store.dispatch.lastCall.args[0];
3943
expect(dispatch.type).to.equal(ActionTypes.CHANGE_TEXT);
4044
expect(dispatch.text).to.equal('Hello Text');
45+
});
4146

47+
it('It provides getAPIText property which dispatches getAPIText action', ()=> {
48+
var getAPITextFunction = main.prop('getAPIText');
49+
50+
getAPITextFunction();
51+
var dispatch = store.dispatch.lastCall;
52+
//dispatch.args[0]();
53+
expect(Actions.getAPIText.called).to.equal(true);
4254
});
4355
});
4456

@@ -49,7 +61,7 @@ describe('Main View', function () {
4961

5062
before(()=> {
5163
textValue = 'here is the text';
52-
main = mount(<Main text={textValue} changeText={()=>{}}/>);
64+
main = mount(<Main text={textValue} changeText={()=>{}} getAPIText={()=>{}}/>);
5365
});
5466

5567
it('Has a view with some text', ()=> {
@@ -58,35 +70,51 @@ describe('Main View', function () {
5870
expect(text.text()).to.equal(textValue);
5971
});
6072

61-
it('Has a button', ()=> {
73+
it('Has a push me button', ()=> {
6274
var view = main.find(View);
63-
var button = view.find(TouchableHighlight);
75+
var button = view.find(TouchableHighlight).at(0);
6476
var buttonText = button.find(Text);
6577
expect(buttonText.text()).to.equal('Push Me');
6678
});
79+
80+
it('Has a Get Text From server button', ()=> {
81+
var view = main.find(View);
82+
var button = view.find(TouchableHighlight).at(1);
83+
var buttonText = button.find(Text);
84+
expect(buttonText.text()).to.equal('Get Text from server');
85+
});
6786
});
6887

6988
describe('Interaction', () => {
70-
it('Fires on click property on button press sends Hello React to changeText method', ()=> {
89+
it('Fires changeText property on button press sends Hello React to changeText method', ()=> {
7190
var changeTextSpy = sinon.spy();
7291
var text = '';
73-
var main = mount(<Main text={text} changeText={changeTextSpy}/>);
74-
var button = main.find(TouchableHighlight);
92+
var main = mount(<Main text={text} changeText={changeTextSpy} getAPIText={()=>{}}/>);
93+
var button = main.find(TouchableHighlight).at(0);
7594

7695
button.prop('onPress')();
7796
expect(changeTextSpy.called).to.equal(true);
7897
expect(changeTextSpy.lastCall.args).to.eql(['Hello React']);
7998
});
8099

81-
it('Fires on click property on button press sends Goodbye React to changeText method if text prop is Hello React', ()=> {
100+
it('Fires changeText property on button press sends Goodbye React to changeText method if text prop is Hello React', ()=> {
82101
var changeTextSpy = sinon.spy();
83102
var text = 'Hello React';
84-
var main = mount(<Main text={text} changeText={changeTextSpy}/>);
85-
var button = main.find(TouchableHighlight);
103+
var main = mount(<Main text={text} changeText={changeTextSpy} getAPIText={()=>{}}/>);
104+
var button = main.find(TouchableHighlight).at(0);
86105

87106
button.prop('onPress')();
88107
expect(changeTextSpy.called).to.equal(true);
89108
expect(changeTextSpy.lastCall.args).to.eql(['Goodbye React']);
90109
});
110+
111+
it('Fires getAPIText property on button pressed', ()=> {
112+
var apiTextSpy = sinon.spy();
113+
var main = mount(<Main text={''} changeText={()=>{}} getAPIText={apiTextSpy}/>);
114+
var button = main.find(TouchableHighlight).at(1);
115+
116+
button.prop('onPress')();
117+
expect(apiTextSpy.called).to.equal(true);
118+
});
91119
});
92120
});

app/actions/__tests__/actions-test.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
import actions from '../actions';
22
import ActionTypes from '../actionTypes';
3-
4-
describe('Actions View', ()=> {
3+
import FetchMock from 'fetch-mock';
4+
describe('Actions', ()=> {
55
describe('changeText', ()=> {
66
it('Returns the correct payload', ()=> {
77
var newText = 'Here is the next text';
88
var payload = actions.changeText(newText);
99
expect(payload).to.eql({type: ActionTypes.CHANGE_TEXT, text: newText});
1010
});
11-
})
11+
});
12+
13+
describe('gotAPIText', ()=> {
14+
it('Returns the correct payload', ()=> {
15+
var response = {response: 'stuff'};
16+
var payload = actions.gotAPIText(response);
17+
expect(payload).to.eql({type: ActionTypes.GOT_API_TEXT, response: response});
18+
});
19+
});
20+
21+
describe('getAPIText', ()=> {
22+
it('Calls fetch to the api, and dispatches got APIText on success', (done)=> {
23+
24+
var spy = sinon.spy();
25+
var responseJson = {text: 'sometext'};
26+
FetchMock.mock('http://localhost:3000/', responseJson);
27+
28+
actions.getAPIText()(spy).then(()=>{
29+
expect(FetchMock.called('http://localhost:3000/')).to.equal(true);
30+
expect(spy.calledWith(responseJson));
31+
FetchMock.restore();
32+
done();
33+
});
34+
35+
});
36+
});
1237
});

app/actions/actionTypes.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
const CHANGE_TEXT = 'CHANGE_TEXT';
2-
3-
module.exports ={CHANGE_TEXT};
2+
const GET_API_TEXT='GET_API_TEXT';
3+
const GOT_API_TEXT='GOT_API_TEXT';
4+
module.exports ={CHANGE_TEXT,GET_API_TEXT,GOT_API_TEXT};

app/actions/actions.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import ActionTypes from './actionTypes.js';
22

3-
function changeText(text){
3+
function changeText(text) {
44
return {type: ActionTypes.CHANGE_TEXT, text: text};
55
}
6+
function getAPIText() {
7+
return ((dispatch)=> {
8+
return fetch('http://localhost:3000/')
9+
.then((response)=> {
10+
return response.json();
11+
}).then((json)=> {
12+
dispatch(gotAPIText(json));
13+
});
14+
})
15+
}
16+
17+
function gotAPIText(response) {
18+
19+
return {type: ActionTypes.GOT_API_TEXT, response: response}
20+
}
621

7-
module.exports = {changeText};
22+
module.exports = {changeText, getAPIText, gotAPIText};

app/main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
'use strict';
66
import {bindActionCreators} from 'redux';
77
import { connect} from 'react-redux';
8-
import {changeText} from './actions/actions';
8+
import {changeText, getAPIText} from './actions/actions';
99
import React,
1010
{
1111
Component,
@@ -31,12 +31,12 @@ export class Main extends Component {
3131
}
3232
}
3333

34-
3534
render() {
3635
return (
3736
<View style={styles.container}>
3837
<Text>{this.props.text}</Text>
3938
<TouchableHighlight onPress={this._updateText}><Text>Push Me</Text></TouchableHighlight>
39+
<TouchableHighlight onPress={this.props.getAPIText}><Text>Get Text from server</Text></TouchableHighlight>
4040
</View>
4141
);
4242
}
@@ -73,7 +73,7 @@ const mapStateToProps = (state) => {
7373
};
7474

7575
const mapDispatchToProps = (dispatch) => {
76-
return bindActionCreators({changeText}, dispatch);
76+
return bindActionCreators({changeText, getAPIText}, dispatch);
7777
};
7878

7979
export default connect(mapStateToProps, mapDispatchToProps)(Main);

app/reducers/reducers.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ function text(state = 'Hello Tests', action = {type: 'NONE'}) {
55
switch (action.type) {
66
case ActionTypes.CHANGE_TEXT:
77
return action.text;
8+
case ActionTypes.GOT_API_TEXT:
9+
return action.response.text;
810
default:
911
return state
1012
}

app/storeFactory.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { createStore } from 'redux';
1+
import { createStore, applyMiddleware} from 'redux';
22
import reducer from './reducers/reducers'
3-
3+
import thunk from 'redux-thunk'
44
export default {
55
create: (initialState)=> {
6-
return createStore(reducer, initialState);
6+
return createStore(reducer, initialState, applyMiddleware(thunk));
77
}
88
};

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
"babel-preset-react": "^6.3.13",
1717
"chai": "^3.5.0",
1818
"enzyme": "^1.5.0",
19+
"es6-promise": "^3.1.2",
20+
"fetch-mock": "^4.1.1",
1921
"ignore-styles": "^1.2.0",
2022
"mocha": "^2.4.5",
23+
"nock": "^7.2.2",
2124
"react-addons-test-utils": "^0.14.3",
2225
"react-dom": "^0.14.3",
26+
"redux-thunk": "^2.0.1",
2327
"sinon": "^1.17.3"
2428
}
2529
}

0 commit comments

Comments
 (0)