Skip to content

TL;DR: Run the guard inside the TestBed.runInInjectionContext callback.

Let's say, we have a functional guard that checks if the user is authorized to use the application that we want to test.

// auth.guard.ts
export const authGuard = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean => {
	return inject(UserService).isAuthorised
}

Now we need to create a unit test file to run test of the guard.

To properly run the guard function in a test spec, you need to wrap it in the TestBed.runInInjectionContext's callback, as mentioned above. It will call the callback argument inside its own injection context.

Just create a function that will run the runInInjectionContext that will run the guard. And then use that function in the it blocks as if it was the actual functional guard.

// auth.guard.spec.ts

// A blank component to emulate a page
@Component({})
class BlankComponent {}

// Injected service's stub for testing purposes
class UserServiceStub {
   public static isAuthorised = true;
   public isAuthorised = UserServiceMock.isAuthorised;
}

function runAuthGuard(): boolean {
  const snapshot = TestBed.inject(ActivatedRoute).snapshot;
  return TestBed.runInInjectionContext(() => authGuard(snapshot, {} as RouterStateSnapshot));
}

describe('AuthGuard', () => {
	beforeEach(() => {
		TestBed.configureTestingModule({
			providers: [
				{
					provide: ActivatedRoute,
					useValue: {
						snapshot: {},
					},
				},
				{
					provide: UserService,
					useClass: UserServiceStub,
				},
			],
			imports: [
				RouterTestingModule.withRoutes([
					{
						path: '',
						component: BlankComponent,
					},
					{
						path: 'dashboard',
						component: BlankComponent,
						canActivate: [authGuard],
					},
				]),
			],
		})
	})

    // To prevent occasional errors in tests
    afterEach(async () => {
      await TestBed.inject(Router).navigate(['/']);
    });

    it('let\'s authorised users pass', () => {
        expect(runAuthGuard()).toEqual(true)
    })

    it('doesn\'t let unauthorised users pass', () => {
        UserServiceStub.isAuthorised = false;
        expect(runAuthGuard()).toEqual(false)
    })
})