mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
440 lines
16 KiB
TypeScript
440 lines
16 KiB
TypeScript
import { fakeAsync, flush, TestBed } from '@angular/core/testing';
|
|
|
|
import { provideMockActions } from '@ngrx/effects/testing';
|
|
import { Store, StoreModule } from '@ngrx/store';
|
|
import { MockStore, provideMockStore } from '@ngrx/store/testing';
|
|
import { cold, hot } from 'jasmine-marbles';
|
|
import { Observable, of as observableOf, throwError as observableThrow } from 'rxjs';
|
|
|
|
import { AuthEffects } from './auth.effects';
|
|
import {
|
|
AuthActionTypes,
|
|
AuthenticatedAction,
|
|
AuthenticatedErrorAction,
|
|
AuthenticatedSuccessAction,
|
|
AuthenticationErrorAction,
|
|
AuthenticationSuccessAction,
|
|
CheckAuthenticationTokenCookieAction,
|
|
LogOutErrorAction,
|
|
LogOutSuccessAction,
|
|
RefreshTokenErrorAction,
|
|
RefreshTokenSuccessAction,
|
|
RetrieveAuthenticatedEpersonAction,
|
|
RetrieveAuthenticatedEpersonErrorAction,
|
|
RetrieveAuthenticatedEpersonSuccessAction,
|
|
RetrieveAuthMethodsAction,
|
|
RetrieveAuthMethodsErrorAction,
|
|
RetrieveAuthMethodsSuccessAction,
|
|
RetrieveTokenAction
|
|
} from './auth.actions';
|
|
import { authMethodsMock, AuthServiceStub } from '../../shared/testing/auth-service.stub';
|
|
import { AuthService } from './auth.service';
|
|
import { authReducer } from './auth.reducer';
|
|
import { AuthStatus } from './models/auth-status.model';
|
|
import { EPersonMock } from '../../shared/testing/eperson.mock';
|
|
import { AppState, storeModuleConfig } from '../../app.reducer';
|
|
import { StoreActionTypes } from '../../store.actions';
|
|
import { isAuthenticated, isAuthenticatedLoaded } from './selectors';
|
|
import { AuthorizationDataService } from '../data/feature-authorization/authorization-data.service';
|
|
|
|
describe('AuthEffects', () => {
|
|
let authEffects: AuthEffects;
|
|
let actions: Observable<any>;
|
|
let authServiceStub;
|
|
let initialState;
|
|
let token;
|
|
let store: MockStore<AppState>;
|
|
|
|
const authorizationService = jasmine.createSpyObj(['invalidateAuthorizationsRequestCache']);
|
|
|
|
function init() {
|
|
authServiceStub = new AuthServiceStub();
|
|
token = authServiceStub.getToken();
|
|
initialState = {
|
|
core: {
|
|
auth: {
|
|
authenticated: false,
|
|
loaded: false,
|
|
loading: false,
|
|
authMethods: []
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
beforeEach(() => {
|
|
init();
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig)
|
|
],
|
|
providers: [
|
|
AuthEffects,
|
|
provideMockStore({ initialState }),
|
|
{ provide: AuthorizationDataService, useValue: authorizationService },
|
|
{ provide: AuthService, useValue: authServiceStub },
|
|
provideMockActions(() => actions),
|
|
// other providers
|
|
],
|
|
});
|
|
|
|
authEffects = TestBed.inject(AuthEffects);
|
|
store = TestBed.inject(Store as any);
|
|
});
|
|
|
|
describe('authenticate$', () => {
|
|
describe('when credentials are correct', () => {
|
|
it('should return a AUTHENTICATE_SUCCESS action in response to a AUTHENTICATE action', () => {
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.AUTHENTICATE,
|
|
payload: { email: 'user', password: 'password' }
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new AuthenticationSuccessAction(token) });
|
|
|
|
expect(authEffects.authenticate$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when credentials are wrong', () => {
|
|
it('should return a AUTHENTICATE_ERROR action in response to a AUTHENTICATE action', () => {
|
|
spyOn((authEffects as any).authService, 'authenticate').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.AUTHENTICATE,
|
|
payload: { email: 'user', password: 'wrongpassword' }
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new AuthenticationErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.authenticate$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('authenticateSuccess$', () => {
|
|
|
|
it('should return a AUTHENTICATED action in response to a AUTHENTICATE_SUCCESS action', () => {
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATE_SUCCESS, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new AuthenticatedAction(token) });
|
|
|
|
expect(authEffects.authenticateSuccess$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('authenticated$', () => {
|
|
|
|
describe('when token is valid', () => {
|
|
it('should return a AUTHENTICATED_SUCCESS action in response to a AUTHENTICATED action', () => {
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATED, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new AuthenticatedSuccessAction(true, token, EPersonMock._links.self.href) });
|
|
|
|
expect(authEffects.authenticated$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when token is not valid', () => {
|
|
it('should return a AUTHENTICATED_ERROR action in response to a AUTHENTICATED action', () => {
|
|
spyOn((authEffects as any).authService, 'authenticatedUser').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATED, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new AuthenticatedErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.authenticated$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('authenticatedSuccess$', () => {
|
|
|
|
it('should return a RETRIEVE_AUTHENTICATED_EPERSON action in response to a AUTHENTICATED_SUCCESS action', (done) => {
|
|
spyOn((authEffects as any).authService, 'storeToken');
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.AUTHENTICATED_SUCCESS, payload: {
|
|
authenticated: true,
|
|
authToken: token,
|
|
userHref: EPersonMock._links.self.href
|
|
}
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonAction(EPersonMock._links.self.href) });
|
|
|
|
authEffects.authenticatedSuccess$.subscribe(() => {
|
|
expect(authServiceStub.storeToken).toHaveBeenCalledWith(token);
|
|
});
|
|
|
|
expect(authEffects.authenticatedSuccess$).toBeObservable(expected);
|
|
done();
|
|
});
|
|
|
|
});
|
|
|
|
describe('checkToken$', () => {
|
|
|
|
describe('when check token succeeded', () => {
|
|
it('should return a AUTHENTICATED action in response to a CHECK_AUTHENTICATION_TOKEN action', () => {
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN } });
|
|
|
|
const expected = cold('--b-', { b: new AuthenticatedAction(token) });
|
|
|
|
expect(authEffects.checkToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when check token failed', () => {
|
|
it('should return a CHECK_AUTHENTICATION_TOKEN_ERROR action in response to a CHECK_AUTHENTICATION_TOKEN action', () => {
|
|
spyOn((authEffects as any).authService, 'hasValidAuthenticationToken').and.returnValue(observableThrow(''));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new CheckAuthenticationTokenCookieAction() });
|
|
|
|
expect(authEffects.checkToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('checkTokenCookie$', () => {
|
|
|
|
describe('when check token succeeded', () => {
|
|
it('should return a RETRIEVE_TOKEN action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action when authenticated is true', () => {
|
|
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(
|
|
observableOf(
|
|
{
|
|
authenticated: true
|
|
})
|
|
);
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE } });
|
|
|
|
const expected = cold('--b-', { b: new RetrieveTokenAction() });
|
|
|
|
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
|
|
authEffects.checkTokenCookie$.subscribe(() => {
|
|
expect((authEffects as any).authorizationsService.invalidateAuthorizationsRequestCache).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('should return a RETRIEVE_AUTH_METHODS action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action when authenticated is false', () => {
|
|
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(
|
|
observableOf(
|
|
{ authenticated: false })
|
|
);
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE } });
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthMethodsAction({ authenticated: false } as AuthStatus) });
|
|
|
|
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when check token failed', () => {
|
|
it('should return a AUTHENTICATED_ERROR action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action', () => {
|
|
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new AuthenticatedErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('retrieveAuthenticatedEperson$', () => {
|
|
|
|
describe('when request is successful', () => {
|
|
it('should return a RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS action in response to a RETRIEVE_AUTHENTICATED_EPERSON action', () => {
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON,
|
|
payload: EPersonMock._links.self.href
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonSuccessAction(EPersonMock.id) });
|
|
|
|
expect(authEffects.retrieveAuthenticatedEperson$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when request is not successful', () => {
|
|
it('should return a RETRIEVE_AUTHENTICATED_EPERSON_ERROR action in response to a RETRIEVE_AUTHENTICATED_EPERSON action', () => {
|
|
spyOn((authEffects as any).authService, 'retrieveAuthenticatedUserByHref').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.retrieveAuthenticatedEperson$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('refreshToken$', () => {
|
|
|
|
describe('when refresh token succeeded', () => {
|
|
it('should return a REFRESH_TOKEN_SUCCESS action in response to a REFRESH_TOKEN action', () => {
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.REFRESH_TOKEN } });
|
|
|
|
const expected = cold('--b-', { b: new RefreshTokenSuccessAction(token) });
|
|
|
|
expect(authEffects.refreshToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when refresh token failed', () => {
|
|
it('should return a REFRESH_TOKEN_ERROR action in response to a REFRESH_TOKEN action', () => {
|
|
spyOn((authEffects as any).authService, 'refreshAuthenticationToken').and.returnValue(observableThrow(''));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.REFRESH_TOKEN, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new RefreshTokenErrorAction() });
|
|
|
|
expect(authEffects.refreshToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('retrieveToken$', () => {
|
|
describe('when user is authenticated', () => {
|
|
it('should return a AUTHENTICATE_SUCCESS action in response to a RETRIEVE_TOKEN action', () => {
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.RETRIEVE_TOKEN
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new AuthenticationSuccessAction(token) });
|
|
|
|
expect(authEffects.retrieveToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when user is not authenticated', () => {
|
|
it('should return a AUTHENTICATE_ERROR action in response to a RETRIEVE_TOKEN action', () => {
|
|
spyOn((authEffects as any).authService, 'refreshAuthenticationToken').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', {
|
|
a: {
|
|
type: AuthActionTypes.RETRIEVE_TOKEN
|
|
}
|
|
});
|
|
|
|
const expected = cold('--b-', { b: new AuthenticationErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.retrieveToken$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('logOut$', () => {
|
|
|
|
describe('when refresh token succeeded', () => {
|
|
it('should return a LOG_OUT_SUCCESS action in response to a LOG_OUT action', () => {
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.LOG_OUT } });
|
|
|
|
const expected = cold('--b-', { b: new LogOutSuccessAction() });
|
|
|
|
expect(authEffects.logOut$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when refresh token failed', () => {
|
|
it('should return a REFRESH_TOKEN_ERROR action in response to a LOG_OUT action', () => {
|
|
spyOn((authEffects as any).authService, 'logout').and.returnValue(observableThrow(new Error('Message Error test')));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.LOG_OUT, payload: token } });
|
|
|
|
const expected = cold('--b-', { b: new LogOutErrorAction(new Error('Message Error test')) });
|
|
|
|
expect(authEffects.logOut$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('retrieveMethods$', () => {
|
|
|
|
describe('when retrieve authentication methods succeeded', () => {
|
|
it('should return a RETRIEVE_AUTH_METHODS_SUCCESS action in response to a RETRIEVE_AUTH_METHODS action', () => {
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.RETRIEVE_AUTH_METHODS } });
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthMethodsSuccessAction(authMethodsMock) });
|
|
|
|
expect(authEffects.retrieveMethods$).toBeObservable(expected);
|
|
});
|
|
});
|
|
|
|
describe('when retrieve authentication methods failed', () => {
|
|
it('should return a RETRIEVE_AUTH_METHODS_ERROR action in response to a RETRIEVE_AUTH_METHODS action', () => {
|
|
spyOn((authEffects as any).authService, 'retrieveAuthMethodsFromAuthStatus').and.returnValue(observableThrow(''));
|
|
|
|
actions = hot('--a-', { a: { type: AuthActionTypes.RETRIEVE_AUTH_METHODS } });
|
|
|
|
const expected = cold('--b-', { b: new RetrieveAuthMethodsErrorAction() });
|
|
|
|
expect(authEffects.retrieveMethods$).toBeObservable(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('clearInvalidTokenOnRehydrate$', () => {
|
|
|
|
beforeEach(() => {
|
|
store.overrideSelector(isAuthenticated, false);
|
|
});
|
|
|
|
describe('when auth loaded is false', () => {
|
|
it('should not call removeToken method', (done) => {
|
|
store.overrideSelector(isAuthenticatedLoaded, false);
|
|
actions = hot('--a-|', { a: { type: StoreActionTypes.REHYDRATE } });
|
|
spyOn(authServiceStub, 'removeToken');
|
|
|
|
authEffects.clearInvalidTokenOnRehydrate$.subscribe(() => {
|
|
expect(authServiceStub.removeToken).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe('when auth loaded is true', () => {
|
|
it('should call removeToken method', fakeAsync(() => {
|
|
store.overrideSelector(isAuthenticatedLoaded, true);
|
|
actions = hot('--a-|', { a: { type: StoreActionTypes.REHYDRATE } });
|
|
spyOn(authServiceStub, 'removeToken');
|
|
|
|
authEffects.clearInvalidTokenOnRehydrate$.subscribe(() => {
|
|
expect(authServiceStub.removeToken).toHaveBeenCalled();
|
|
flush();
|
|
});
|
|
|
|
}));
|
|
});
|
|
});
|
|
|
|
describe('invalidateAuthorizationsRequestCache$', () => {
|
|
it('should call invalidateAuthorizationsRequestCache method in response to a REHYDRATE action', (done) => {
|
|
actions = hot('--a-|', { a: { type: StoreActionTypes.REHYDRATE } });
|
|
|
|
authEffects.invalidateAuthorizationsRequestCache$.subscribe(() => {
|
|
expect((authEffects as any).authorizationsService.invalidateAuthorizationsRequestCache).toHaveBeenCalled();
|
|
});
|
|
|
|
done();
|
|
});
|
|
});
|
|
});
|