#169: remove unhandled promise rejections in tests. Added loging for that cases

This commit is contained in:
SleepWalker 2016-12-06 23:08:51 +02:00
parent febd148b2e
commit f9ae7053d0
18 changed files with 67 additions and 40 deletions

View File

@ -12,7 +12,7 @@ let promise;
*
* @param {object} store - redux store
*
* @return {Promise} - a promise, that resolves in User state
* @return {Promise<User>} - a promise, that resolves in User state
*/
export function factory(store) {
if (promise) {

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import CompleteState from './CompleteState';
@ -14,7 +16,8 @@ export default class AcceptRulesState extends AbstractState {
resolve(context) {
context.run('acceptRules')
.then(() => context.setState(new CompleteState()));
.then(() => context.setState(new CompleteState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
reject(context) {

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import CompleteState from './CompleteState';
import ResendActivationState from './ResendActivationState';
@ -18,7 +20,8 @@ export default class ActivationState extends AbstractState {
resolve(context, payload) {
context.run('activate', payload)
.then(() => context.setState(new CompleteState()));
.then(() => context.setState(new CompleteState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
reject(context) {

View File

@ -1,5 +1,7 @@
import { routeActions } from 'react-router-redux';
import logger from 'services/logger';
import RegisterState from './RegisterState';
import LoginState from './LoginState';
import OAuthState from './OAuthState';
@ -88,7 +90,7 @@ export default class AuthFlow {
if (this.onReady) {
const callback = this.onReady;
this.onReady = () => {};
return resp.then(callback);
return resp.then(callback, (err) => err || logger.warn(err));
}
return resp;
@ -119,7 +121,7 @@ export default class AuthFlow {
* (state's enter function's promise resolved)
*/
handleRequest(request, replace, callback = function() {}) {
const {path, params = {}, query = {}} = request;
const {path} = request;
this.replace = replace;
this.onReady = callback;
@ -175,7 +177,6 @@ export default class AuthFlow {
break;
default:
console.log('Unsupported request', {path, query, params});
replace('/404');
break;
}

View File

@ -71,8 +71,11 @@ export default class CompleteState extends AbstractState {
if (resp.redirectUri.indexOf('static_page') === 0) {
context.setState(new FinishState());
} else {
context.run('redirect', resp.redirectUri);
return Promise.reject(); // do not allow loader to be hidden and app to be rendered
return new Promise(() => {
// do not resolve promise to make loader visible and
// overcome app rendering
context.run('redirect', resp.redirectUri);
});
}
}, (resp) => {
if (resp.unauthorized) {

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import PasswordState from './PasswordState';
@ -20,6 +22,7 @@ export default class LoginState extends AbstractState {
resolve(context, payload) {
context.run('login', payload)
.then(() => context.setState(new PasswordState()));
.then(() => context.setState(new PasswordState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
}

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import LoginState from './LoginState';
import CompleteState from './CompleteState';
@ -18,7 +20,8 @@ export default class RecoverPasswordState extends AbstractState {
resolve(context, payload) {
context.run('recoverPassword', payload)
.then(() => context.setState(new CompleteState()));
.then(() => context.setState(new CompleteState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
goBack(context) {

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import CompleteState from './CompleteState';
import ActivationState from './ActivationState';
@ -16,7 +18,8 @@ export default class RegisterState extends AbstractState {
resolve(context, payload) {
context.run('register', payload)
.then(() => context.setState(new CompleteState()));
.then(() => context.setState(new CompleteState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
reject(context, payload) {

View File

@ -1,3 +1,5 @@
import logger from 'services/logger';
import AbstractState from './AbstractState';
import CompleteState from './CompleteState';
import ActivationState from './ActivationState';
@ -16,7 +18,8 @@ export default class ResendActivationState extends AbstractState {
resolve(context, payload) {
context.run('resendActivation', payload)
.then(() => context.setState(new ActivationState()));
.then(() => context.setState(new ActivationState()))
.catch((err = {}) => err.errors || logger.warn(err));
}
reject(context) {

View File

@ -126,7 +126,7 @@ describe('components/accounts/actions', () => {
sessionStorage.removeItem(expectedKey);
return authenticate(account)(dispatch).then(() => {
expect(sessionStorage.getItem(expectedKey), 'not to be null')
expect(sessionStorage.getItem(expectedKey), 'not to be null');
sessionStorage.removeItem(expectedKey);
});
});

View File

@ -1,4 +1,5 @@
import expect from 'unexpected';
import sinon from 'sinon';
import { routeActions } from 'react-router-redux';
@ -56,24 +57,15 @@ describe('components/user/actions', () => {
});
});
it('should post to /api/authentication/logout with user jwt', () => {
// TODO: need an integration test with a middleware, because this
// test is not reliable to check, whether logout request will have token inside
request.post.returns(new Promise((resolve) => {
setTimeout(() => {
// we must not overwrite user's token till request starts
expect(dispatch, 'was not called');
resolve();
}, 0);
}));
return callThunk(logout).then(() => {
it('should post to /api/authentication/logout with user jwt', () =>
callThunk(logout).then(() => {
expect(request.post, 'to have a call satisfying', [
'/api/authentication/logout', {}, {}
'/api/authentication/logout', {}, {
token: expect.it('not to be empty')
}
]);
});
});
})
);
testChangedToGuest();
testAccountsReset();

View File

@ -2,14 +2,14 @@ import expect from 'unexpected';
describe('promise.prototype.finally', () => {
it('should be invoked after promise resolved', () =>
expect(new Promise((resolve) => {
expect(new Promise((resolve) =>
Promise.resolve().finally(resolve)
}), 'to be fulfilled')
), 'to be fulfilled')
);
it('should be invoked after promise rejected', () =>
expect(new Promise((resolve) => {
Promise.reject().finally(resolve)
}), 'to be fulfilled')
expect(new Promise((resolve) =>
expect(Promise.reject().finally(resolve), 'to be rejected')
), 'to be fulfilled')
);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import AcceptRulesState from 'services/authFlow/AcceptRulesState';
import CompleteState from 'services/authFlow/CompleteState';
@ -50,7 +52,8 @@ describe('AcceptRulesState', () => {
describe('#resolve', () => {
it('should call acceptRules', () => {
expectRun(mock, 'acceptRules').returns({then() {}});
expectRun(mock, 'acceptRules')
.returns(Promise.resolve());
state.resolve(context);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import ActivationState from 'services/authFlow/ActivationState';
import CompleteState from 'services/authFlow/CompleteState';
import ResendActivationState from 'services/authFlow/ResendActivationState';
@ -73,7 +75,7 @@ describe('ActivationState', () => {
mock,
'activate',
sinon.match.same(payload)
).returns({then() {}});
).returns(Promise.resolve());
state.resolve(context, payload);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import LoginState from 'services/authFlow/LoginState';
import PasswordState from 'services/authFlow/PasswordState';
@ -52,7 +54,7 @@ describe('LoginState', () => {
mock,
'login',
sinon.match.same(payload)
).returns({then() {}});
).returns(Promise.resolve());
state.resolve(context, payload);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import RecoverPasswordState from 'services/authFlow/RecoverPasswordState';
import CompleteState from 'services/authFlow/CompleteState';
import LoginState from 'services/authFlow/LoginState';
@ -67,7 +69,7 @@ describe('RecoverPasswordState', () => {
mock,
'recoverPassword',
sinon.match(expectedPayload)
).returns({then() {}});
).returns(Promise.resolve());
state.resolve(context, expectedPayload);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import RegisterState from 'services/authFlow/RegisterState';
import CompleteState from 'services/authFlow/CompleteState';
import ActivationState from 'services/authFlow/ActivationState';
@ -52,7 +54,7 @@ describe('RegisterState', () => {
mock,
'register',
sinon.match.same(payload)
).returns({then() {}});
).returns(Promise.resolve());
state.resolve(context, payload);
});

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import ResendActivationState from 'services/authFlow/ResendActivationState';
import CompleteState from 'services/authFlow/CompleteState';
import ActivationState from 'services/authFlow/ActivationState';
@ -69,7 +71,7 @@ describe('ResendActivationState', () => {
mock,
'resendActivation',
sinon.match.same(payload)
).returns({then() {}});
).returns(Promise.resolve());
state.resolve(context, payload);
});