From d6fe9dbb7ce0278b7b3b8ece7942857904b8a1ae Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 11:39:45 -0800 Subject: [PATCH 1/9] Mock async call in token validation test --- .../app/services/util/prev-auth-guard.spec.ts | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 5bfb91c1..f83860cb 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -1,12 +1,11 @@ -import { TestBed } from '@angular/core/testing'; -import { PrevAuthGuard } from './prev-auth-guard'; -import { TokenService } from 'src/app/services/token.service'; -import { AppConfigService } from 'src/app/services/app-config.service'; -import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { of, Subject, BehaviorSubject } from 'rxjs'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { ResourcesRoutes } from 'src/app/utils'; +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { BehaviorSubject, of, Subject } from 'rxjs'; +import { AppConfigService } from 'src/app/services/app-config.service'; +import { TokenService } from 'src/app/services/token.service'; +import { PrevAuthGuard } from './prev-auth-guard'; class MockActivatedRouteSnapshot extends ActivatedRouteSnapshot { constructor(public routeConfigOverride?: any) { @@ -188,24 +187,29 @@ describe('PrevAuthGuard', () => { }); }); - it('should handle route with scopes when token validation fails', (done) => { + it('should handle route with scopes when token validation fails', fakeAsync(() => { // Setup route with scopes route.data = { scopes: [['test-scope']] }; - + // Mock token exists tokenService.getOauthToken.and.returnValue('test-token'); - + // Mock token validation fails tokenService.validateToken.and.returnValue(of(false)); - + // Spy on redirectToErrorPage spyOn(guard, 'redirectToErrorPage'); - - guard.canActivate(route, state).subscribe(result => { - expect(guard.redirectToErrorPage).toHaveBeenCalled(); - done(); + + // Trigger canActivate + let result: boolean | undefined; + guard.canActivate(route, state).subscribe(res => { + result = res; }); - }); + + tick(); // Simulate passage of time for the observable + expect(guard.redirectToErrorPage).toHaveBeenCalled(); + expect(result).toBeUndefined(); // Ensure the result matches the expectation + })); }); describe('getTokenInfo', () => { From fd63deb4f64a4bb69982fcfc947f3bb66fe0c548 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 12:07:13 -0800 Subject: [PATCH 2/9] Update test name to be more specific --- .../main/angular/src/app/services/util/prev-auth-guard.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index f83860cb..5ee65b74 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -187,7 +187,7 @@ describe('PrevAuthGuard', () => { }); }); - it('should handle route with scopes when token validation fails', fakeAsync(() => { + it('should redirect user to error page when token validation fails', fakeAsync(() => { // Setup route with scopes route.data = { scopes: [['test-scope']] }; From cec8d422311099a0b1779aeaccc852ac026b7136 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 12:36:36 -0800 Subject: [PATCH 3/9] Update test name and use new RouterStateSnapshot --- .../app/services/util/prev-auth-guard.spec.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 5ee65b74..dfe90707 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -189,28 +189,31 @@ describe('PrevAuthGuard', () => { it('should redirect user to error page when token validation fails', fakeAsync(() => { // Setup route with scopes + const route = new ActivatedRouteSnapshot(); route.data = { scopes: [['test-scope']] }; - + + const state = jasmine.createSpyObj('RouterStateSnapshot', [], { url: '/test' }); + // Mock token exists tokenService.getOauthToken.and.returnValue('test-token'); - + // Mock token validation fails tokenService.validateToken.and.returnValue(of(false)); - + // Spy on redirectToErrorPage spyOn(guard, 'redirectToErrorPage'); - + // Trigger canActivate let result: boolean | undefined; guard.canActivate(route, state).subscribe(res => { result = res; }); - + tick(); // Simulate passage of time for the observable expect(guard.redirectToErrorPage).toHaveBeenCalled(); expect(result).toBeUndefined(); // Ensure the result matches the expectation })); - }); + }) describe('getTokenInfo', () => { let mockRoute: any; @@ -288,31 +291,31 @@ describe('PrevAuthGuard', () => { tokenService.getOauthToken.and.returnValue(null); const result = await guard.canAccessRoute([['test-scope']], tokenService); - + expect(result).toBeFalse(); }); it('should return true when token is validated successfully', async () => { // Mock token exists tokenService.getOauthToken.and.returnValue('test-token'); - + // Mock token validation tokenService.validateToken.and.returnValue(of(true)); const result = await guard.canAccessRoute([['test-scope']], tokenService); - + expect(result).toBeTrue(); }); it('should return false when token validation fails', async () => { // Mock token exists tokenService.getOauthToken.and.returnValue('test-token'); - + // Mock token validation fails tokenService.validateToken.and.returnValue(of(false)); const result = await guard.canAccessRoute([['test-scope']], tokenService); - + expect(result).toBeFalse(); }); }); From 5d1febd799a4ab639f70547ab6c7ad4a58b71316 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 13:10:29 -0800 Subject: [PATCH 4/9] Improve logic in canActivate and fix test --- .../app/services/util/prev-auth-guard.spec.ts | 20 +++++++++--------- .../src/app/services/util/prev-auth-guard.ts | 21 ++++++++++++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index dfe90707..183c0e6f 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -1,5 +1,5 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { TestBed, fakeAsync, tick, flush } from '@angular/core/testing'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { BehaviorSubject, of, Subject } from 'rxjs'; @@ -188,30 +188,30 @@ describe('PrevAuthGuard', () => { }); it('should redirect user to error page when token validation fails', fakeAsync(() => { - // Setup route with scopes const route = new ActivatedRouteSnapshot(); route.data = { scopes: [['test-scope']] }; - + const state = jasmine.createSpyObj('RouterStateSnapshot', [], { url: '/test' }); - + // Mock token exists tokenService.getOauthToken.and.returnValue('test-token'); - + // Mock token validation fails tokenService.validateToken.and.returnValue(of(false)); - + // Spy on redirectToErrorPage spyOn(guard, 'redirectToErrorPage'); - + // Trigger canActivate let result: boolean | undefined; guard.canActivate(route, state).subscribe(res => { result = res; }); - - tick(); // Simulate passage of time for the observable + + tick(); // Simulate passage of time for observable + flush(); // Flush any remaining async operations + expect(guard.redirectToErrorPage).toHaveBeenCalled(); - expect(result).toBeUndefined(); // Ensure the result matches the expectation })); }) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts index 4d4f08db..41b9e377 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts @@ -32,16 +32,31 @@ export class PrevAuthGuard extends AuthGuard { route: ActivatedRouteSnapshot, state: RouterStateSnapshot, ): Observable { - + console.log('in here') if (!window.navigator.onLine) { + console.log('in here') return of(false); } if (route?.data?.['scopes']?.length > 0) { + console.log('in here1') // Wrap the Promise returned by getTokenInfo with from() return from(this.getTokenInfo(route)).pipe( - map(result => result), - catchError(() => of(false)) + map(result => { + console.log('result: ', result) + console.log('in here2') + if (result === false || result === undefined) { + console.log('in here3') + this.redirectToErrorPage(); + return of(false); + } + return result; + }), + catchError(() => { + console.log('in here4') + this.redirectToErrorPage(); + return of(false); + }) ); } else { console.log('returning true'); From e8e11d01dc2d0eb1c87847dafd3171a69b103405 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 13:16:49 -0800 Subject: [PATCH 5/9] Remobe console logs & useless result assignment --- .../angular/src/app/services/util/prev-auth-guard.spec.ts | 6 +----- .../main/angular/src/app/services/util/prev-auth-guard.ts | 8 -------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 183c0e6f..72163259 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -202,11 +202,7 @@ describe('PrevAuthGuard', () => { // Spy on redirectToErrorPage spyOn(guard, 'redirectToErrorPage'); - // Trigger canActivate - let result: boolean | undefined; - guard.canActivate(route, state).subscribe(res => { - result = res; - }); + guard.canActivate(route, state); tick(); // Simulate passage of time for observable flush(); // Flush any remaining async operations diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts index 41b9e377..e482d197 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.ts @@ -32,34 +32,26 @@ export class PrevAuthGuard extends AuthGuard { route: ActivatedRouteSnapshot, state: RouterStateSnapshot, ): Observable { - console.log('in here') if (!window.navigator.onLine) { - console.log('in here') return of(false); } if (route?.data?.['scopes']?.length > 0) { - console.log('in here1') // Wrap the Promise returned by getTokenInfo with from() return from(this.getTokenInfo(route)).pipe( map(result => { - console.log('result: ', result) - console.log('in here2') if (result === false || result === undefined) { - console.log('in here3') this.redirectToErrorPage(); return of(false); } return result; }), catchError(() => { - console.log('in here4') this.redirectToErrorPage(); return of(false); }) ); } else { - console.log('returning true'); return of(true); } } From 2b37d688a68a158272dab9130262f39d571ca5a3 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 13:49:37 -0800 Subject: [PATCH 6/9] Add test for when getTokenInfo returns as undefined --- .../app/services/util/prev-auth-guard.spec.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 72163259..562e3adc 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -211,6 +211,46 @@ describe('PrevAuthGuard', () => { })); }) + it('should redirect to error page when getTokenInfo returns false', fakeAsync(() => { + const route = new MockActivatedRouteSnapshot(); + route.data = { scopes: [['test-scope']] }; + const state = jasmine.createSpyObj('RouterStateSnapshot', [], { + url: '/test' + }); + + // Spy on getTokenInfo to return false + spyOn(guard, 'getTokenInfo' as any).and.returnValue(Promise.resolve(false)); + + // Spy on redirectToErrorPage + spyOn(guard, 'redirectToErrorPage'); + + guard.canActivate(route, state).subscribe(); + + tick(); // Advance async operations + + expect(guard.redirectToErrorPage).toHaveBeenCalled(); + })); + + it('should redirect to error page when getTokenInfo returns undefined', fakeAsync(() => { + const route = new MockActivatedRouteSnapshot(); + route.data = { scopes: [['test-scope']] }; + const state = jasmine.createSpyObj('RouterStateSnapshot', [], { + url: '/test' + }); + + // Spy on getTokenInfo to return undefined + spyOn(guard, 'getTokenInfo' as any).and.returnValue(Promise.resolve(undefined)); + + // Spy on redirectToErrorPage + spyOn(guard, 'redirectToErrorPage'); + + guard.canActivate(route, state).subscribe(); + + tick(); + + expect(guard.redirectToErrorPage).toHaveBeenCalled(); + })); + describe('getTokenInfo', () => { let mockRoute: any; From 731e971a6f00e7172d43b088a71ca35d0cfbf792 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 13:55:00 -0800 Subject: [PATCH 7/9] Flush any remaining async operations in token validation tests --- .../main/angular/src/app/services/util/prev-auth-guard.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 562e3adc..ccdbc5c6 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -227,6 +227,7 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state).subscribe(); tick(); // Advance async operations + flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); })); @@ -247,6 +248,7 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state).subscribe(); tick(); + flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); })); From 2c7041f99aea35f940d1e83136cffe820b3626a7 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 14:53:08 -0800 Subject: [PATCH 8/9] Remove calls to tick function --- .../angular/src/app/services/util/prev-auth-guard.spec.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index ccdbc5c6..5b7fc1ae 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -204,7 +204,6 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state); - tick(); // Simulate passage of time for observable flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); @@ -225,8 +224,7 @@ describe('PrevAuthGuard', () => { spyOn(guard, 'redirectToErrorPage'); guard.canActivate(route, state).subscribe(); - - tick(); // Advance async operations + flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); @@ -247,7 +245,6 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state).subscribe(); - tick(); flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); From cad0943d1f760fd059d0f77818f4992c7c861421 Mon Sep 17 00:00:00 2001 From: Sean Sylver Date: Mon, 9 Dec 2024 15:34:20 -0800 Subject: [PATCH 9/9] revert last change --- .../main/angular/src/app/services/util/prev-auth-guard.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts index 5b7fc1ae..8ae021a6 100644 --- a/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts +++ b/client/wfprev-war/src/main/angular/src/app/services/util/prev-auth-guard.spec.ts @@ -204,6 +204,7 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state); + tick(); flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); @@ -225,6 +226,7 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state).subscribe(); + tick(); flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled(); @@ -245,6 +247,7 @@ describe('PrevAuthGuard', () => { guard.canActivate(route, state).subscribe(); + tick(); flush(); // Flush any remaining async operations expect(guard.redirectToErrorPage).toHaveBeenCalled();