reduxjs / redux-mock-store Goto Github PK
View Code? Open in Web Editor NEWA mock store for testing Redux async action creators and middleware.
License: MIT License
A mock store for testing Redux async action creators and middleware.
License: MIT License
Hi, I am trying to run this library with tape
but having some trouble. Here is my gist: https://gist.github.com/marr/a3195dadb924a977a00a
I receive the following error when running the test: โ test exited without ending
We use redux thunk and are therefore sending functions as actions sometimes. (https://github.com/gaearon/redux-thunk). We use your mock (thanks!) but would like it to also accept functions apart from object with type attribute. Would you like such a pull request?
I tryed to test a little unit that handle dispatches after promise returned in a sync way, but for some reason, I am always get an empty actions array from store.getActions(). Can someone help me?
btw, the action is:
export function firstRefresh(instrumentId)
{
return dispatch =>
{
Router.refresh(instrumentId, 0)
.then((data) =>
{
try
{
dispatch(setAssetsByMarkets(data.assetsByMarketsObj));
dispatch(setAssetsAndOptionsFirstTime(data));
dispatch(setMarkets(data.markets));
}
catch (error)
{
console.error('an error catched: ', error);
}
}).catch( () =>
{
dispatch(setAssetsAndOptions({assets : [], options : []}));
});
};
}
and the test is:
describe('async actions', () => {
it('firstRefresh success', () => {
const instrumentId = ...,
serverUrl =...,
serverPostPath = ...,
timeStamp = new Date().getTime(),
replayStatusCode = 200,
mockReplayBody = {...
},
requestHeaders = {
reqheaders: {...}
},
requestBody = {...
},
store = mockStore(storeInitialState)
nock(serverUrl, requestHeaders)
.post(serverPostPath)
.reply(replayStatusCode, {body: mockReplayBody})
const expectedActions = [
{
type: 'SET_ASSETS_BY_MARKETS',
value: mockReplayBody.assetsByMarketsObj
}, {
type: 'SET_ASSETS_AND_OPTIONS_FIRST_TIME',
data: mockReplayBody
}, {
type: 'UPDATE_MARKETS',
value: mockReplayBody.markets
}
]
store.dispatch(actions.firstRefresh(instrumentId))
expect(store.getActions()).toEqual(expectedActions)
})
})
If I set up a test that should fail because the dispatched actions do not meet the expectations, the test is in-fact passing which can be quite dangerous.
This is using redux-mock-store 0.0.6 and Jest 0.8.2.
I believe the problem lies here:
} catch (e) {
if (done) {
done(e);
}
throw e;
}
I was able to cause the test to fail as expected by simply not calling done, e.g:
} catch (e) {
if (done) {
//done(e);
}
throw e;
}
I'm not 100% sure if this is an issue with this library or one with Jest, therefore I have not put together a PR yet until the matter has been discussed.
I have an action creator which which updates a user, and then dispatches another action to display a notification. The notification displays for a few seconds and then disappears. To make this happen a private id is assigned to the action by the notification action creator.
In my test, I'd like to ensure that both the user update action and the notification action are triggered successfully.
In expectedActions I can add a notification action with the correct action type, with the message in the payload, but I can't provide the private notification id. Because the action I provided doesn't match exactly (the provided action has no id), the test fails.
Ideally I'd like an option to make the equality test less strict, one that ensures that the all the properties of the object in expectedActions are present and equal in the actual action, and that any additional properties in the actual action are ignored.
So for the purpose of my test, I'd like the following to be considered equal:
Object in expectedActions:
{ type: types.NOTIFICATION, message: 'user updated' }
Actual action:
{ type: types.NOTIFICATION, id: 616, message: 'user updated' ...any other properties }
I can understand if this goes against the spirit of the project, in which case I'd certainly appreciate any suggestions on how to handle my situation.
Thanks.
This commit added:
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
);
}
This will throw if you are using arrays that redux-multi will handle e.g:
[
{ type: 'action1',
payload: { id: '1234' }
},
{ type: 'action2',
payload: { id: '5678' }
}
]
I created this Stackoverflow questions a few days ago, but I didn't get an answer. I tried since but I didn't find a solution to the problem.
The problem basically occurs when I dispatch actions in catch statements. They neither show up in store.getActions()
nor is the state altert. I described it in relative detail in the question so I won't repeat it here. Feel free to request more info though.
I'm still not sure if it's a bug or if I'm just doing it wrong.
Is it an idea to add a fake subscribe method so that you can use the store to test react-redux connectors? It doesn't even have to do anything by itself, you might be allowed to pass in your own spy or fake method.
Hi,
I created simple chai bindings to test redux-store, should I open a MR to add a link to the README?
Thanks for your great work by the way :)
Hello,
I have an action like this
export function getItems() {
return {
type: GET_ITEMS,
payload: {
promise: axios.get(`${domain}:${port}/api/items`)
}
};
}
and my testing code
import promiseMiddleware from 'redux-promise-middleware';
import nock from 'nock';
import configureStore from 'redux-mock-store';
import { domain, port } from '../../config/environment';
import { GET_ITEMS_START,
GET_ITEMS_SUCCESS } from '../../constants/items';
import { getItems } from './items';
const promise = promiseMiddleware({
promiseTypeSuffixes: ['START', 'SUCCESS', 'ERROR']
});
const mockStore = configureStore([promise]);
describe('Items Action Creator', () => {
describe('Get Items', () => {
it('should create GET_ITEMS_SUCCESS action after successfully getting items', (done) => {
nock(`${domain}:${port}`)
.get('/api/items')
.reply(200, {
_id: '1',
text: 'Make Eggs',
completed: false
});
const expectedActions = [
{ type: GET_ITEMS_START },
{ type: GET_ITEMS_SUCCESS, payload: {
data: { _id: '1', text: 'Make Eggs', completed: false }
}}
];
const store = mockStore({}, expectedActions, done);
store.dispatch(getItems());
});
});
This is the result that was being returned
1) Items Action Creator Get Items should create GET_ITEMS_SUCCESS action after successfully getting items:
Error: Expected { payload: { config: { headers: {}, method: 'get', timeout: 0, transformRequest: [ [Function] ], transformResponse: [ [Function] ], url: 'http://localhost:3000/api/items', withCredentials: undefined }, data: { _id: '1', completed: false, text: 'Make Eggs' }, headers: {}, status: 200, statusText: 'OK' }, type: 'GET_ITEMS_SUCCESS' } to equal { payload: { data: { _id: '1', completed: false, text: 'Make Eggs' } }, type: 'GET_ITEMS_SUCCESS' }
+ expected - actual
{
"payload": {
- "config": {
- "headers": {}
- "method": "get"
- "timeout": 0
- "transformRequest": [
- [Function]
- ]
- "transformResponse": [
- [Function]
- ]
- "url": "http://localhost:3000/api/items"
- "withCredentials": [undefined]
- }
"data": {
"_id": "1"
"completed": false
"text": "Make Eggs"
}
- "headers": {}
- "status": 200
- "statusText": "OK"
}
"type": "GET_ITEMS_SUCCESS"
}
How do I just make sure that only the "data" property that is being compared instead of the whole payload object
I'm confused about how we update the store dynamically. I presume this doesn't actually call reducers seen as it's just a mock.
See http://stackoverflow.com/questions/41642041/redux-how-to-update-the-store-in-unit-tests for more details.
I have also tried using enzyme's setContext({ store: //newStore here }); but it doesn't update the store correctly.
I am testing actions in redux, but there is asyn behavior in the middleware. So, I don't to want to monitor the action when I invoke dispatch(), whate I really want is to monitor the incoming actions in the reducer. is there any way to make it (method replaceReducer seems doesn't work well)? Thanks a lot!
I found the monitor method dispatch() is ok for my question, but i can only get the first action, and can't catch the second ation. setTimeout() don't work well.
My issue is related to:
#59
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
I followed the steps to resolve the same errors experienced by that issue, but the following test still produces an error for me:
import createSagaMiddleware from 'redux-saga'
import configureStore from 'redux-mock-store'
import {applyMiddleware} from 'redux'
const testingRoot = "http://localhost:9090";
describe('async actions', () => {
afterEach(() => {
nock.cleanAll()
});
it('triggers RESPONSE_FILTER_CHANGE_WITH_OPERATORS_SUCCESS when fetchTransmissions completes successfully', () => {
const sagaMiddleware = createSagaMiddleware();
const mockStore = configureStore([applyMiddleware(sagaMiddleware)]);
// sagaMiddleware.run(WaterlevelSagas);
nock.disableNetConnect();
const mockedResponse = WaterlevelMockData;
nock(testingRoot)
.get(Config.waterlevelCatalog.url.stagedConfig.waterlevelCatalog.url.staged)
.reply(200, mockedResponse);
// const fullState = Immutable.fromJS({transmission: {}, operator: {}});
const expectedActions = [
{type: FilterActions.REQUEST_FILTER_CHANGE_BY_CATEGORY},
{type: FilterActions.RESPONSE_FILTER_CHANGE_WITH_OPERATORS_SUCCESS}
];
const store = mockStore({});
return store.dispatch(FilterActions.requestFilterChangeByCategory(FilterConstants.category.staged))
.then(() => {
store.getActions().should.deep.equal(expectedActions)
});
})
});
The following line:
const store = mockStore({});
produces the following error in my test:
1) async actions triggers RESPONSE_FILTER_CHANGE_WITH_OPERATORS_SUCCESS when fetchTransmissions completes successfully:
TypeError: createStore is not a function
at node_modules/redux/lib/applyMiddleware.js:38:19
at node_modules/redux/lib/applyMiddleware.js:51:63
at mockStore (node_modules/redux-mock-store/lib/index.js:79:12)
at Context.<anonymous> (src/app/WaterlevelSagas-spec.js:54:23)
Any idea on where "createStore" comes into play here and how to resolve this? I haven't used "createStore" anywhere in my test.
In my regular application I have:
import createLogger from 'redux-logger';
const logger = createLogger();
const enhancer = compose(
applyMiddleware(thunk, logger),
persistState(
window.location.href.match(
/[?&]debug_session=([^&#]+)\b/
)
)
);
export default function configureStore(initialState) {
const store = createStore(rootReducer, initialState, enhancer);
if (module.hot) {
module.hot.accept('../reducer', () => {
store.replaceReducer(require('../reducer').default);
});
}
return store;
But within my tests I have
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
But in my terinal window and withink Karma's Chrome Browser I am getting redux-logger details printed out. LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{auth: Object{accessToken: null, userId: null, isAuthenticated: false, isAuthenticating: false, statusText: null}, form: Object{}, header: Object{showAside: false}, routing: Object{locationBeforeTransitions: null}, user: Object{isFetching: false, errors: []}}
I'm not adding redux-logger to my configureMockStore, only my real store which I am not using for my tests. Is there any way to get rid of redux-logger for tests?
I have 2 test cases and the second one will not pass and throw
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
Here is my code snippet:
it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', (done) => {
const expectedActions = [
{type: TodoConstants.GET_TODOS_REQUEST},
{type: TodoConstants.GET_TODOS_SUCCESS, todos: [
{
id: 1, text: 'todo1', isDone: false
},
{
id: 2, text: 'todo2', isDone: true
}
]}
];
const store = mockStore({todos: []}, expectedActions, done);
store.dispatch(actions.fetchTodos());
});
it('post ADD_TODO_SUCCESS when add todo has been done', (done) => {
const expectedActions = [
{type: TodoConstants.ADD_TODO_REQUEST, text: 'todo3'},
{type: TodoConstants.ADD_TODO_SUCCESS, todo: {
id: 3, text: 'todo3', isDone: false
}}
];
const store = mockStore({todos: []}, expectedActions, done);
store.dispatch(actions.addTodo('todo3'));
});
I duplicated the 'get' test case, only the first 'get' test case can pass.
then I removed the duplicate test case and put the 'post' test case in front of the 'get' test case, neither test case can pass.
My temporary solution is calling the done() function explicitly for each test case.
A lot of recent PRs introduce changes to the TypeScript definition and it causes problems to users. It would be wiser to defer the support to https://github.com/DefinitelyTyped/DefinitelyTyped and make the package more stable.
Let me know what you think.
I have downloaded redux-mock-store and it include a definition, when you attempt to use it provides the following error:
Exported external package typings file 'C:/Test/node_modules/redux-mock-store/index.d.ts' is not a module. Please contact the package author to update the package definition
We have implemented a manual typing for redux-mock-store, that worked fine for us:
/// <reference path="../../typings/globals/redux/index.d.ts"/>
declare module "redux-mock-store" {
interface MockStore extends Redux.Store {
getState(): any;
getActions(): Array<any>;
dispatch(action: any): any;
clearActions(): void;
subscribe(): any;
}
function configureStore(...args: any[]) : (...args: any[]) => MockStore;
export = configureStore;
}
This index.d.ts is providing conflicts (even excluding node_modules folders), in our case we are manually deleting that file whenever we install the package.Could it be a good idea to remove the d.ts from redux-mock-store, review it and an updated on to the typings repository?
The mock store accepts either undefined
or a function as the done
parameter. It also checks for done
before calling it in the try
case. However it doesn't check in the catch
case. So if you don't supply a function and you have an error, you will get a done is not a function error
.
Very helpful library, by the way.
I have no idea why this action is array is becoming empty, especially when I log it inside the dispatch action it seems to push it in just fine. Somewhere inside the dispatch of the action it is getting cleared. If anybody has any ideas that would be a great help.
Here is the unit test:
let response: any = [{ 'displayOrder': -1, 'formTypeId': 3717, 'id': 829, 'name': 'a', 'parentId': 3717 }];
let prefix: string ='TestString'
it('should call RECEIVE_DATA when fetching has been done', () => {
nock(someURL)
.get('someURL')
.reply(200, response);
let collection: Array<any> = response;
const expectedActions = [
{
type: prefix + '_RECEIVE_DATA',
data: Immutable.List<IChildEntity>(collection),
}
]
const store = mockStore({ MetadataField: [] });
let id: number = 3717;
return store.dispatch(IChildEntityActions.initializeData(prefix, id))
.then(
() => { // return of async actions
Chai.expect(store.getActions()).to.deep.equal(expectedActions);
})
})
})
I am trying to write a test using redux-saga and redux-mock-store:
Below is my test:
import { describe, before, after, it } from 'mocha';
import { assert, expect } from 'chai';
import configureMockStore from 'redux-mock-store';
import { applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import fetch from 'isomorphic-fetch';
import fetchMock from 'fetch-mock';
import reducer from '../app/reducers';
import * as actions from '../app/actions/winratio-actions';
import rootSaga from '../app/sagas';
const sagaMiddleware = createSagaMiddleware();
const mockStore = configureMockStore(
reducer,
compose(
applyMiddleware(sagaMiddleware)
));
describe('fetch results', () => {
after(() => {
fetchMock.restore();
});
it("should call failure action", () => {
fetchMock.mock('http://localhost:4040/api/results', 501);
const store = mockStore({});
store.runSaga = sagaMiddleware.run;
store.runSaga(rootSaga);
store.dispatch(actions.loadResultsPage());
//expect(store).to.not.be.null;
});
});
But I get the following error message:
fetch results should call failure action: TypeError: middleware is not a function at node_modules/redux/lib/applyMiddleware.js:49:16 at Array.map (native) at node_modules/redux/lib/applyMiddleware.js:48:27 at mockStore (node_modules/redux-mock-store/lib/index.js:70:12) at Context.<anonymous> (results-test.js:36:19)
The only examples I can find online use redux-thunk:
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
How do I configure the mock store to use redux-saga?
If I am testing a function that is supposed to dispatch certain actions, and I somehow forgot to dispatch any actions, redux-mock-store won't even bother checking the expected actions defined in mockStore
.
Hi,
I'm wondering if it's possible to test nested promises:
eg. response.json() - it's a promise which can be invoked after fetch promise,
however if I create "then" method for "store.dispatch" the nested promise won't get executed, is it possible to wait until it's executed?
Regards
Would it be helpful to add store.subscribe method?
I'm just getting started learning how to test react, so I'm not sure what it'd look like. I may be understanding this as intended to use for a completely different purpose than I'm trying to test.
I'm trying to do this:
// I have a shallowRender helper util
const component = shallowRender(
<Provider store={store}>
<ConnectedCounterContainer />
</Provider>
)
so I can simply test to see if the component received the prop count: 0
but I get:
Warning: Failed Context Types: Required child context `store.subscribe` was not specified in `Provider`.
so I'm assuming it wants a store.subscribe()
method on the mocked store.
Limiting the version number to just the minor number is kinda awkward.
Is there a way to test that there are no actions? My function may have a condition before dispatching the action.
it('dispatches no actions', (done) => {
const store = mockStore({}, [], done);
store.dispatch(
(dispatch) => {}
);
});
This test fails with:
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
TestUtils.Simulate.click(btnNext)
console.log(store.dispatch.callCount) //0
TestUtils.Simulate.click(btnNext)
console.log(store.dispatch.callCount) //0
console.log(store.getActions()) //[ { type: 'CHANGE_BLOCK_LAYOUT',
//blockId: '2c7dbb58-2025-4b9f-b8ad-c206ed5f15a0',
//layout: 1 },
// { type: 'CHANGE_BLOCK_LAYOUT',
// blockId: '2c7dbb58-2025-4b9f-b8ad-c206ed5f15a0',
//layout: 1 } ]
Just realized,
In this PR we merged the wrong version of the d.ts definitions:
The right version was the one commented by @asgarddesigns but by mistake we merged the one in the PR.
import {Store} from 'redux';
interface MockStore extends Store {
getState():any;
getActions():Array<any>;
dispatch(action:any):any;
clearActions():void;
subscribe():any;
}
declare function configureStore(...args:any[]):(...args:any[]) => MockStore;
export = configureStore;
I have created a new PR containing the right version:
https://github.com/arnaudbenard/redux-mock-store/pull/51/files
For some reasons, when a test fails, it seems to be run twice (or at least it sends twice done(e)
).
Moreover, the error is very hard to read. Would it be possible to improve the error?
I have noticed that there are multiple bugs related to how testing frameworks handle errors. I have built this library for mocha but it looks like we need to make it work with Jasmine and tape. I would love to get a conversation started on how we can make the library support multiple frameworks.
Do you have examples of framework agnostic testing libraries?
Or
Should we make forks for every testing framework?
Action creators:
export function sendVerCode(mobile) {
return dispatch => {
dispatch(requestSendCode(mobile))
return fetch('/api/signup-send-code',
{
method: 'post',
body: `mobile=${mobile}`
}
).then(response => response.json())
.then(json => {
if(json.success) {
dispatch(sendCodeSucceed(json))
} else {
dispatch(sendCodeFailed(json))
}
})
.catch((err) => dispatch(sendCodeFailed('send verfiy code failed',err)) )
}
}
function requestSendCode(mobile) {
return {
type: REQUEST_SEND_CODE,
mobile:mobile,
requestedAt:Date.now()
}
}
function sendCodeSucceed(json) {
return {
type: SEND_CODE_SUCCEED,
result: json,
receivedAt: Date.now()
}
}
function sendCodeFailed(message,err) {
return {
type: SEND_CODE_FAILED,
message: message,
err:err,
receivedAt: Date.now()
}
}
Tests:
it.only('creates SEND_CODE_SUCCEED when sendVerCode has been done', () => {
fetchMock.mock({
routes: {
name: 'route',
matcher: '/api/signup-send-code',
method: 'POST',
response: { success: true }
}
})
var expectedActions = [
{ type: REQUEST_SEND_CODE, mobile:'13911088888',requestedAt:Date.now()},
{ type: SEND_CODE_FAILED, result:{ success: true } } //Here should be SEND_CODE_SUCCEED
]
var store = mockStore(Map({}), expectedActions)
store.dispatch(sendVerCode('13911088888'))
})
Second action should be SEND_CODE_SUCCEED,But the test passed!It seems the second expected action was ignored.
we are using redux-mock-store in a react native project and we are running into this issue:
we are not using babel-preset-es2015
in our project, but we must install it in order to make this error go away.
Possible cause: I have looked at the package.json
file for this package and noticed all the dependencies are listed as devDependencies -- as far as I know , devDependencies for third party modules do not get installed. Additionally, the error message suggests babel is looking for files relative to node_modules/redux-mock-store first. A possible fix would be to list babel-preset-es2015 as a regular dependency instead of a devDependency.
i have test with nock.js
i don't want to use setTimeout
is there anything else?
The following test case doesn't work (and it should IMO). I was able to test code like this in v0.6, but can't in the new v1.0.2
it('should work with redux-thunk', (done) => {
function success() {
return {
type: 'FETCH_DATA_SUCCESS'
};
}
function asyncAction() {
return dispatch => {
setTimeout(() => {
dispatch(success());
}, 10);
};
}
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const store = mockStore({});
store.dispatch(asyncAction()).then(() => {
expect(store.getActions()[0]).toEqual(success())
done();
});
})
Thanks for this great library BTW!
We've an action creator that looks something like this:
export function changeFilter(from, to) {
return (dispatch, getState) => {
// Updates the state with the new values and sets a loading flag
dispatch(changeFilterRequest(from, to));
// Now I want to use those newly-set values to build a query string
// However, the stubbed implementation of `dispatch` doesn't use reducers,
// so `getState` returns the original value!
const { activeUsers } = getState();
return doSomeWebRequest(activeUsersParams(activeUsers))
.then(response => dispatch(changeFilterSuccess(response)))
};
}
Like many asynchronous action creators, we split it up into two actions, one to signal the start of an action and another to signal the end. However, our web request in the middle relies on the values set by the first dispatch.
The implementation of dispatch
is pretty sparse, and in (obvious) hindsight, we never pass the reducers to the mocked store!
Are there any existing patterns for performing these types of tests?
Thanks for a great library; keep up the good work!
Hi,
I'm getting some errors when transpiling the project, just checked the repository and found that you have removed the d.ts file and recommend using the typings one:
But if I just go via npm install I can see that the .d.ts is still on the local files installed, Is there a new version pending to be published on npm?
Thanks
I'm using Jest to do unit test based on Jasmine 2
When I was testing my async action store having Parse query
It throws this error :
''Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVL."
Here is my code from _tests/actions/auth-test.js
it('should creates SIGNUP_REQUEST and SIGNUP_SUCCESS when signup has been done successfully', (done) => {
/* If this account has already exists in Parse database, it will get SIGNUP_ERROR */
const expectedActions = [
{ type: 'SIGNUP_REQUEST', payload: { username, password } },
{ type: 'SIGNUP_SUCCESS', payload: { user: { /* whatever. Anyway, it needs to be defined */ } } },
];
const store = mockStore({}, expectedActions, done);
store.dispatch(Auth.signup(username, password));
})
Finally, I revised some code from yours and tested successfully.
It seems that the main problem is Jasmine done()
doesn't be invoked, so it causes this error.
Here is my revised code :
function configureMockStore(middlewares = []) {
return function mockStore(getState, expectedActions, done) {
if (!Array.isArray(expectedActions)) {
throw new Error('expectedActions should be an array of expected actions.');
}
if (typeof done !== 'undefined' && typeof done !== 'function') {
throw new Error('done should either be undefined or function.');
}
function mockStoreWithoutMiddleware() {
return {
getState() {
return typeof getState === 'function' ? getState() : getState;
},
dispatch(action) {
const expectedAction = expectedActions.shift();
/* Customize for auth action test */
switch(action.type) {
case 'SIGNUP_REQUEST':
case 'LOGIN_REQUEST':
expect(action).toEqual(expectedAction);
break;
case 'SIGNUP_SUCCESS':
case 'LOGIN_SUCCESS':
expect(action.type).toEqual(expectedAction.type);
expect(action.payload.user).toBeDefined();
break;
case 'SIGNUP_ERROR':
case 'LOGIN_ERROR':
expect(action.type).toEqual(expectedAction.type);
expect(action.payload.error).toBeDefined();
break;
}
if (done && !expectedActions.length) {
done();
}
return action;
}
}
}
const mockStoreWithMiddleware = applyMiddleware(
...middlewares
)(mockStoreWithoutMiddleware);
return mockStoreWithMiddleware();
}
}
Hello! I have an issue with failing tests on Mocha.
Given an array of expected actions, if the last one fails Mocha return me the correct wrong expectation, but if another actions fails (before the last), the callback is called multiple times and Mocha return me thi exception: Error: done() called multiple times
. So I don't know which action failed!
The problem is that the mocked store when catching an exception, pass it as argument to the callback and doesn't throw it, so it keeps running and when it reach the last action, calls the callback again.
I don't know if that's a problem only with Mocha though, in that case maybe it should be configurable to make it work with every testing library.
Here's a simple test to replicate the behaviour:
it('handles multiple actions', done => {
const store = mockStore({}, [{ type: 'ADD_ITEM' }, { type: 'REMOVE_ITEM' }], done);
store.dispatch({ type: 'ADD_ITEMS' });
store.dispatch({ type: 'REMOVE_ITEM' });
});
Firstly this library is proving to be very useful when testing my app, so many thanks!
One thing I have found is that if there is a mismatch with the expected actions in my test and the actual code then it can be tricky to find exactly where the problem is - typically the mocha test just times out because the done callback hasn't been triggered.
Is there a way to log the difference between expected and actual actions called?
I'm a novice so this may be a trivial question.
I'm currently trying to test my actions for signing up a user. For some reason my post request fails by timing out, when my endpoints seem to be fine.
// the test
it('creates SIGNUP_USER_SUCCESS when user completes signup', (done) => {
var signupUser = require('../actions/auth/signup').signupUser;
nock('http://api.dockerhost')
.post('/signup', {
first_name: 'Robin',
last_name: 'Kim',
username: '[email protected]',
password: 'password'
})
.reply(200, {
body: {
user: {
username: '[email protected]'
}
}
})
const expectedActions = [
{ type: constants.SIGNUP_USER_REQUEST },
{ type: constants.SIGNUP_USER_SUCCESS }
];
const store = mockStore({ user: {}}, expectedActions, done);
store.dispatch(signupUser('Robin Kim', '[email protected]', 'password'));
})
// the action
const signupUser = (name, username, password) => {
const first_name = name.split(' ').slice(0, -1).join(' ');
const last_name = name.split(' ').slice(-1).join(' ');
const url = `http://api.dockerhost/signup`;
const data = { first_name, last_name, username, password }
return (dispatch) => {
dispatch(signupUserRequest());
return request
.post(url)
.type('form')
.send(data)
.end()
.then((response) => {
console.log('the response', response)
dispatch(signupUserSuccess());
return dispatch(loginUser(username, password, '/downloads'));
})
.catch((error) => {
console.log('error', error) // this is where I get the error
return dispatch(signupUserFailure({
response: {
statusText: error.response.body.errors.username.message,
field: error.response.body.errors.username.path
}
}))
})
}
}
// the error response
`{ [Error: Nock: No match for request POST http://api.dockerhost/signup first_name=Robin&last_name=Kim&username=rokim8%40gmail.com&password=password] status: 404, statusCode: 404, response: undefined }`
// the test log
`Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.`
It seems like it simply cannot hit my /signup endpoint, but I'm unsure as to why.
Hello,
For some reason the state within my mocked store is not being updated after an action has been dispatched. I've pasted my unit test below. Any suggestion on how to proceed would be greatly appreciated.
describe('Landing Page Action Creators', () => {
let store = mockStore({app: {kbbToken: 'MTI2MDk2NjUy'}, ymmt: YMMT_INITIAL_STATE});
beforeEach(() => {
// Redux Mock store - clear actions before each test to assert the new actions being dispatched
store.clearActions();
});
describe('Years', () => {
// getYears()
it('getYears() -> Should return an array of years dating back to 1992', (done) => {
const expectedActions = [
{type: 'GET_YEARS_PENDING'},
{type: 'GET_YEARS_FULFILLED', payload: LandingMockedResponses.getYears}
];
return store.dispatch(LandingActions.fetchYears())
.then(() => { // return of async actions
done();
expect(store.getActions()).to.eql(expectedActions)
})
});
// ***END getYears()
// setYear(2016)
it('setYear(year) -> Set selected year (ymmt)', (done) => {
let expectedActions = [
{type: 'SET_YEAR', payload: 2016},
{ type: 'GET_MAKES_PENDING' }
];
store.dispatch(LandingActions.setYear(2016));
done();
expect(store.getActions()).to.eql(expectedActions);
});
// ***END setYear(2016)
});
describe('Makes', () => {
// getMakes()
it('getMakes() -> Should return an array of makes based on the year passed in', (done) => {
store.clearActions();
console.log(store.getState().ymmt);
let expectedActions = [
{type: 'GET_MAKES_PENDING'},
{type: 'GET_MAKES_FULFILLED', payload: LandingMockedResponses.getMakes}
];
return store.dispatch(LandingActions.fetchMakes(2016))
.then(() => { // return of async actions
done();
expect(store.getActions()).to.eql(expectedActions)
})
});
// ***END getMakes()
});
});
I have the following set-up
actions.js
export function loadData() {
return function (dispatch) {
dispatch(transactions([876]));
};
}
actions-test.js
jest.dontMock('../actions');
jest.dontMock('redux-mock-store');
jest.dontMock('redux-thunk');
const configureMockStore = require('redux-mock-store');
const thunk = require('redux-thunk');
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
describe('actions', () => {
it('should load data', (done) => {
const expectedActions = [
{ type: actions.TRANSACTIONS, transactions : [876] },
//{ type: actions.DOES_NOT_EXIST, foo : [] },
//{ type: actions.EXISTS, foo : [] }
];
const store = mockStore({}, expectedActions, done);
store.dispatch(actions.loadData());
});
});
Running the above test passes as expected.
The problem is if I uncomment
//{ type: actions.DOES_NOT_EXIST, foo : [] },
//{ type: actions.EXISTS, foo : [] }
the test still passes even though now only one of the 3 expectedActions
is dispatched.
Is this a bug, or am I misunderstanding something?
Since upgrading to 1.1.0 or above (previously on 1.0.4), using redux-thunk, dispatching a thunk fails with "Actions may not have an undefined "type" property. Have you misspelled a constant?" (this was introduced in 2f7fa44).
For example, my action creator returns a thunk:
export function fetchSomething(smthg) {
return dispatch => {
return API.someCall(smthg).then(things => {
dispatch(plainActionCreator(things));
return things;
});
};
}
As well, I've configured the mock store to use redux-thunk
.
My tests simply dispatch this action using a mock store:
describe('Blah', () => {
it('should work', () => {
return store.dispatch(fetchSomething('code'));
});
});
I'm having the same issue as #45. Maybe I'm not understanding this correctly, but does mock-store actually run the actions through the reducers anywhere? I'm not seeing how they're ever connected with a setup like this:
import configureStore from 'redux-mock-store'
import thunk from 'redux-thunk'
const mockStore = configureStore([thunk])
const store = mockStore({ ...state })
console.log(store.getState()) // => { ...state }
store.dispatch(someAction())
console.log(store.getActions()) // => [ someAction() ] The action does show up here!
console.log(store.getState()) // => { ...state } But this is the same unchanged state as above
Here's my test:
it('should save entry', () => {
const expectedActions = [
{type: ENTRY_SAVE_REQUEST},
{type: ENTRY_SAVE_SUCCESS},
{type: SYNC_STARTED},
];
// const store = mockStore({}, expectedActions)
// return store.dispatch(actions.saveEntry())
const store = mockStore({})
store.dispatch(actions.saveEntry())
let retActions = store.getActions()
expect(retActions).toEqual(expectedActions) // exception thrown here
})
Also tried the old syntax (commented out) but it passes every time, no matter if expected actions are correct or not.
Packages I'm using:
The full error:
- Cannot read property 'toObject' of undefined }) ] to equal [ Object({ type: 'ENTRY_SAVE_REQUEST' }), Object({ type: 'ENTRY_SAVE_SUCCESS' }), Object({ type: 'SYNC_STARTED' }) ].
at jasmine.buildExpectationResult (node_modules/jest-jasmine2/src/index.js:80:44)
at Object.eval (src/reducers/entry/__tests__/entryActions-test.js:86:20)
at Object.<anonymous> (node_modules/jest-jasmine2/src/jasmine-pit.js:35:32)
at Object.<anonymous> (node_modules/jest-jasmine2/src/jasmine-pit.js:40:11)
at Object.<anonymous> (node_modules/jest-jasmine2/src/jasmine-pit.js:40:11)
at Object.<anonymous> (node_modules/jest-jasmine2/src/jasmine-pit.js:40:11)
at jasmine2 (node_modules/jest-jasmine2/src/index.js:253:7)
at Test.run (node_modules/jest-cli/src/Test.js:44:12)
at handle (node_modules/worker-farm/lib/child/index.js:41:8)
at process.<anonymous> (node_modules/worker-farm/lib/child/index.js:47:3)
at emitTwo (events.js:87:13)
at process.emit (events.js:172:7)
at handleMessage (internal/child_process.js:686:10)
at Pipe.channel.onread (internal/child_process.js:440:11)
Hey there ! I'm getting an issue with the library (i'm using Jest). Here is the code :
import * as actions from '../actions'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
describe('Dataset actions', () => {
it('compareMutuallyExclusiveKeys - default parameters', () => {
const expectedActions = [{
type: actions.COMPARE_MUTUALLY_EXCLUSIVE_KEYS,
payload: {
mutually_exclusive_keys: [],
meta: {}
}
}]
const store = mockStore({})
return store.dispatch(actions.compareMutuallyExclusiveKeys())
.then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
})
})
And the error :
TypeError: mockStore is not a function
Tried to upgrade redux-thunk (2.0.1) and redux-mock-store (1.1.4), but still getting the error...
Thanks for your help !
My mocha tests are passing, but I am getting this new error about how 'dispatch' is not a function.
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
const mockStore = configureMockStore([thunk]);
it('should attempt to login', (done) => {
const userInfo = {email: 'Fizz', password: 'Buzz'};
const userActions = require('../../../src/actions/userActions');
const store = mockStore({});
const dispatch = store.dispatch;
const login = userActions.login;
store.subscribe(() => {
expect(store.getActions()[0].type).to.equal('LOG_IN');
expect(store.getActions()[0].data.email).to.equal('Fizz');
expect(store.getActions()[0].data.password).to.equal('Buzz');
done();
});
dispatch(userActions.asyncLogin(userInfo)(dispatch(login(userInfo))));
});
describe('fetchArticleList action', () => {
it('Get articles should sucess with correctly api', () => {
const store = mockStore({})
function fetchArticleListSuccess(json) {
return {
type: 'FETCH_ARTICLE_LIST_SUCCESS',
ArticleList: json
}
}
return store.dispatch(fetchArticleList(ARTICLES_API))
.then(() => {
//the json have a lot of strings
expect(store.getActions()[1]).toEqual(fetchArticleListSuccess())
console.log(store.getState()) // => {}
})
})
})
so I wonder 'const store = mockStore({})' or 'const mockStore = configureStore(meddlewares)'
could applying my reducers in the mock Store
but I don't how to write the code
The mock store is currently missing this method which is often used for code splitting.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.