redux-testkit
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -1,9 +0,3 @@ | ||
'use strict'; | ||
var _mockStore=require('./mockStore');var _mockStore2=_interopRequireDefault(_mockStore);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} | ||
var _mockStore = require('./mockStore'); | ||
var _mockStore2 = _interopRequireDefault(_mockStore); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
module.exports = { MockStore: _mockStore2.default }; | ||
module.exports={MockStore:_mockStore2.default}; |
@@ -1,85 +0,52 @@ | ||
'use strict'; | ||
Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};}();var _lodash=require('lodash');var _lodash2=_interopRequireDefault(_lodash);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i];}return arr2;}else{return Array.from(arr);}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}var | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
MockStore=function(){ | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
function MockStore(){_classCallCheck(this,MockStore); | ||
this.reset(); | ||
this.mockDispatch=this.mockDispatch.bind(this); | ||
}_createClass(MockStore,[{key:'reset',value:function reset() | ||
var _lodash = require('lodash'); | ||
{ | ||
this.state={}; | ||
this.actions=[]; | ||
}},{key:'setState',value:function setState( | ||
var _lodash2 = _interopRequireDefault(_lodash); | ||
newState){ | ||
this.state=newState; | ||
}},{key:'getState',value:function getState() | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
{ | ||
return this.state; | ||
}},{key:'dispatchSync',value:function dispatchSync( | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
action){ | ||
var done=false; | ||
var result=void 0; | ||
action(this.mockDispatch,this.getState).then(function(r){ | ||
result=r; | ||
done=true; | ||
}); | ||
require('deasync').loopWhile(function(){return!done;}); | ||
//require('deasync').sleep(100); | ||
return result; | ||
}},{key:'dispatch',value:function dispatch( | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
action){ | ||
return action(); | ||
}},{key:'mockDispatch',value:function mockDispatch( | ||
var MockStore = function () { | ||
function MockStore() { | ||
_classCallCheck(this, MockStore); | ||
action){ | ||
if(_lodash2.default.isFunction(action)){ | ||
this.actions=[].concat(_toConsumableArray(this.actions),[action.name]); | ||
}else if(_lodash2.default.has(action,'type')){ | ||
this.actions=[].concat(_toConsumableArray(this.actions),[action]); | ||
}else{ | ||
throw'Unsupported action type sent to dispatch'; | ||
} | ||
return true; | ||
}},{key:'getActions',value:function getActions() | ||
this.reset(); | ||
this.mockDispatch = this.mockDispatch.bind(this); | ||
} | ||
_createClass(MockStore, [{ | ||
key: 'reset', | ||
value: function reset() { | ||
this.state = {}; | ||
this.actions = []; | ||
} | ||
}, { | ||
key: 'setState', | ||
value: function setState(newState) { | ||
this.state = newState; | ||
} | ||
}, { | ||
key: 'getState', | ||
value: function getState() { | ||
return this.state; | ||
} | ||
}, { | ||
key: 'dispatchSync', | ||
value: function dispatchSync(action) { | ||
var done = false; | ||
var result = void 0; | ||
action(this.mockDispatch, this.getState).then(function (r) { | ||
result = r; | ||
done = true; | ||
}); | ||
require('deasync').loopWhile(function () { | ||
return !done; | ||
}); | ||
//require('deasync').sleep(100); | ||
return result; | ||
} | ||
}, { | ||
key: 'dispatch', | ||
value: function dispatch(action) { | ||
return action(); | ||
} | ||
}, { | ||
key: 'mockDispatch', | ||
value: function mockDispatch(action) { | ||
if (_lodash2.default.isFunction(action)) { | ||
this.actions = [].concat(_toConsumableArray(this.actions), [action.name]); | ||
} else if (_lodash2.default.has(action, 'type')) { | ||
this.actions = [].concat(_toConsumableArray(this.actions), [action]); | ||
} else { | ||
throw 'Unsupported action type sent to dispatch'; | ||
} | ||
return true; | ||
} | ||
}, { | ||
key: 'getActions', | ||
value: function getActions() { | ||
return this.actions; | ||
} | ||
}]); | ||
return MockStore; | ||
}(); | ||
exports.default = MockStore; | ||
{ | ||
return this.actions; | ||
}}]);return MockStore;}();exports.default=MockStore; |
{ | ||
"name": "redux-testkit", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "Test kit for redux", | ||
@@ -8,3 +8,3 @@ "main": "lib/index.js", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"compile": "babel --presets es2015,stage-0 -d lib/ src/" | ||
"compile": "babel --presets react-native -d lib/ src/" | ||
}, | ||
@@ -21,6 +21,4 @@ "author": "Yedidya Kennard <yedidyak@gmail.com>", | ||
"devDependencies": { | ||
"babel-cli": "^6.14.0", | ||
"babel-preset-es2015": "^6.14.0", | ||
"babel-preset-stage-0": "^6.5.0" | ||
"babel-preset-react-native": "^1.9.0" | ||
} | ||
} |
# redux-testkit | ||
Testkit for redux | ||
##Testkit for redux thunks | ||
### Installation | ||
Install this module via npm with `npm install redux-testkit --save-dev` | ||
### Description | ||
Use this module to easily write **unit tests** for redux actions, including asynchronous actions using [redux-thunk](https://github.com/gaearon/redux-thunk) middleware. | ||
### Usage | ||
To import the module in your test file, use | ||
`import {MockStore} from 'redux-testkit';` | ||
MockStore provides these methods: | ||
#### reset() | ||
Simply resets the store, usually you would use this in `beforeEach` or equivalent in your test suite, for example | ||
``` | ||
beforeEach(() => { | ||
mockStore.reset(); | ||
}); | ||
``` | ||
#### setState(newState) | ||
This sets the redux store state that will be provided via `getState` to thunks dispatched to the mockStore. Use this to set up a test that depends on an existing state. | ||
**Important note: This object is NOT affected by dispatches, or internal dispatches called in tests. This shouldn't cause any problems because thinks _should not rely on the reducer logic_ but should only 'fire and forget' events to the store** | ||
#### dispatchSync(action) | ||
This is the key method for running your tests. Say your thunk is: | ||
``` | ||
export function actionToTest(parameters) { | ||
return async function(dispatch, getState) { | ||
//Asynchronous logic with lots of awaits here | ||
} | ||
} | ||
``` | ||
then you send this to the mockStore with `mockStore.dispatchSync(actionToTest(paramObjects));`. | ||
The testkit will run this test **synchronously** and then you can run `expect` asertations on the output with: | ||
#### getActions() | ||
This is where you do the work in the tests. To unit test an action, you want to test what effect the action has given a specific starting environment. We set up this environment before the test with `setState()` and by passing parameters. There are three ways a dispatched action can cause effects: | ||
1. By dispatching an object with a `type` field to the store | ||
2. By dispatching another action to the store | ||
3. By calling some external function | ||
In case 3, you test the effect by mocking the external function. Typically you would extract that logic to a separate class and import it into your action's class, and so you mock it by using a tool like `proxyquire` when importing you actions into the test suite. | ||
redux-testkit allows you to *unit test* cases 1 and 2. | ||
`getActions()` returns an `array` of all the dispatches sent by the tested action, in order. In case 1, the entire object is saved and you can `expect` it to have a type and other fields, for example: | ||
``` | ||
expect(mockStore.getActions()[0].type).toEqual(actionTypes.ACTION_TYPE_1); | ||
expect(mockStore.getActions()[0].otherField).toEqual({some object}); | ||
``` | ||
In case 2, the `name` of the dispatched function is saved, and can be tested like this | ||
``` | ||
expect(mockStore.getActions()[1]).toEqual('name_of_function'); | ||
``` | ||
**If this is another thunk, then you must name the internal anonymous async function, like this:** | ||
``` | ||
export function name_of_function() { | ||
return async function name_of_function(dispatch, getState) { | ||
} | ||
} | ||
``` | ||
To test a **synchronous** action that dispacthes other actions or objects, you should inject the `mockDispatch()` and `getState()` from the mockStore. For example: | ||
``` | ||
const result = actions.syncAction(mockStore.mockDispatch, mockStore.getState(), params...); | ||
expect(result).toEqual(123456); | ||
expect(mockStore.getActions()).to.... | ||
``` | ||
## TODO | ||
[ ] Improve syntax with Matchers - Please open issues to suggest the syntax you'd want! |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28685
1
94
92