Open kopax opened 7 years ago
What I typically do is to create an object that has all my API calls in it and pass that in as an injected dep. Then you can easily pass in a mocked call when testing and can make it succeed or throw errors as you want.
So your code would look something like this:
// in your configure store
const api = {
performLogin
};
const logicMiddleware = createLogicMiddleware(logic, { api }); // inject api as a dependency
export const getAuthorizeLogic = createLogic({
type: SUBMIT_LOGIN_REQUEST, // trigger on this action
cancelType: LOCATION_CHANGE, // cancel if route changes
latest: true, // use response for the latest request when multiple
async process({ api, authService, forwardTo, pages, action }, dispatch, done) {
const { username, password } = action.data;
try {
const jwt = await api.performLogin(authService, username, password);
dispatch(onSuccessLoginRequest());
dispatch(jwtLoaded(jwt));
forwardTo(pages.pageDashboard.path); // Go to dashboard page
} catch (err) {
dispatch(onErrorLoginRequest(err));
forwardTo(pages.pageLogin.path); // Go to dashboard page
}
done();
},
});
That way when we are testing, you can inject whatever you want for api.performLogin, even changing it for each test, just set the injectedDeps in your createMockStore. So you can test any type of success or failure scenario.
That way when we are testing, you can inject whatever you want
I have tried an apparently my code is failing right after I try to read from injectedDeps.
Or
I'd like to take a particular attention for that line
I was never using done
before and never felt that it was required for my test.
I've try to add it on a test logic and I have that kind of error with the done
:
dka@dev-01:[/workspace/wip/myappurl/backoffice-logic]: jest /workspace/wip/myappurl/backoffice-logic/app/containers/App/logics/tests/getLogoutLogic.test.js
(node:14883) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: expect(jest.fn()).toHaveBeenCalledWith(expected)
Expected mock function to have been called with:
["/"]
But it was not called.
(node:14883) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
FAIL app/containers/App/logics/tests/getLogoutLogic.test.js (6.322s)
● getLogoutLogic › getLogoutLogic › should make logout request and dispatch
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:480:19)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
getLogoutLogic
getLogoutLogic
✕ should make logout request and dispatch (5004ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 7.041s
Ran all test suites matching "/workspace/wip/myappurl/backoffice-logic/app/containers/App/logics/tests/getLogoutLogic.test.js".
while I only have warning without it :
dka@dev-01:[/workspace/wip/myappurl/backoffice-logic]: jest /workspace/wip/myappurl/backoffice-logic/app/containers/App/logics/tests/getLogoutLogic.test.js
PASS app/containers/App/logics/tests/getLogoutLogic.test.js
getLogoutLogic
getLogoutLogic
✓ should make logout request and dispatch (4ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.135s, estimated 7s
Ran all test suites matching "/workspace/wip/myappurl/backoffice-logic/app/containers/App/logics/tests/getLogoutLogic.test.js".
(node:15007) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: expect(jest.fn()).toHaveBeenCalledWith(expected)
Expected mock function to have been called with:
["/"]
But it was not called.
(node:15007) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
This is what my async services for the most look like:
const managers = {
getAll() {
const options = {
method: 'GET',
};
return api('http://myserver:31735/v1/managers', options)
.then((response) => Promise.resolve(response));
},
};
export default managers;
actions
?done()
? Any update on this?
@kopax sorry for the delay, I'll try to follow up on Monday.
Regarding your question about needing to use done in your tests, if you have an async test (meaning that you have to wait for somethings to happen like when using API's with promises) then you either need to return the promise to the test or add a done cb and call that. I recommend returning the promise as the better of the two ways to handle things since it will give you a better error message when things fail. I should probably update my example to show that as well, it would look like this:
it('should fetch answer and dispatch', () => {
store.dispatch({ type: 'FOO' }); // start fetching
return store.whenComplete(() => { // all logic has completed, return promise
expect(store.actions).toEqual([
{ type: 'FOO' },
{ type: 'FOO_SUCCESS', payload: 42 }
]);
});
});
Let me know if you still have any issues after you update your code to return the promise. It looks like it is rejecting so I imagine once you change this it will be more clear what the reject error actually is.
Hi @jeffbski, thanks again for your answer.
I have tried to return store.whenComplete(...)
but it didn't change the result
I don't understand why it fails silently. I have my test that pass, but apparently the tools that inject dependency doesn't work for me.
I have tried to added a console.log
in my mock of fn:follow
fn:api
, it never get called. Is it working for you ?
Note that when you return the promise for a test you should not use the done
cb, you need to do one or the other, not both. So you should remove that from the signature of your it
test
it('should fetch answer and dispatch', () => { // do not include done cb
store.dispatch({ type: 'FOO' }); // start fetching
return store.whenComplete(() => { // all logic has completed, return promise
expect(store.actions).toEqual([
{ type: 'FOO' },
{ type: 'FOO_SUCCESS', payload: 42 }
]);
});
});
Hopefully this should help it start reporting the errors.
If not maybe post everything to a gist or a repo where I can take a deeper look.
I have tried and unfortunately, it didn't change.
I have just created a demo project so you can test yourself.
git clone git@github.com:kopax/redux-logic-example.git
cd redux-logic-example
npm install
npm test
google-chrome coverage/lcov-report/index.html # only if you have google-chrome installed
excellent. I'll spin it up on Monday and see if I can figure out what is causing the issue.
I installed from your repo and took a look at your coverage.
Basically the coverage is low for your logic.js since you didn't dispatch any actions that would cause that logic to run.
So in your logic.js, the logic action types it is listening for are LOAD_FROM_SERVER and ON_NAVIGATE.
In your logic.test.js, you are only dispatching ON_LIST_SUCCESS so neither of these logic would run for that action type and thus coverage is low.
Also note that you should probably just always reset (by recreating the store using createMockStore) the store for every iteration using beforeEach rather than beforeAll. You generally want clean state for each test, so that's what I would suggest. So change your beforeAll to beforeEach and then add some additional tests where you dispatch LOAD_FROM_SERVER and ON_NAVIGATE to have the tests exercise your logic.
Hi @jeffbski, I finally got time to try this lib, sorry for taking so long!
I want to test the
onErrorLoginRequest
in atry catch
block.I have the following logic:
Test:
Work fine so far.