Skip to content

Commit 9e91fa9

Browse files
committed
Add tests for assertions
1 parent 4b38196 commit 9e91fa9

File tree

12 files changed

+384
-123
lines changed

12 files changed

+384
-123
lines changed

README.md

Lines changed: 45 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
# redux-actions-assertions [![Build Status](https://travis-ci.org/dmitry-zaets/redux-actions-assertions.svg?branch=master)](https://travis-ci.org/dmitry-zaets/redux-actions-assertions)
2-
1+
# redux-actions-assertions
32
Assertions for redux actions testing
43

54
This library add assertions for [redux actions](http://redux.js.org/docs/advanced/AsyncActions.html) testing.
65
It use [redux-mock-store](https://github.com/arnaudbenard/redux-mock-store) to mock redux store.
76

8-
7+
[![build status](https://img.shields.io/travis/dmitry-zaets/redux-actions-assertions/master.svg?style=flat-square)](https://travis-ci.org/dmitry-zaets/redux-actions-assertions)
8+
[![npm version](https://img.shields.io/npm/v/redux-actions-assertions.svg?style=flat-square)](https://www.npmjs.com/package/redux-actions-assertions)
99

1010
## Supported Assertion Frameworks/Libraries:
11-
- [expect](#expect)
1211
- [chai](#chai)
12+
- [expect](#expect)
1313
- [expect.js](#expectjs)
1414
- [should](#should)
15-
- [jasmine and jest](#jasmine-and-jest) [In Progress]
1615

17-
If you have not found assertion framework/library that you are using - you still can use [pure assertion function](#javascript).
16+
If you have not found assertion framework/library that you are using - you can use [pure javascript assertion](#javascript) or create an issue.
1817

1918
## Installation
2019

@@ -103,45 +102,6 @@ Same as `toDispatchActions` + asserts that store initialised with `state` before
103102
toDispatchActions({property: 'value'}, testActionCreator(), [{type: 'MY_ACTION_START'}], callback);
104103
```
105104

106-
## [expect](https://github.com/mjackson/expect)
107-
108-
### Registration
109-
110-
```js
111-
// using ES6 modules
112-
import { registerAssertions } from 'redux-actions-assertions/expect';
113-
114-
// using CommonJS modules
115-
var registerAssertions = require('redux-actions-assertions/expect').registerAssertions;
116-
117-
// registration
118-
registerAssertions();
119-
```
120-
### Usage
121-
122-
#### .toDispatchActions
123-
124-
> `expect(action).toDispatchActions(expectedActions, callback)`
125-
126-
Asserts that when given `action` is dispatched it will dispatch `expectedActions`. `action` can be plain object (action) or function (action creator). `expectedActions` can be can be plain object (action) or function (action creator) or array of objects/functions.
127-
128-
```js
129-
expect(myActionCreator())
130-
.toDispatchActions({type: 'MY_ACTION_START'}, callback);
131-
```
132-
133-
#### .withState
134-
135-
> `expect(action).withState(state).toDispatchActions(expectedActions, callback)`
136-
137-
Asserts that store initialised with `state` before `action` is dispatched.
138-
139-
```js
140-
expect(myActionCreator())
141-
.withState({property: 'value'})
142-
.toDispatchActions([{type: 'MY_ACTION_START'}, finishActionCreator()], callback);
143-
```
144-
145105
## [chai](https://github.com/chaijs/chai)
146106

147107
### Registration
@@ -207,6 +167,45 @@ assert.isDispatchingWithState(
207167
);
208168
```
209169

170+
## [expect](https://github.com/mjackson/expect)
171+
172+
### Registration
173+
174+
```js
175+
// using ES6 modules
176+
import { registerAssertions } from 'redux-actions-assertions/expect';
177+
178+
// using CommonJS modules
179+
var registerAssertions = require('redux-actions-assertions/expect').registerAssertions;
180+
181+
// registration
182+
registerAssertions();
183+
```
184+
### Usage
185+
186+
#### .toDispatchActions
187+
188+
> `expect(action).toDispatchActions(expectedActions, callback)`
189+
190+
Asserts that when given `action` is dispatched it will dispatch `expectedActions`. `action` can be plain object (action) or function (action creator). `expectedActions` can be can be plain object (action) or function (action creator) or array of objects/functions.
191+
192+
```js
193+
expect(myActionCreator())
194+
.toDispatchActions({type: 'MY_ACTION_START'}, callback);
195+
```
196+
197+
#### .withState
198+
199+
> `expect(action).withState(state).toDispatchActions(expectedActions, callback)`
200+
201+
Asserts that store initialised with `state` before `action` is dispatched.
202+
203+
```js
204+
expect(myActionCreator())
205+
.withState({property: 'value'})
206+
.toDispatchActions([{type: 'MY_ACTION_START'}, finishActionCreator()], callback);
207+
```
208+
210209
## [expect.js](https://github.com/Automattic/expect.js)
211210

212211
### Registration
@@ -305,18 +304,4 @@ myActionCreator().should
305304
myActionCreator().should
306305
.with.state({property: 'value'})
307306
.dispatchActions({type: 'MY_ACTION_START'}, callback);
308-
```
309-
## [jasmine](https://github.com/jasmine/jasmine) and [jest](https://github.com/facebook/jest)
310-
311-
### Registration
312-
313-
```js
314-
// using ES6 modules
315-
import { registerAssertions } from 'redux-actions-assertions/jasmine';
316-
317-
// using CommonJS modules
318-
var registerAssertions = require('redux-actions-assertions/jasmine').registerAssertions;
319-
320-
// registration
321-
registerAssertions();
322-
```
307+
```

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "lib/index.js",
66
"scripts": {
77
"lint": "eslint src test",
8-
"test:general": "mocha --compilers js:babel-register --reporter spec test/*.js",
8+
"test:general": "mocha --compilers js:babel-register --reporter spec test/general/*.js test/assertions/*.js",
99
"test:chai": "mocha --compilers js:babel-register --reporter spec test/chai/*.js",
1010
"test:expect": "mocha --compilers js:babel-register --reporter spec test/expect/*.js",
1111
"test:expectjs": "mocha --compilers js:babel-register --reporter spec test/expect.js/*.js",
@@ -36,7 +36,6 @@
3636
"eslint-plugin-babel": "^3.1.0",
3737
"expect": "^1.16.0",
3838
"expect.js": "^0.3.1",
39-
"jasmine": "^2.4.1",
4039
"mocha": "^2.4.5",
4140
"redux-thunk": "^2.0.1",
4241
"rimraf": "^2.5.2",

src/assertions/actionUtils.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import find from 'lodash.find';
2+
import flattenDeep from 'lodash.flattendeep';
3+
import { toArray } from '../utils';
4+
import getMockStore from '../mockStore';
5+
6+
function getDispatchedActions(initialState, action) {
7+
return new Promise((resolve, reject) => {
8+
const store = getMockStore()(initialState);
9+
const dispatchResult = store.dispatch(action);
10+
11+
if (dispatchResult instanceof Promise) {
12+
dispatchResult.then(() => {
13+
resolve(store.getActions());
14+
}).catch((result) => {
15+
reject(result);
16+
});
17+
} else {
18+
resolve(store.getActions());
19+
}
20+
});
21+
}
22+
23+
function unrollActions(initialState, expectedActions) {
24+
const promises = [];
25+
const actions = toArray(expectedActions);
26+
27+
for (let index = 0; index < actions.length; index++) {
28+
promises.push(getDispatchedActions(initialState, actions[index]));
29+
}
30+
31+
return Promise.all(promises).then((resultActions) => {
32+
return flattenDeep(resultActions);
33+
});
34+
}
35+
36+
function assertDispatchedActions(dispatched, expected) {
37+
for (let index = 0; index < expected.length; index++) {
38+
if (!find(dispatched, expected[index])) {
39+
throw new Error(
40+
`Expected action ${JSON.stringify(expected[index])} was not dispatched.\n` +
41+
`Actual dispatched actions: ${JSON.stringify(dispatched)}`
42+
);
43+
}
44+
}
45+
}
46+
47+
export {
48+
getDispatchedActions,
49+
unrollActions,
50+
assertDispatchedActions
51+
};

src/assertions/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import toDispatchActions from './toDispatchActions';
2-
import toDispatchActionsWithState from './toDispatchActionsWithState';
1+
import { toDispatchActions } from './toDispatchActions';
2+
import { toDispatchActionsWithState } from './toDispatchActionsWithState';
33

44
export default { toDispatchActions, toDispatchActionsWithState };

src/assertions/toDispatchActions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import getInitialStoreState from '../initialState';
2-
import toDispatchActionsWithState from './toDispatchActionsWithState';
2+
import { toDispatchActionsWithState } from './toDispatchActionsWithState';
33

44
function toDispatchActions(actionUnderTest, expectedActions, done, fail) {
55
return toDispatchActionsWithState(
@@ -10,4 +10,4 @@ function toDispatchActions(actionUnderTest, expectedActions, done, fail) {
1010
);
1111
}
1212

13-
export default toDispatchActions;
13+
export { toDispatchActions };
Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,5 @@
1-
import flattenDeep from 'lodash.flattendeep';
2-
import find from 'lodash.find';
3-
import { isFunction, isObject, toArray } from '../utils';
4-
import getMockStore from '../mockStore';
5-
6-
function getDispatchedActions(initialState, action) {
7-
return new Promise((resolve, reject) => {
8-
const store = getMockStore()(initialState);
9-
const dispatchResult = store.dispatch(action);
10-
11-
if (dispatchResult instanceof Promise) {
12-
dispatchResult.then(() => {
13-
resolve(store.getActions());
14-
}).catch((result) => {
15-
reject(result);
16-
});
17-
} else {
18-
resolve(store.getActions());
19-
}
20-
});
21-
}
22-
23-
function unrollActions(initialState, expectedActions) {
24-
const promises = [];
25-
const actions = toArray(expectedActions);
26-
27-
for (let index = 0; index < actions.length; index++) {
28-
promises.push(getDispatchedActions(initialState, actions[index]));
29-
}
30-
31-
return Promise.all(promises).then((resultActions) => {
32-
return flattenDeep(resultActions);
33-
});
34-
}
1+
import { isFunction, isObject } from '../utils';
2+
import { getDispatchedActions, unrollActions, assertDispatchedActions } from './actionUtils';
353

364
function toDispatchActionsWithState(initialState, actionUnderTest, expectedActions, done, fail) {
375
if (!isFunction(actionUnderTest) && !isObject(actionUnderTest)) {
@@ -40,7 +8,9 @@ function toDispatchActionsWithState(initialState, actionUnderTest, expectedActio
408
);
419
}
4210

43-
if (!isFunction(expectedActions) && !isObject(expectedActions)) {
11+
if (!isFunction(expectedActions) &&
12+
!isObject(expectedActions) &&
13+
!Array.isArray(expectedActions)) {
4414
throw new Error(
4515
'The "expectedActions" argument must be ' +
4616
'an action creator function or an action object or an array of them'
@@ -49,28 +19,24 @@ function toDispatchActionsWithState(initialState, actionUnderTest, expectedActio
4919

5020
return getDispatchedActions(initialState, actionUnderTest).then((dispatchedActions) => {
5121
return unrollActions(initialState, expectedActions).then((expectedUnrolledActions) => {
52-
for (let index = 0; index < expectedUnrolledActions.length; index++) {
53-
if (!find(dispatchedActions, expectedUnrolledActions[index])) {
54-
throw new Error(
55-
`Expected action ${JSON.stringify(expectedUnrolledActions[index])} was not dispatched.`
56-
+ `\nActual dispatched actions: ${JSON.stringify(dispatchedActions)}`
57-
);
58-
}
59-
}
22+
assertDispatchedActions(dispatchedActions, expectedUnrolledActions);
23+
6024
if (isFunction(done)) {
6125
done();
6226
}
63-
}).catch((err) => {
64-
if (isFunction(fail)) {
65-
fail(err);
66-
return;
67-
} else if (isFunction(done)) {
68-
done(err);
69-
return;
70-
}
71-
throw new Error(err);
7227
});
28+
}).catch((err) => {
29+
if (isFunction(fail)) {
30+
fail(err);
31+
return;
32+
} else if (isFunction(done)) {
33+
done(err);
34+
return;
35+
}
36+
throw new Error(JSON.stringify(err));
7337
});
7438
}
7539

76-
export default toDispatchActionsWithState;
40+
export {
41+
toDispatchActionsWithState
42+
};

src/jasmine/index.js

Whitespace-only changes.

test/assertions/actionUtils.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import expect from 'expect';
2+
import {
3+
getDispatchedActions,
4+
unrollActions,
5+
assertDispatchedActions
6+
} from '../../src/assertions/actionUtils';
7+
8+
describe('assertions', () => {
9+
describe('action utils', () => {
10+
describe('getDispatchedActions', () => {
11+
it('should be function', () => { expect(getDispatchedActions).toBeA('function');});
12+
13+
it('should return a Promise', () => {
14+
const result = getDispatchedActions({}, { type: '' });
15+
expect(result).toBeA(Promise);
16+
});
17+
});
18+
19+
describe('unrollActions', () => {
20+
function asyncActionCreator() {
21+
return dispatch => {
22+
dispatch({ type: '0-0' });
23+
dispatch({ type: '0-1' });
24+
return Promise.resolve().then(() => {
25+
dispatch({ type: '1-0' });
26+
dispatch({ type: '1-1' });
27+
return Promise.resolve().then(() => {
28+
dispatch({ type: '2-0' });
29+
dispatch({ type: '2-1' });
30+
});
31+
});
32+
};
33+
}
34+
35+
it('should be function', () => { expect(unrollActions).toBeA('function');});
36+
37+
it('should return flat array with all actions', () => {
38+
unrollActions({}, asyncActionCreator()).then((result) => {
39+
const expectedActions = [
40+
{ type: '0-0' },
41+
{ type: '0-1' },
42+
{ type: '1-0' },
43+
{ type: '1-1' },
44+
{ type: '2-0' },
45+
{ type: '2-1' }
46+
];
47+
expect(result).toBe(expectedActions);
48+
});
49+
});
50+
});
51+
52+
describe('assertDispatchedActions', () => {
53+
it('should be function', () => { expect(assertDispatchedActions).toBeA('function');});
54+
55+
it('should throw error if expected action was not dispatched', () => {
56+
const dispatchedActions = [
57+
{ type: '0-0' },
58+
{ type: '0-1' }
59+
];
60+
const expectedActions = [
61+
{ type: '0-0' },
62+
{ type: '10-0' }
63+
];
64+
65+
expect(assertDispatchedActions)
66+
.withArgs([dispatchedActions, expectedActions])
67+
.toThrow();
68+
});
69+
});
70+
});
71+
});

0 commit comments

Comments
 (0)