4

I have the following component method:

onSignup() {
    if (this.form.valid) {
      let email = this.form.value.email;
      let password = this.form.value.password;
      this.usersService.signup(email, password)
        .then(() => {
          console.log('1')
          this.router.navigate(['/app/home']);
        })
        .catch(err => {
          this.mdlSnackbarService.showToast(err);
        });
    }
  }

And the following unit test:

it('should navigate on success', async(() => {
    spyOn(usersService, 'signup').and.returnValue(Promise.resolve());

    component.form.setValue({'email': 'mail@mail.com', 'password': '123456'});

    component.onSignup();

    fixture.whenStable().then(() => {
        console.log('2')
        expect(router.navigate).toHaveBeenCalledWith(['/app/home']);
    })
  }))

I have added a couple of console.log in order to figure out why this fails, and it turns out that 1 is never printed, so it doesn't wait for the promise to be resolved, despite being using fixture.whenStable(). This is my beforeEach:

beforeEach(inject([Router],(_router: Router) => {
    router = _router;
    router.navigate = jasmine.createSpy('navigate');
    fixture = TestBed.createComponent(SignupComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

Does anyone know what I am doing wrong here?

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
mario595
  • 3,671
  • 7
  • 34
  • 57
  • actually i can see this works somehow in my plunker - http://plnkr.co/edit/xIUqQwtFtaC4gBcGTioh?p=preview, it will be good if you can demostrate your problem with plunker (may be by edit this one) – happyZZR1400 Mar 23 '17 at 09:04
  • It's odd. When trying to spy on the mock directly, it fails for me. I need to spy on the mock from the component, like in @happyZZR1400 example. Not sure why this is. Another problem is the catch is never called for Promise.reject(). You need to use the format `method().then(successFn, errorFn)` – Paul Samsotha Mar 23 '17 at 09:16
  • How can you do `comp.usersService` if `usersService` is a private member of the class `UserComponent`? – mario595 Mar 23 '17 at 18:51
  • Also, I've debugged it and if I inspect `this.usersService` I can see that it is an actual instance of `UsersService`, not the mock, so apparently, `{ provide: UsersService, useValue: usersService}` is not working. Any ideas why? – mario595 Mar 23 '17 at 18:58
  • @peeskillet "You need to use the format `method().then(successFn, errorFn)`" You are right, I didn't understand what you meant at first and spent hours trying to figure out why the error test wasn't working. The question is why?!?! Is this documented somewhere? – mario595 Mar 25 '17 at 07:50
  • Check out the docs for [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise). It seems an exception needs to be thrown. I guess the `catch` and `errorFn` have different purposes – Paul Samsotha Mar 25 '17 at 07:59
  • _"How can you do comp.usersService if usersService is a private member of the class UserComponent"_ - You could also get it from the TestBed... `Testbed.get(MyService)`. I think that would work also – Paul Samsotha Mar 25 '17 at 08:00
  • I finally used `fixture.debugElement.injector.get(UsersService)` to get the service instance and then spy on it. A bit annoying not being able to just use a mock instead of creating an actual service instance, but at least it works. Thanks for your help! – mario595 Mar 25 '17 at 09:02
  • You can still use the mock. Either with the line of code in your comment or using the `TestBed.get`. it will get the mock, not the real service. As long as the mock is what is actually configured. The `xx.get` just _looks up_ the service, by the _token_ `UserService` (`{ provide: UserService...}`). But the actual instance returned will be whatever you configured (`{... useValue: mockService }`) – Paul Samsotha Mar 25 '17 at 12:06

0 Answers0