Skip to content

Commit

Permalink
feat(auth): call unauthenticated hooks before resetting client cache (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 committed Jul 13, 2023
1 parent 57127d3 commit a519413
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 29 deletions.
82 changes: 56 additions & 26 deletions libs/auth/state/src/effects/auth.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
DaffAuthStorageFailure,
DaffAuthGuardLogout,
DaffAuthLogoutSuccess,
DaffAuthResetToUnauthenticated,
} from '@daffodil/auth/state';
import {
DaffServerSideStorageError,
Expand All @@ -37,6 +38,7 @@ import {
DaffDriverHttpClientCacheServiceInterface,
} from '@daffodil/driver';

import { DAFF_AUTH_UNAUTHENTICATED_HOOK } from '../injection-tokens/unauthenticated/hook.token';
import { DaffAuthEffects } from './auth.effects';

const getScheduler = () => new TestScheduler((actual, expected) => {
Expand All @@ -53,6 +55,7 @@ describe('@daffodil/auth/state | DaffAuthEffects', () => {
let clientCacheSpy: jasmine.SpyObj<DaffDriverHttpClientCacheServiceInterface>;
let getTokenSpy: jasmine.Spy<DaffAuthStorageService['getAuthToken']>;
let removeTokenSpy: jasmine.Spy<DaffAuthStorageService['removeAuthToken']>;
let unauthenticatedHook: jasmine.Spy;

const authStorageFailureAction = new DaffAuthStorageFailure(daffTransformErrorToStateError(
new DaffStorageServiceError('Storage of auth token has failed.')),
Expand All @@ -63,6 +66,7 @@ describe('@daffodil/auth/state | DaffAuthEffects', () => {

beforeEach(() => {
clientCacheSpy = jasmine.createSpyObj('DaffDriverHttpClientCacheServiceInterface', ['reset']);
unauthenticatedHook = jasmine.createSpy();

TestBed.configureTestingModule({
providers: [
Expand All @@ -82,6 +86,10 @@ describe('@daffodil/auth/state | DaffAuthEffects', () => {
provide: DAFF_DRIVER_HTTP_CLIENT_CACHE_SERVICE,
useValue: clientCacheSpy,
},
{
provide: DAFF_AUTH_UNAUTHENTICATED_HOOK,
useValue: unauthenticatedHook,
},
],
});

Expand Down Expand Up @@ -202,46 +210,68 @@ describe('@daffodil/auth/state | DaffAuthEffects', () => {
});
});

describe('clearClientCache$', () => {
describe('resetToUnauthenticated$', () => {
let expected;

describe('when DaffAuthCheckFailure is dispatched', () => {
let revokeAction: DaffAuthCheckFailure;
describe('when AuthCheckFailure is dispatched', () => {
let authLogoutSuccessAction: DaffAuthCheckFailure;

beforeEach(() => {
revokeAction = new DaffAuthCheckFailure(null);
authLogoutSuccessAction = new DaffAuthCheckFailure({ code: 'code', message: 'message' });
actions$ = hot('--a', { a: authLogoutSuccessAction });
expected = cold('--a', { a: new DaffAuthResetToUnauthenticated() });
});

it('should reset the client cache after a delay', () => {
scheduler = getScheduler();
scheduler.run(({ expectObservable, time, flush, hot: createHot }) => {
actions$ = createHot('--a-', { a: revokeAction });
expectObservable(effects.clearClientCache$(10, scheduler)).toBe('---');
expect(clientCacheSpy.reset).not.toHaveBeenCalled();
time('10|');
flush();
expect(clientCacheSpy.reset).toHaveBeenCalledWith();
});
it('should dispatch DaffAuthResetToUnauthenticated', () => {
expect(effects.resetToUnauthenticated$).toBeObservable(expected);
});
});

describe('when DaffAuthGuardLogout is dispatched', () => {
let revokeAction: DaffAuthGuardLogout;
describe('when AuthGuardLogout is dispatched', () => {
let authLogoutSuccessAction: DaffAuthGuardLogout;

beforeEach(() => {
revokeAction = new DaffAuthGuardLogout(null);
authLogoutSuccessAction = new DaffAuthGuardLogout({ code: 'code', message: 'message' });
actions$ = hot('--a', { a: authLogoutSuccessAction });
expected = cold('--a', { a: new DaffAuthResetToUnauthenticated() });
});

it('should dispatch DaffAuthResetToUnauthenticated', () => {
expect(effects.resetToUnauthenticated$).toBeObservable(expected);
});
});

describe('when LogoutSuccess is dispatched', () => {
let authLogoutSuccessAction: DaffAuthLogoutSuccess;

beforeEach(() => {
authLogoutSuccessAction = new DaffAuthLogoutSuccess();
actions$ = hot('--a', { a: authLogoutSuccessAction });
expected = cold('--a', { a: new DaffAuthResetToUnauthenticated() });
});

it('should dispatch DaffAuthResetToUnauthenticated', () => {
expect(effects.resetToUnauthenticated$).toBeObservable(expected);
});
});
});

describe('clearClientCache$', () => {
let expected;

describe('when DaffAuthResetToUnauthenticated is dispatched', () => {
let revokeAction: DaffAuthResetToUnauthenticated;

beforeEach(() => {
revokeAction = new DaffAuthResetToUnauthenticated();
actions$ = hot('--a', { a: revokeAction });
expected = cold('---');
});

it('should reset the client cache after a delay', () => {
scheduler = getScheduler();
scheduler.run(({ expectObservable, time, flush, hot: createHot }) => {
actions$ = createHot('--a-', { a: revokeAction });
expectObservable(effects.clearClientCache$(10, scheduler)).toBe('---');
expect(clientCacheSpy.reset).not.toHaveBeenCalled();
time('10|');
flush();
expect(clientCacheSpy.reset).toHaveBeenCalledWith();
});
expect(effects.clearClientCache$).toBeObservable(expected);
expect(unauthenticatedHook).toHaveBeenCalledWith();
expect(clientCacheSpy.reset).toHaveBeenCalledWith();
});
});
});
Expand Down
18 changes: 16 additions & 2 deletions libs/auth/state/src/effects/auth.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ import {
DaffAuthLoginActionTypes,
DaffAuthActions,
DaffAuthLoginActions,
DaffAuthResetToUnauthenticated,
} from '../actions/public_api';
import {
DaffAuthStateConfig,
DAFF_AUTH_STATE_CONFIG,
} from '../config/public_api';
import { DAFF_AUTH_UNAUTHENTICATED_HOOK } from '../injection-tokens/unauthenticated/hook.token';

@Injectable()
export class DaffAuthEffects {
Expand All @@ -63,6 +65,7 @@ export class DaffAuthEffects {
private storage: DaffAuthStorageService,
@Inject(DAFF_AUTH_STATE_CONFIG) private config: DaffAuthStateConfig,
@Inject(DAFF_DRIVER_HTTP_CLIENT_CACHE_SERVICE) private clientCache: DaffDriverHttpClientCacheServiceInterface,
@Inject(DAFF_AUTH_UNAUTHENTICATED_HOOK) private unauthenticatedHook: () => void,
) {}

check$ = createEffect(() => this.actions$.pipe(
Expand Down Expand Up @@ -113,13 +116,24 @@ export class DaffAuthEffects {
}),
));

clearClientCache$ = createEffect(() => (delayTime = 10, scheduler = asyncScheduler) => this.actions$.pipe(
resetToUnauthenticated$ = createEffect(() => this.actions$.pipe(
ofType(
DaffAuthActionTypes.AuthCheckFailureAction,
DaffAuthActionTypes.AuthGuardLogoutAction,
DaffAuthLoginActionTypes.LogoutSuccessAction,
),
delay(delayTime, scheduler),
map(() => new DaffAuthResetToUnauthenticated()),
));

clearClientCache$ = createEffect(() => this.actions$.pipe(
ofType(
DaffAuthActionTypes.ResetToUnauthenticatedAction,
),
// map here to be sure that the stream waits for the hook to complete
// tap is for side effects and might use setTimeout
map(() => {
this.unauthenticatedHook();
}),
tap(() => {
this.clientCache.reset();
}),
Expand Down
2 changes: 1 addition & 1 deletion libs/auth/state/src/effects/login.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class DaffAuthLoginEffects<
switchMap((action: DaffAuthLogout) =>
this.loginDriver.logout().pipe(
map(() => new DaffAuthLogoutSuccess()),
tap(() => this.storage.removeAuthToken()),
tap(() => this.storage.removeAuthToken()),
catchError((error: DaffError) => {
switch (true) {
case error instanceof DaffServerSideStorageError:
Expand Down

0 comments on commit a519413

Please sign in to comment.