angular 2 testing w/router

2019-05-10 07:23发布

I have a component and when a user logs in it routes to a url called /dashboard I am really struggling figuring out why I am getting the following error.

cannot read property 'args' of undefined

I have been following the official docs on testing with router found here https://angular.io/docs/ts/latest/guide/testing.html#!#routed-component but it doesnt seem to help. Half my problem is I dont quite understand all the code in the doc. Here is my unit test for the route

 beforeEach(async(()=>{

      class AuthStub{
        private loggedin: boolean = false;
            login(){
              return this.loggedin = true;

            }
      };

      class RouterStub{
        navigateByUrl(url:string){return url;}
      }

    TestBed.configureTestingModule({
      declarations: [ HomePageContentComponent ],
      providers:[
        {provide: Auth, useClass:AuthStub},
        {provide: Router, useClass: RouterStub}
        ]
    })
    .compileComponents()
  }));

  beforeEach(()=>{

      fixture = TestBed.createComponent(HomePageContentComponent);
      comp = fixture.componentInstance;

      de = fixture.debugElement.query(By.css('.loginbtn'));
      el = de.nativeElement;
      fixture.detectChanges();

    });

    it('Should log in and navigate to dashboard', inject([Router],(router:Router)=>{

      const spy = spyOn(router, 'navigateByUrl');

      el.click();

      const navArgs = spy.calls.first().args[0];

      expect(navArgs).toBe('/dashboard');

    }))      
}); 

So my question is what is this line of code doing...

const navArgs = spy.calls.first().args[0];

and how can I fix my problem?

Service added

@Injectable()
export class Auth { 
    lock = new Auth0Lock('fakefakefakefakefake', 'fake.auth0.com', {
         additionalSignUpFields: [{
            name: "address",                              
            placeholder: "enter your address"
        }],
        theme: {
            primaryColor:"#b3b3b3",
        },
         languageDictionary: {
            title: "FAKE"
        }
    });

    userProfile: any;

    constructor(private router: Router) {
        this.userProfile = JSON.parse(localStorage.getItem('profile'));

        this.lock.on("authenticated", (authResult) => {
            localStorage.setItem('id_token', authResult.idToken);

            this.lock.getProfile(authResult.idToken, (error, profile) => {
                if (error) {

                    alert(error);
                    return;
                }

                profile.user_metadata = profile.user_metadata || {};
                localStorage.setItem('profile', JSON.stringify(profile));
                this.userProfile = profile;
            });
            this.router.navigate(['/dashboard']);
        });
    }

    public login(){
        this.lock.show();

    };

    public authenticated() {
        return tokenNotExpired();
    };

    public logout() {
        localStorage.removeItem('id_token');
        localStorage.removeItem('profile');
        this.router.navigate(['/logout']);
    };
}

1条回答
你好瞎i
2楼-- · 2019-05-10 07:51

Let's say you have the following component:

@Component({
  selector: 'home-comp',
  template: `<button (click)="login()" class="loginbtn">Login</button>
  `
})
export class HomePageContentComponent {
  constructor(private auth: Auth, private router: Router) { }

  login() {
    this.router.navigateByUrl(`/dashboard`);
  }
}

In your test after replacing real Router with mocked version:

{ provide: Router, useClass: RouterStub }

Inside you case:

it('Should log in and navigate to dashboard', inject([Router],(router:Router)=>{

router will be instance of RouterStub.

then you spy on for navigateByUrl method to watching how many times it was called

const spy = spyOn(router, 'navigateByUrl');

so when you clicking on the .loginbtn button router.navigateByUrl is running (see above component) and spy incrementes calls with some information(for example, what was called the argument)

Finally in this line

const navArgs = spy.calls.first().args[0];

is expected that your router.navigateByUrl method was called at least once then is getting passed argument from the first call.

Here is working Live Example

Possible you went wrong somewhere and your router.navigateByUrl isn't executed.

查看更多
登录 后发表回答