Skip to content

Commit 2a08009

Browse files
committed
Merge pull request #380 from sambs/example-tests-rebased
tests for the examples
2 parents a467c41 + 8cbd405 commit 2a08009

File tree

21 files changed

+991
-15
lines changed

21 files changed

+991
-15
lines changed

examples/buildAll.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ var exampleDirs = fs.readdirSync(__dirname).filter((file) => {
1313
// Ordering is important here. `npm install` must come first.
1414
var cmdArgs = [
1515
{ cmd: 'npm', args: ['install'] },
16-
{ cmd: 'webpack', args: ['index.js'] }
16+
{ cmd: 'webpack', args: ['index.js'] },
17+
{ cmd: 'npm', args: ['test'] }
1718
];
1819

1920
for (let dir of exampleDirs) {

examples/counter/actions/CounterActions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ export function incrementIfOdd() {
2424
};
2525
}
2626

27-
export function incrementAsync() {
27+
export function incrementAsync(delay=1000) {
2828
return dispatch => {
2929
setTimeout(() => {
3030
dispatch(increment());
31-
}, 1000);
31+
}, delay);
3232
};
3333
}

examples/counter/components/Counter.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React, { Component, PropTypes } from 'react';
22

33
class Counter extends Component {
4+
45
render() {
5-
const { increment, incrementIfOdd, decrement, counter } = this.props;
6+
const { increment, incrementIfOdd, incrementAsync, decrement, counter } = this.props;
67
return (
78
<p>
89
Clicked: {counter} times
@@ -12,6 +13,8 @@ class Counter extends Component {
1213
<button onClick={decrement}>-</button>
1314
{' '}
1415
<button onClick={incrementIfOdd}>Increment if odd</button>
16+
{' '}
17+
<button onClick={() => incrementAsync()}>Increment async</button>
1518
</p>
1619
);
1720
}
@@ -20,6 +23,7 @@ class Counter extends Component {
2023
Counter.propTypes = {
2124
increment: PropTypes.func.isRequired,
2225
incrementIfOdd: PropTypes.func.isRequired,
26+
incrementAsync: PropTypes.func.isRequired,
2327
decrement: PropTypes.func.isRequired,
2428
counter: PropTypes.number.isRequired
2529
};

examples/counter/containers/App.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import React, { Component } from 'react';
2-
import CounterApp from './CounterApp';
3-
import { createStore, applyMiddleware, combineReducers } from 'redux';
4-
import thunk from 'redux-thunk';
52
import { Provider } from 'react-redux';
6-
import * as reducers from '../reducers';
3+
import CounterApp from './CounterApp';
4+
import createCounterStore from '../store/createCounterStore';
75

8-
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
9-
const reducer = combineReducers(reducers);
10-
const store = createStoreWithMiddleware(reducer);
6+
const store = createCounterStore();
117

128
export default class App extends Component {
139
render() {

examples/counter/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "Counter example for redux",
55
"main": "server.js",
66
"scripts": {
7-
"start": "node server.js"
7+
"start": "node server.js",
8+
"test": "mocha --recursive --compilers js:babel/register"
89
},
910
"repository": {
1011
"type": "git",
@@ -35,6 +36,10 @@
3536
"devDependencies": {
3637
"babel-core": "^5.6.18",
3738
"babel-loader": "^5.1.4",
39+
"expect": "^1.6.0",
40+
"jsdom": "^5.6.1",
41+
"mocha": "^2.2.5",
42+
"mocha-jsdom": "^1.0.0",
3843
"node-libs-browser": "^0.5.2",
3944
"react-hot-loader": "^1.2.7",
4045
"webpack": "^1.9.11",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createStore, applyMiddleware, combineReducers } from 'redux';
2+
import thunk from 'redux-thunk';
3+
import * as reducers from '../reducers';
4+
5+
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
6+
const reducer = combineReducers(reducers);
7+
8+
export default function createCounterStore(initialState) {
9+
return createStoreWithMiddleware(reducer, initialState);
10+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import expect from 'expect';
2+
import * as actions from '../../actions/CounterActions';
3+
import * as types from '../../constants/ActionTypes';
4+
5+
describe('actions', () => {
6+
7+
it('increment should create increment action', () => {
8+
expect(actions.increment()).toEqual({ type: types.INCREMENT_COUNTER });
9+
});
10+
11+
it('decrement should create decrement action', () => {
12+
expect(actions.decrement()).toEqual({ type: types.DECREMENT_COUNTER });
13+
});
14+
15+
it('incrementIfOdd should create increment action', () => {
16+
let fn = actions.incrementIfOdd();
17+
expect(fn).toBeA('function');
18+
let dispatch = expect.createSpy();
19+
let getState = () => ({ counter: 1 });
20+
fn(dispatch, getState);
21+
expect(dispatch).toHaveBeenCalledWith({ type: types.INCREMENT_COUNTER });
22+
});
23+
24+
it('incrementIfOdd shouldnt create increment action if counter is even', () => {
25+
let fn = actions.incrementIfOdd();
26+
let dispatch = expect.createSpy();
27+
let getState = () => ({ counter: 2 });
28+
fn(dispatch, getState);
29+
expect(dispatch.calls.length).toBe(0);
30+
});
31+
32+
// There's no nice way to test this at the moment...
33+
it('incrementAsync', (done) => {
34+
let fn = actions.incrementAsync(1);
35+
expect(fn).toBeA('function');
36+
let dispatch = expect.createSpy();
37+
fn(dispatch);
38+
setTimeout(() => {
39+
expect(dispatch).toHaveBeenCalledWith({ type: types.INCREMENT_COUNTER });
40+
done();
41+
}, 5);
42+
});
43+
});
44+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import expect from 'expect';
2+
import jsdomReact from '../jsdomReact';
3+
import React from 'react/addons';
4+
import Counter from '../../components/Counter';
5+
6+
const { TestUtils } = React.addons;
7+
8+
function setup() {
9+
const actions = {
10+
increment: expect.createSpy(),
11+
incrementIfOdd: expect.createSpy(),
12+
incrementAsync: expect.createSpy(),
13+
decrement: expect.createSpy()
14+
};
15+
const component = TestUtils.renderIntoDocument(<Counter counter={1} {...actions} />);
16+
return {
17+
component: component,
18+
actions: actions,
19+
buttons: TestUtils.scryRenderedDOMComponentsWithTag(component, 'button').map(button => {
20+
return button.getDOMNode();
21+
}),
22+
p: TestUtils.findRenderedDOMComponentWithTag(component, 'p').getDOMNode()
23+
};
24+
}
25+
26+
describe('Counter component', () => {
27+
jsdomReact();
28+
29+
it('should display count', () => {
30+
const { p } = setup();
31+
expect(p.textContent).toMatch(/^Clicked: 1 times/);
32+
});
33+
34+
it('first button should call increment', () => {
35+
const { buttons, actions } = setup();
36+
TestUtils.Simulate.click(buttons[0]);
37+
expect(actions.increment).toHaveBeenCalled();
38+
});
39+
40+
it('second button should call decrement', () => {
41+
const { buttons, actions } = setup();
42+
TestUtils.Simulate.click(buttons[1]);
43+
expect(actions.decrement).toHaveBeenCalled();
44+
});
45+
46+
it('third button should call incrementIfOdd', () => {
47+
const { buttons, actions } = setup();
48+
TestUtils.Simulate.click(buttons[2]);
49+
expect(actions.incrementIfOdd).toHaveBeenCalled();
50+
});
51+
52+
it('fourth button should call incrementAsync', () => {
53+
const { buttons, actions } = setup();
54+
TestUtils.Simulate.click(buttons[3]);
55+
expect(actions.incrementAsync).toHaveBeenCalled();
56+
});
57+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import expect from 'expect';
2+
import jsdomReact from '../jsdomReact';
3+
import React from 'react/addons';
4+
import { Provider } from 'react-redux';
5+
import CounterApp from '../../containers/CounterApp';
6+
import createCounterStore from '../../store/createCounterStore';
7+
8+
const { TestUtils } = React.addons;
9+
10+
function setup(initialState) {
11+
const store = createCounterStore(initialState);
12+
const app = TestUtils.renderIntoDocument(
13+
<Provider store={store}>
14+
{() => <CounterApp />}
15+
</Provider>
16+
);
17+
return {
18+
app: app,
19+
buttons: TestUtils.scryRenderedDOMComponentsWithTag(app, 'button').map(button => {
20+
return button.getDOMNode();
21+
}),
22+
p: TestUtils.findRenderedDOMComponentWithTag(app, 'p').getDOMNode()
23+
};
24+
}
25+
26+
describe('containers', () => {
27+
jsdomReact();
28+
29+
describe('App', () => {
30+
31+
it('should display initial count', () => {
32+
const { p } = setup();
33+
expect(p.textContent).toMatch(/^Clicked: 0 times/);
34+
});
35+
36+
it('should display updated count after increment button click', () => {
37+
const { buttons, p } = setup();
38+
TestUtils.Simulate.click(buttons[0]);
39+
expect(p.textContent).toMatch(/^Clicked: 1 times/);
40+
});
41+
42+
it('should display updated count after descrement button click', () => {
43+
const { buttons, p } = setup();
44+
TestUtils.Simulate.click(buttons[1]);
45+
expect(p.textContent).toMatch(/^Clicked: -1 times/);
46+
});
47+
48+
it('shouldnt change if even and if odd button clicked', () => {
49+
const { buttons, p } = setup();
50+
TestUtils.Simulate.click(buttons[2]);
51+
expect(p.textContent).toMatch(/^Clicked: 0 times/);
52+
});
53+
54+
it('should change if odd and if odd button clicked', () => {
55+
const { buttons, p } = setup({ counter: 1 });
56+
TestUtils.Simulate.click(buttons[2]);
57+
expect(p.textContent).toMatch(/^Clicked: 2 times/);
58+
});
59+
});
60+
});

examples/counter/test/jsdomReact.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import ExecutionEnvironment from 'react/lib/ExecutionEnvironment';
2+
import jsdom from 'mocha-jsdom';
3+
4+
export default function jsdomReact() {
5+
jsdom();
6+
ExecutionEnvironment.canUseDOM = true;
7+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import expect from 'expect';
2+
import counter from '../../reducers/counter';
3+
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../../constants/ActionTypes';
4+
5+
describe('reducers', () => {
6+
describe('counter', () => {
7+
8+
it('should handle initial state', () => {
9+
expect(counter(undefined, {})).toBe(0);
10+
});
11+
12+
it('should handle INCREMENT_COUNTER', () => {
13+
expect(counter(1, { type: INCREMENT_COUNTER })).toBe(2);
14+
});
15+
16+
it('should handle DECREMENT_COUNTER', () => {
17+
expect(counter(1, { type: DECREMENT_COUNTER })).toBe(0);
18+
});
19+
20+
it('should handle unknown action type', () => {
21+
expect(counter(1, { type: 'unknown' })).toBe(1);
22+
});
23+
});
24+
});

examples/todomvc/components/MainSection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ class MainSection extends Component {
7171
<Footer markedCount={markedCount}
7272
unmarkedCount={unmarkedCount}
7373
filter={filter}
74-
onClearMarked={::this.handleClearMarked}
75-
onShow={::this.handleShow} />
74+
onClearMarked={this.handleClearMarked.bind(this)}
75+
onShow={this.handleShow.bind(this)} />
7676
);
7777
}
7878
}

examples/todomvc/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "TodoMVC example for redux",
55
"main": "server.js",
66
"scripts": {
7-
"start": "node server.js"
7+
"start": "node server.js",
8+
"test": "mocha --recursive --compilers js:babel/register"
89
},
910
"repository": {
1011
"type": "git",
@@ -36,6 +37,10 @@
3637
"devDependencies": {
3738
"babel-core": "^5.6.18",
3839
"babel-loader": "^5.1.4",
40+
"expect": "^1.8.0",
41+
"jsdom": "^5.6.1",
42+
"mocha": "^2.2.5",
43+
"mocha-jsdom": "^1.0.0",
3944
"node-libs-browser": "^0.5.2",
4045
"raw-loader": "^0.5.1",
4146
"react-hot-loader": "^1.2.7",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import expect from 'expect';
2+
import * as types from '../../constants/ActionTypes';
3+
import * as actions from '../../actions/TodoActions';
4+
5+
describe('todo actions', () => {
6+
7+
it('addTodo should create ADD_TODO action', () => {
8+
expect(actions.addTodo('Use Redux')).toEqual({
9+
type: types.ADD_TODO,
10+
text: 'Use Redux'
11+
});
12+
});
13+
14+
it('deleteTodo should create DELETE_TODO action', () => {
15+
expect(actions.deleteTodo(1)).toEqual({
16+
type: types.DELETE_TODO,
17+
id: 1
18+
});
19+
});
20+
21+
it('editTodo should create EDIT_TODO action', () => {
22+
expect(actions.editTodo(1, 'Use Redux everywhere')).toEqual({
23+
type: types.EDIT_TODO,
24+
id: 1,
25+
text: 'Use Redux everywhere'
26+
});
27+
});
28+
29+
it('markTodo should create MARK_TODO action', () => {
30+
expect(actions.markTodo(1)).toEqual({
31+
type: types.MARK_TODO,
32+
id: 1
33+
});
34+
});
35+
36+
it('markAll should create MARK_ALL action', () => {
37+
expect(actions.markAll()).toEqual({
38+
type: types.MARK_ALL
39+
});
40+
});
41+
42+
it('clearMarked should create CLEAR_MARKED action', () => {
43+
expect(actions.clearMarked('Use Redux')).toEqual({
44+
type: types.CLEAR_MARKED
45+
});
46+
});
47+
});
48+

0 commit comments

Comments
 (0)