From a2202da41a47f906fea1b7b818e70df023346d84 Mon Sep 17 00:00:00 2001 From: Maximilian Mantz Date: Wed, 12 Jul 2017 10:03:15 +0200 Subject: [PATCH] pre-publish v3.0.0-beta.8 --- README.md | 7 +--- dist/redux-oidc.js | 2 +- package.json | 9 ++--- src/actions/index.js | 9 ++++- src/constants/index.js | 1 + src/helpers/loadUser.js | 49 +++++++++++++++++------ src/oidcMiddleware.js | 47 +++++++++++++++++----- tests/actions/index.test.js | 30 +++++++++++++- tests/helpers/loadUser.test.js | 46 +++++++++++++++------ tests/oidcMiddleware.test.js | 73 ++++++++++++++++++++++------------ 10 files changed, 197 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 4f8cc2a..c4fa2e5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# redux-oidc +# redux-oidc [![Build Status](https://travis-ci.org/maxmantz/redux-oidc.svg?branch=master)](https://travis-ci.org/maxmantz/redux-oidc) -A package for managing OpenID-Connect authentication in ReactJS / Redux apps. +A package for managing OpenID-Connect authentication in ReactJS / Redux apps. It wraps the popular oidc-client library to redux actions and reducers. ### Installation `npm install --save redux-oidc` @@ -12,9 +12,6 @@ In order to install this run: `npm install --save oidc-client` -There is also a dependency on [co](https://www.npmjs.com/package/co). - -`npm install --save co` In addition there is a peer dependency for [immutable.js](https://facebook.github.io/immutable-js/), if you want to use it. diff --git a/dist/redux-oidc.js b/dist/redux-oidc.js index 509de76..00aa8d1 100644 --- a/dist/redux-oidc.js +++ b/dist/redux-oidc.js @@ -1 +1 @@ -!function(e,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r(require("co"),require("prop-types"),require("react"),require("immutable"),require("oidc-client"));else if("function"==typeof define&&define.amd)define(["co","prop-types","react","immutable","oidc-client"],r);else{var t="object"==typeof exports?r(require("co"),require("prop-types"),require("react"),require("immutable"),require("oidc-client")):r(e.co,e["prop-types"],e.react,e.immutable,e["oidc-client"]);for(var n in t)("object"==typeof exports?exports:e)[n]=t[n]}}(this,function(e,r,t,n,o){return function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={};return r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="",r(r.s=16)}([function(e,r,t){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.USER_EXPIRED="redux-oidc/USER_EXPIRED",r.REDIRECT_SUCCESS="redux-oidc/REDIRECT_SUCCESS",r.USER_LOADED="redux-oidc/USER_LOADED",r.SILENT_RENEW_ERROR="redux-oidc/SILENT_RENEW_ERROR",r.SESSION_TERMINATED="redux-oidc/SESSION_TERMINATED",r.USER_EXPIRING="redux-oidc/USER_EXPIRING",r.USER_FOUND="redux-oidc/USER_FOUND",r.LOADING_USER="redux-oidc/LOADING_USER",r.USER_SIGNED_OUT="redux-oidc/USER_SIGNED_OUT"},function(e,r,t){"use strict";function n(){return{type:l.USER_EXPIRED}}function o(e){return{type:l.REDIRECT_SUCCESS,payload:e}}function u(e){return{type:l.USER_FOUND,payload:e}}function s(e){return{type:l.SILENT_RENEW_ERROR,payload:e}}function i(){return{type:l.SESSION_TERMINATED}}function a(){return{type:l.USER_EXPIRING}}function c(){return{type:l.LOADING_USER}}function d(){return{type:l.USER_SIGNED_OUT}}Object.defineProperty(r,"__esModule",{value:!0}),r.userExpired=n,r.redirectSuccess=o,r.userFound=u,r.silentRenewError=s,r.sessionTerminated=i,r.userExpiring=a,r.loadingUser=c,r.userSignedOut=d;var l=t(0)},function(e,r,t){"use strict";function n(e){return new o.UserManager(e)}Object.defineProperty(r,"__esModule",{value:!0}),r.default=n;var o=t(15)},function(e,r){e.exports=require("co")},function(e,r){e.exports=require("prop-types")},function(e,r){e.exports=require("react")},function(e,r,t){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(r,"__esModule",{value:!0}),r.userSignedOut=r.loadingUser=r.userExpiring=r.sessionTerminated=r.silentRenewError=r.userFound=r.redirectSuccess=r.userExpired=r.USER_SIGNED_OUT=r.LOADING_USER=r.USER_EXPIRING=r.SESSION_TERMINATED=r.SILENT_RENEW_ERROR=r.USER_NOT_FOUND=r.USER_FOUND=r.REDIRECT_SUCCESS=r.USER_EXPIRED=r.OidcProvider=r.reducer=r.immutableReducer=r.CallbackComponent=r.loadUser=r.processSilentRenew=r.createUserManager=void 0;var o=t(11),u=n(o);r.createUserManager=t(2).default,r.processSilentRenew=t(10).default,r.loadUser=t(9).default,r.CallbackComponent=t(7).default,r.immutableReducer=t(12).default,r.reducer=t(13).default,r.OidcProvider=t(8).default,r.USER_EXPIRED=t(0).USER_EXPIRED,r.REDIRECT_SUCCESS=t(0).REDIRECT_SUCCESS,r.USER_FOUND=t(0).USER_FOUND,r.USER_NOT_FOUND=t(0).USER_NOT_FOUND,r.SILENT_RENEW_ERROR=t(0).SILENT_RENEW_ERROR,r.SESSION_TERMINATED=t(0).SESSION_TERMINATED,r.USER_EXPIRING=t(0).USER_EXPIRING,r.LOADING_USER=t(0).LOADING_USER,r.USER_SIGNED_OUT=t(0).USER_SIGNED_OUT,r.userExpired=t(1).userExpired,r.redirectSuccess=t(1).redirectSuccess,r.userFound=t(1).userFound,r.silentRenewError=t(1).silentRenewError,r.sessionTerminated=t(1).sessionTerminated,r.userExpiring=t(1).userExpiring,r.loadingUser=t(1).loadingUser,r.userSignedOut=t(1).userSignedOut,r.default=u.default},function(e,r,t){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function o(e,r){if(!(e instanceof r))throw new TypeError("Cannot call a class as a function")}function u(e,r){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!r||"object"!=typeof r&&"function"!=typeof r?e:r}function s(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Super expression must either be null or a function, not "+typeof r);e.prototype=Object.create(r&&r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),r&&(Object.setPrototypeOf?Object.setPrototypeOf(e,r):e.__proto__=r)}Object.defineProperty(r,"__esModule",{value:!0});var i=function(){function e(e,r){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:r,o=arguments[1];switch(o.type){case n.USER_EXPIRED:return e({user:null,isLoadingUser:!1});case n.SILENT_RENEW_ERROR:return e({user:null,isLoadingUser:!1});case n.SESSION_TERMINATED:case n.USER_SIGNED_OUT:return e({user:null,isLoadingUser:!1});case n.REDIRECT_SUCCESS:case n.USER_FOUND:return e({user:o.payload,isLoadingUser:!1});case n.LOADING_USER:return t.set("isLoadingUser",!0);default:return t}}}()}catch(e){o=function(){console.error("You must install immutable-js for the immutable reducer to work!")}}r.default=o},function(e,r,t){"use strict";function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:s,r=arguments[1];switch(r.type){case u.USER_EXPIRED:return Object.assign({},o({},e),{user:null,isLoadingUser:!1});case u.SILENT_RENEW_ERROR:return Object.assign({},o({},e),{user:null,isLoadingUser:!1});case u.SESSION_TERMINATED:case u.USER_SIGNED_OUT:return Object.assign({},o({},e),{user:null,isLoadingUser:!1});case u.REDIRECT_SUCCESS:case u.USER_FOUND:return Object.assign({},o({},e),{user:r.payload,isLoadingUser:!1});case u.LOADING_USER:return Object.assign({},o({},e),{isLoadingUser:!0});default:return e}}Object.defineProperty(r,"__esModule",{value:!0});var o=Object.assign||function(e){for(var r=1;r0&&void 0!==arguments[0]?arguments[0]:u,r=arguments[1];switch(r.type){case n.USER_EXPIRED:case n.SILENT_RENEW_ERROR:return i({user:null,isLoadingUser:!1});case n.SESSION_TERMINATED:case n.USER_SIGNED_OUT:return i({user:null,isLoadingUser:!1});case n.REDIRECT_SUCCESS:case n.USER_FOUND:return i({user:r.payload,isLoadingUser:!1});case n.LOADING_USER:return e.set("isLoadingUser",!0);default:return e}}}catch(e){o=function(){console.error("You must install immutable-js for the immutable reducer to work!")}}r.default=o},function(e,r,t){"use strict";function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:u,r=arguments[1];switch(r.type){case i.USER_EXPIRED:case i.SILENT_RENEW_ERROR:return Object.assign({},o({},e),{user:null,isLoadingUser:!1});case i.SESSION_TERMINATED:case i.USER_SIGNED_OUT:return Object.assign({},o({},e),{user:null,isLoadingUser:!1});case i.REDIRECT_SUCCESS:case i.USER_FOUND:return Object.assign({},o({},e),{user:r.payload,isLoadingUser:!1});case i.LOADING_USER:return Object.assign({},o({},e),{isLoadingUser:!0});default:return e}}Object.defineProperty(r,"__esModule",{value:!0});var o=Object.assign||function(e){for(var r=1;r=4.6.0", - "react": ">=0.14.0", - "oidc-client": ">=1.2.0", - "prop-types": ">=15.5.0" + "react": ">=0.15.0", + "oidc-client": ">=1.3.0", + "prop-types": ">=15.5.0" }, "optionalDependencies": { "immutable": ">=3.6.0" diff --git a/src/actions/index.js b/src/actions/index.js index b1ab5a1..473936f 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -6,7 +6,8 @@ import { USER_EXPIRING, SESSION_TERMINATED, LOADING_USER, - USER_SIGNED_OUT + USER_SIGNED_OUT, + LOAD_USER_ERROR } from '../constants' // dispatched when the existing user expired @@ -67,3 +68,9 @@ export function userSignedOut() { type: USER_SIGNED_OUT }; } + +export function loadUserError() { + return { + type: LOAD_USER_ERROR + }; +} diff --git a/src/constants/index.js b/src/constants/index.js index d9478cd..aca1502 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -7,3 +7,4 @@ export const USER_EXPIRING = 'redux-oidc/USER_EXPIRING'; export const USER_FOUND = 'redux-oidc/USER_FOUND'; export const LOADING_USER = 'redux-oidc/LOADING_USER'; export const USER_SIGNED_OUT = 'redux-oidc/USER_SIGNED_OUT'; +export const LOAD_USER_ERROR = 'redux-oidc/LOAD_USER_ERROR'; diff --git a/src/helpers/loadUser.js b/src/helpers/loadUser.js index 3b46f84..e12e857 100644 --- a/src/helpers/loadUser.js +++ b/src/helpers/loadUser.js @@ -1,7 +1,36 @@ -import co from 'co'; -import { userFound, userExpired } from '../actions'; +import { userFound, userExpired, loadUserError } from '../actions'; -export function* loadUserHandler(store, userManager) { +// stores the redux store here to be accessed by all functions +let reduxStore; + +// helper function to set the redux store (for testing) +export function setReduxStore(newStore) { + reduxStore = newStore; +} + +// helper function to get the redux store (for testing) +export function getReduxStore() { + return reduxStore; +} + +// callback function called when the user has been loaded +export function getUserCallback(user) { + if (user && !user.expired) { + reduxStore.dispatch(userFound(user)); + } else if (user && user.expired) { + reduxStore.dispatch(userExpired()); + } +} + +// error callback called when the userManager's loadUser() function failed +export function errorCallback(error) { + console.error(`redux-oidc: Error in loadUser() function: ${error.message}`); + reduxStore.dispatch(loadUserError()); +} + +// function to load the current user into the store +// NOTE: use only when silent renew is configured +export default function loadUser(store, userManager) { if (!store || !store.dispatch) { throw new Error('redux-oidc: You need to pass the redux store into the loadUser helper!'); } @@ -10,15 +39,9 @@ export function* loadUserHandler(store, userManager) { throw new Error('redux-oidc: You need to pass the userManager into the loadUser helper!'); } - const user = yield userManager.getUser(); - - if (user && !user.expired) { - store.dispatch(userFound(user)); - } else { - store.dispatch(userExpired()); - } -} + reduxStore = store; -export default function loadUser(store, userManager) { - co(loadUserHandler(store, userManager)); + userManager.getUser() + .then(getUserCallback) + .catch(errorCallback); } diff --git a/src/oidcMiddleware.js b/src/oidcMiddleware.js index 46b25e6..4cc9bc7 100644 --- a/src/oidcMiddleware.js +++ b/src/oidcMiddleware.js @@ -1,9 +1,20 @@ -import { userExpired, userFound, loadingUser } from './actions'; +import { userExpired, userFound, loadingUser, loadUserError } from './actions'; import { USER_EXPIRED, LOADING_USER } from './constants'; -import co from 'co'; // store the user here to prevent future promise calls to getUser() export let storedUser = null; +// store the next middleware here so it can be accessed by the getUserCallback +export let nextMiddleware = null; + +// helper function to set the stored next middleware (for testing) +export function setNext(newNext) { + nextMiddleware = newNext; +} + +// a function to get the next middleware (for testing) +export function getNext() { + return nextMiddleware; +} // helper function to set the stored user manually (for testing) export function setStoredUser(user) { @@ -15,22 +26,36 @@ export function removeStoredUser() { storedUser = null; } +// callback function to the userManager's getUser +export function getUserCallback(user) { + if (!user || user.expired) { + nextMiddleware(userExpired()); + } else { + storedUser = user; + nextMiddleware(userFound(user)); + } +} + +// callback for the userManager's getUser.catch +export function errorCallback(error) { + console.error(`redux-oidc: Error loading user in oidcMiddleware: ${error.message}`); + nextMiddleware(loadUserError()); +} + // the middleware handler function -export function* middlewareHandler(next, action, userManager) { +export function middlewareHandler(next, action, userManager) { // prevent an infinite loop of dispatches of these action types (issue #30) if (action.type === USER_EXPIRED || action.type === LOADING_USER) { return next(action); } + nextMiddleware = next; + if (!storedUser || storedUser.expired) { next(loadingUser()); - let user = yield userManager.getUser(); - if (!user || user.expired) { - next(userExpired()); - } else { - storedUser = user; - next(userFound(user)); - } + userManager.getUser() + .then(getUserCallback) + .catch(errorCallback); } return next(action); } @@ -43,6 +68,6 @@ export default function createOidcMiddleware(userManager) { // the middleware return (store) => (next) => (action) => { - co(middlewareHandler(next, action, userManager)); + middlewareHandler(next, action, userManager); } }; diff --git a/tests/actions/index.test.js b/tests/actions/index.test.js index c338f30..24355e2 100644 --- a/tests/actions/index.test.js +++ b/tests/actions/index.test.js @@ -1,8 +1,27 @@ import '../setup'; import expect from 'expect'; import sinon from 'sinon'; -import { USER_EXPIRED, REDIRECT_SUCCESS, USER_FOUND, SILENT_RENEW_ERROR, USER_EXPIRING, SESSION_TERMINATED, LOADING_USER, USER_SIGNED_OUT } from '../../src/constants'; -import { userExpired, userFound, silentRenewError, sessionTerminated, userExpiring, redirectSuccess, loadingUser, userSignedOut } from '../../src/actions'; +import { + USER_EXPIRED, + REDIRECT_SUCCESS, + USER_FOUND, + SILENT_RENEW_ERROR, + USER_EXPIRING, + SESSION_TERMINATED, + LOADING_USER, USER_SIGNED_OUT, + LOAD_USER_ERROR +} from '../../src/constants'; +import { + userExpired, + userFound, + silentRenewError, + sessionTerminated, + userExpiring, + redirectSuccess, + loadingUser, + userSignedOut, + loadUserError +} from '../../src/actions'; describe('action - userExpired', () => { it('should return the correct action object', () => { @@ -68,3 +87,10 @@ describe('action - userSignedOut', () => { expect(action.type).toEqual(USER_SIGNED_OUT); }); }); + +describe('action - loadUserError', () => { + it('should return the correct action object', () => { + const action = loadUserError(); + expect(action.type).toEqual(LOAD_USER_ERROR); + }) +}) diff --git a/tests/helpers/loadUser.test.js b/tests/helpers/loadUser.test.js index e9f1346..3e280bd 100644 --- a/tests/helpers/loadUser.test.js +++ b/tests/helpers/loadUser.test.js @@ -1,22 +1,22 @@ import '../setup'; import sinon from 'sinon'; import expect from 'expect'; -import { loadUserHandler } from '../../src/helpers/loadUser'; -import { userExpired, userFound } from '../../src/actions'; - -const coMocha = require('co-mocha'); -const mocha = require('mocha'); -coMocha(mocha); +import loadUserHandler, { getUserCallback, errorCallback, setReduxStore, getReduxStore } from '../../src/helpers/loadUser'; +import { userExpired, userFound, loadUserError } from '../../src/actions'; describe('helper - loadUser()', () => { let userManagerMock; let storeMock; let getUserStub; let dispatchStub; + let thenStub; + let catchStub; beforeEach(() => { dispatchStub = sinon.stub(); getUserStub = sinon.stub(); + thenStub = sinon.stub(); + catchStub = sinon.stub(); userManagerMock = { getUser: getUserStub @@ -25,23 +25,45 @@ describe('helper - loadUser()', () => { storeMock = { dispatch: dispatchStub }; + + getUserStub.returns({ + then: thenStub + }); + + thenStub.returns({ + catch: catchStub + }); + + setReduxStore(storeMock); }); - it('should dispatch a valid user to the store', function* () { + it('should dispatch a valid user to the store', () => { const validUser = { some: 'user' }; - getUserStub.returns(validUser); - yield* loadUserHandler(storeMock, userManagerMock); + getUserCallback(validUser); expect(dispatchStub.calledWith(userFound(validUser))).toEqual(true); }); - it('should dispatch USER_EXPIRED when no valid user is present', function* () { + it('should dispatch USER_EXPIRED when no valid user is present', () => { const invalidUser = { expired: true }; - getUserStub.returns(invalidUser); - yield* loadUserHandler(storeMock, userManagerMock); + getUserCallback(invalidUser); expect(dispatchStub.calledWith(userExpired())).toEqual(true); }); + + it('should set the redux store', () => { + loadUserHandler(storeMock, userManagerMock); + + expect(getReduxStore() === storeMock).toEqual(true); + }); + + it('errorCallback should dispatch LOAD_USER_ERROR', () => { + setReduxStore(storeMock); + + errorCallback({ message: 'Some message!'}); + + expect(dispatchStub.calledWith(loadUserError())).toEqual(true); + }) }); diff --git a/tests/oidcMiddleware.test.js b/tests/oidcMiddleware.test.js index b21d754..ed05877 100644 --- a/tests/oidcMiddleware.test.js +++ b/tests/oidcMiddleware.test.js @@ -1,16 +1,14 @@ import './setup'; import sinon from 'sinon'; import expect from 'expect'; -import createOidcMiddleware, { getUserSuccessCallback, getUserErrorCallback, setStoredUser, removeStoredUser, storedUser, middlewareHandler } from '../src/oidcMiddleware'; -import { userExpired, userFound, loadingUser } from '../src/actions'; - -const coMocha = require('co-mocha'); -const mocha = require('mocha'); -coMocha(mocha); +import createOidcMiddleware, { getUserCallback, errorCallback, setStoredUser, removeStoredUser, storedUser, getNext, setNext, middlewareHandler } from '../src/oidcMiddleware'; +import { userExpired, userFound, loadingUser, loadUserError } from '../src/actions'; describe('createOidcMiddleware()', function () { let userManagerMock; let getUserStub; + let thenStub; + let catchStub; let nextStub; let storeMock; let action; @@ -22,7 +20,15 @@ describe('createOidcMiddleware()', function () { beforeEach(function () { getUserStub = sinon.stub(); - + thenStub = sinon.stub(); + catchStub = sinon.stub(); + + thenStub.returns({ + catch: catchStub + }); + getUserStub.returns({ + then: thenStub + }); userManagerMock = { getUser: getUserStub }; @@ -38,7 +44,7 @@ describe('createOidcMiddleware()', function () { removeStoredUser(); }); - it('should return the correct middleware function', function* () { + it('should return the correct middleware function', () => { const middleware = createOidcMiddleware(userManagerMock); expect(typeof(middleware)).toEqual('function'); @@ -53,64 +59,79 @@ describe('createOidcMiddleware()', function () { expect(nextFunction.length).toEqual(1); }); - it('should throw an error when no user manager has been provided', function* () { + it('should throw an error when no user manager has been provided', () => { expect(() => {createOidcMiddleware(null)}).toThrow(/You must provide a user manager!/); expect(() => {createOidcMiddleware({})}).toThrow(/You must provide a user manager!/); expect(() => {createOidcMiddleware('userManager')}).toThrow(/You must provide a user manager!/); }); - it('middlewareHandler should not check the storage & trigger validation when the user is present', function* () { + it('middlewareHandler should not check the storage & trigger validation when the user is present', () => { setStoredUser({ some: 'user' }); - const iterator = middlewareHandler(nextStub, action, userManagerMock); - let current = iterator.next(); + middlewareHandler(nextStub, action, userManagerMock); expect(nextStub.calledWith(action)).toEqual(true); expect(nextStub.calledWith(userExpired())).toEqual(false); expect(getUserStub.called).toEqual(false); - expect(current.done).toEqual(true); }); - it('middlewareHandler should handle an expired user correctly', function* () { + it('middlewareHandler should handle an expired user correctly', () => { const expiredUser = { expired: true }; setStoredUser(expiredUser); - getUserStub.returns(expiredUser); + setNext(nextStub); - yield* middlewareHandler(nextStub, action, userManagerMock); + getUserCallback(expiredUser); - expect(getUserStub.called).toEqual(true); - expect(nextStub.calledWith(loadingUser())).toEqual(true); expect(nextStub.calledWith(userExpired())).toEqual(true); - expect(nextStub.calledWith(action)).toEqual(true); }); - it('middlewareHandler should handle a valid user correctly', function* () { + it('middlewareHandler should handle a valid user correctly', () => { const validUser = { some: 'user' }; + setStoredUser(null); getUserStub.returns(validUser); + setNext(nextStub); - yield* middlewareHandler(nextStub, action, userManagerMock); + getUserCallback(validUser); expect(nextStub.calledWith(userFound(validUser))).toEqual(true); expect(storedUser).toEqual(validUser); - expect(nextStub.calledWith(action)).toEqual(true); }); - it('middlwareHandler should not check the stored user when the action type is LOADING_USER', function* () { + it('middlwareHandler should not check the stored user when the action type is LOADING_USER', () => { action = loadingUser(); setStoredUser(null); - yield* middlewareHandler(nextStub, action, userManagerMock); + + middlewareHandler(nextStub, action, userManagerMock); expect(nextStub.calledWith(action)).toEqual(true); expect(getUserStub.called).toEqual(false); }); - it('middlwareHandler should not check the stored user when the action type is USER_EXPIRED', function* () { + it('middlwareHandler should not check the stored user when the action type is USER_EXPIRED', () => { action = userExpired(); setStoredUser(null); - yield* middlewareHandler(nextStub, action, userManagerMock); + + middlewareHandler(nextStub, action, userManagerMock); expect(nextStub.calledWith(action)).toEqual(true); expect(nextStub.calledWith(loadingUser())).toEqual(false); expect(getUserStub.called).toEqual(false); }); + + it('should set the next middleware', () => { + setStoredUser({ some: 'user' }); + setNext(null); + + middlewareHandler(nextStub, action, userManagerMock); + + expect(getNext()).toEqual(nextStub); + }); + + it('errorCallback should dispatch LOAD_USER_ERROR', () => { + setNext(nextStub); + + errorCallback({ message: 'Some message!' }); + + expect(nextStub.calledWith(loadUserError())).toEqual(true); + }) });