简体   繁体   中英

How to inject Angular 6+ service variables into app-routing.module.spec.ts and test router redirection

I'm trying to test whether a user is redirected successfully if an authenticated variable is set to true.

I've tried injecting my LoginService into a beforeEach and setting the authenticated variable to false. Then, in the unit test, setting that variable to true. I then expect my guard to pick up the fact that authenticated is set to true and in turn, redirect to the dashboard page.

app-routing-module.spec.ts:

import { LoginService } from './services/login.service';
import { Router } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';
import { Location } from "@angular/common";
import { routes } from "./app-routing.module";
import { AppComponent } from './components/app.component';


describe('AppRoutingModule, () => {
      let location: Location;
      let router: Router;

  beforeEach(() => {
      TestBed.configureTestingModule({
          declarations: [AppComponent],
          providers: [LoginService]
      })

      router = TestBed.get(Router);
      location = TestBed.get(Location);
      fixture = TestBed.createComponent(AppComponent);
      router.initialNavigation();
  });

  beforeEach(inject([LoginService], (loginService: LoginService) => {
    loginService.authenticated = false;
  }))

  it('should redirect the user form the LoginComponent to the DashboardComponent if the user is already logged in', inject([LoginService](loginService: LoginService) => {
    loginService.authenticated = true;
    console.log(loginService);
    router.navigate([""]).then(() => {
      expect(location.path()).toBe("/dashboard");
    });
  }))
})

login.guard.ts:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { LoginService } from '../services/login.service';
import { Observable } from 'rxjs/index';


@Injectable({
  providedIn: 'root'
})
export class LoginGuard implements CanActivate {

  constructor(private router: Router, private loginService: LoginService) { 
}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    console.log('checked authenticated guard');
    if (this.loginService.authenticated === true) {
      this.loginService.navigationState.next(true);
      return true;
    } else {
      this.router.navigate(['']);
      return false;
    }
  }
}

login.service.ts:

public authenticated = false;

app-routing.module.ts:

export const routes: Routes = [
  { path: '', component: LoginComponent },
  { path: 'dashboard', component: CurrentActivityComponent, canActivate: [LoginGuard] }
]

I expect the test to pass, redirecting the user to 'dashboard', but it fails with: Expected '/' to be '/dashboard'.

I suspect it's to do with how I'm injecting my service. But I'm not sure what I am doing wrong.

In your test you're navigating to the main route ( router.navigate([""]) ) which is not guarded at all (in other words, your guard is not called). The guard will only be invoked if you actually try to access the guarded route. Therefore in your test you would have to navigate to dashboard ( router.navigate(['dashboard']) ) to make it pass.

To achieve the redirection behaviour you're describing, you would've to add another guard for that purpose to the first route.

PS: Jasmine also comes with spies which allow you to fi decouple your component tests from the service implementation by specifying the return value of a service method. They don't work with plain properties (without getter/setter) though. If you had an isAuthenticated method on your service, it would look like this:

const loginService = fixture.debugElement.injector.get(LoginService);
spyOn(loginService, 'isAuthenticated').and.returnValue(true);

Spies are scoped per IT block, meaning they don't have any side effects on your other tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM