Created
July 16, 2020 11:32
-
-
Save LayZeeDK/6d34f5843f123a27950f89c86ab84bbb to your computer and use it in GitHub Desktop.
AuthGuard: Isolated route guard test suite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
ActivatedRouteSnapshot, | |
Params, | |
Route, | |
Router, | |
RouterStateSnapshot, | |
UrlSegment, | |
} from '@angular/router'; | |
import { AuthGuard } from './auth.guard'; | |
import { AuthService } from './auth.service'; | |
function fakeRouterState(url: string): RouterStateSnapshot { | |
return { | |
url, | |
} as RouterStateSnapshot; | |
} | |
describe('AuthGuard (isolated)', () => { | |
beforeEach(() => { | |
routerSpy = jasmine.createSpyObj<Router>('Router', ['navigate']); | |
serviceStub = {}; | |
guard = new AuthGuard(serviceStub as AuthService, routerSpy); | |
}); | |
const dummyRoute = {} as ActivatedRouteSnapshot; | |
const fakeUrls = [ | |
'/', | |
'/admin', | |
'/crisis-center', | |
'/a/deep/route', | |
]; | |
let guard: AuthGuard; | |
let routerSpy: jasmine.SpyObj<Router>; | |
let serviceStub: Partial<AuthService>; | |
describe('when the user is logged in', () => { | |
beforeEach(() => { | |
serviceStub.isLoggedIn = true; | |
}); | |
fakeUrls.forEach(fakeUrl => { | |
it('grants access', () => { | |
const isAccessGranted = guard.checkLogin(fakeUrl); | |
expect(isAccessGranted).toBeTrue(); | |
}); | |
describe('and navigates to a guarded route configuration', () => { | |
it('grants route access', () => { | |
const canActivate = | |
guard.canActivate(dummyRoute, fakeRouterState(fakeUrl)); | |
expect(canActivate).toBeTrue(); | |
}); | |
it('grants child route access', () => { | |
const canActivateChild = | |
guard.canActivateChild(dummyRoute, fakeRouterState(fakeUrl)); | |
expect(canActivateChild).toBeTrue(); | |
}); | |
const paths = fakeUrl.split('/').filter(path => path !== ''); | |
paths.forEach(path => { | |
it('grants feature access', () => { | |
const fakeRoute: Route = { path }; | |
const fakeUrlSegment = { path } as UrlSegment; | |
const canLoad = guard.canLoad(fakeRoute, [fakeUrlSegment]); | |
expect(canLoad).toBeTrue(); | |
}); | |
}); | |
}); | |
}); | |
}); | |
describe('when the user is logged out', () => { | |
beforeEach(() => { | |
serviceStub.isLoggedIn = false; | |
}); | |
fakeUrls.forEach(fakeUrl => { | |
it('rejects access', () => { | |
const isAccessGranted = guard.checkLogin(fakeUrl); | |
expect(isAccessGranted).toBeFalse(); | |
}); | |
it('stores the redirect URL', () => { | |
guard.checkLogin(fakeUrl); | |
expect(serviceStub.redirectUrl).toBe(fakeUrl); | |
}); | |
it('navigates to the login page', () => { | |
guard.checkLogin(fakeUrl); | |
expect(routerSpy.navigate) | |
.toHaveBeenCalledWith(['/login'], jasmine.any(Object)); | |
}); | |
it('adds a token to the login URL', () => { | |
const expectedToken = 'anchor'; | |
guard.checkLogin(fakeUrl); | |
expect(routerSpy.navigate).toHaveBeenCalledWith( | |
jasmine.any(Array), | |
jasmine.objectContaining({ | |
fragment: expectedToken, | |
})); | |
}); | |
it('adds a session ID to the login URL', () => { | |
const expectedQueryParams: Params = { | |
session_id: jasmine.any(Number), | |
}; | |
guard.checkLogin(fakeUrl); | |
expect(routerSpy.navigate).toHaveBeenCalledWith( | |
jasmine.any(Array), | |
jasmine.objectContaining({ | |
queryParams: expectedQueryParams, | |
})); | |
}); | |
describe('and navigates to a guarded route configuration', () => { | |
it('rejects route access', () => { | |
const canActivate = | |
guard.canActivate(dummyRoute, fakeRouterState(fakeUrl)); | |
expect(canActivate).toBeFalse(); | |
}); | |
it('rejects child route access', () => { | |
const canActivateChild = | |
guard.canActivateChild(dummyRoute, fakeRouterState(fakeUrl)); | |
expect(canActivateChild).toBeFalse(); | |
}); | |
const paths = fakeUrl.split('/').filter(path => path !== ''); | |
paths.forEach(path => { | |
it('rejects feature access', () => { | |
const fakeRoute: Route = { path }; | |
const fakeUrlSegment = { path } as UrlSegment; | |
const canLoad = guard.canLoad(fakeRoute, [fakeUrlSegment]); | |
expect(canLoad).toBeFalse(); | |
}); | |
}); | |
}); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@angular/core'; | |
import { | |
ActivatedRouteSnapshot, | |
CanActivate, | |
CanActivateChild, | |
CanLoad, | |
NavigationExtras, | |
Route, | |
Router, | |
RouterStateSnapshot, | |
UrlSegment, | |
} from '@angular/router'; | |
import { AuthService } from './auth.service'; | |
@Injectable({ | |
providedIn: 'root', | |
}) | |
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad { | |
constructor( | |
private authService: AuthService, | |
private router: Router, | |
) { } | |
canActivate( | |
route: ActivatedRouteSnapshot, | |
state: RouterStateSnapshot, | |
): boolean { | |
const url = state.url; | |
return this.checkLogin(url); | |
} | |
canActivateChild( | |
route: ActivatedRouteSnapshot, | |
state: RouterStateSnapshot, | |
): boolean { | |
return this.canActivate(route, state); | |
} | |
canLoad(route: Route, segments: UrlSegment[]): boolean { | |
const url = `/${route.path}`; | |
return this.checkLogin(url); | |
} | |
checkLogin(url: string): boolean { | |
if (this.authService.isLoggedIn) { | |
return true; | |
} | |
// Store the attempted URL for redirecting | |
this.authService.redirectUrl = url; | |
// Create a dummy session id | |
const sessionId = 123456789; | |
// Set our navigation extras object | |
// that contains our global query params and fragment | |
const navigationExtras: NavigationExtras = { | |
queryParams: { session_id: sessionId }, | |
fragment: 'anchor', | |
}; | |
// Navigate to the login page with extras | |
this.router.navigate(['/login'], navigationExtras); | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment