12

As Angular team is constantly upgrading/deprecating stuff in Angular 2 RC versions I encountered this problem.

I have a component that has a Dependency Injection (DI), which is actually a service (UserService in this case). This UserService of course has some DIs of its own. After updating to the latest RC4 of Angular 2 I realised that I cannot create similar tests any more.

So as the docs are not mentioning something relative here's my code (simplified for this question).

My component:

import { Component } from '@angular/core';
import { MdButton } from '@angular2-material/button';
import {
  MdIcon,
  MdIconRegistry
} from '@angular2-material/icon';
import { UserService } from '../../services/index';

@Component({
  moduleId: module.id,
  selector: 'logout-button',
  templateUrl: 'logout-button.component.html',
  styleUrls: ['logout-button.component.css'],
  providers: [MdIconRegistry, UserService],
  directives: [MdButton, MdIcon]
})
export class LogoutButtonComponent {

  constructor(public userService: UserService) {}

  /**
   * Call UserService and logout() method
   */
  logout() {
    this.userService.logout();
  }

}

Component's DI, UserService whic as you can see has some DIs (Router, AuthHttp & Http):

import { Injectable } from '@angular/core';
import {
  Http,
  Headers
} from '@angular/http';
import {
  AuthHttp,
  JwtHelper
} from 'angular2-jwt';
import { Router } from '@angular/router';
import { UMS } from '../common/index';

@Injectable()
export class UserService {

  constructor(
    private router: Router,
    private authHttp: AuthHttp,
    private http: Http) {

      this.router = router;
      this.authHttp = authHttp;
      this.http = http;
    }

    /**
     * Logs out user
     */
    public logout() {
      this.authHttp.get(UMS.url + UMS.apis.logout)
      .subscribe(
        data => this.logoutSuccess(),
        err => this.logoutSuccess()
      );
    }

}

And here's the test for the component:

import { By }           from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import {
  beforeEach,
  beforeEachProviders,
  describe,
  expect,
  it,
  inject,
  fakeAsync,
  TestComponentBuilder
} from '@angular/core/testing';

import { AuthHttp } from 'angular2-jwt';
import { Router } from '@angular/router';
import { Http } from '@angular/http';
import { LogoutButtonComponent } from './logout-button.component';
import { UserService } from '../../services/index';

describe('Component: LogoutButtonComponent', () => {



  beforeEachProviders(() => [
    LogoutButtonComponent,
    UserService
  ]);

  it('should inject UserService', inject([LogoutButtonComponent],
    (component: LogoutButtonComponent) => {
      expect(component).toBeTruthy();
  }));

});

Don't worry about the (it) for now.

As you can see I;m adding the related providers on the beforeEachProviders.

In this case I'm getting an error when I run the tests:

Error: No provider for Router! (LogoutButtonComponent -> UserService -> Router)

Which is expected let's say.

So in order to don't get those errors I'm adding the service's DIs in the providers also:

  beforeEachProviders(() => [
    LogoutButtonComponent,
    Router,
    AuthHttp,
    Http,
    UserService
  ]);

But now I'm, getting this error:

Error: Cannot resolve all parameters for 'Router'(?, ?, ?, ?, ?, ?, ?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Router' is decorated with Injectable.

I'm really trying to figure out what's happening so I found some related answers here but ALL are outdated and covers the old router-deprecated or angular2/router but both are deprecated and are not covering this case.

Would love some help on this and maybe some resources as I cannot find anything related to the latest version of Router: "@angular/router": "3.0.0-beta.2", and RC4.

Thanks

UPDATE!

I manage to bypass the two errors above and now I can access the component. Here's the description code:

describe('Component: LogoutButtonComponent', () => {

  let component: LogoutButtonComponent;
  let router: any = Router;
  let authHttp: any = AuthHttp;
  let http: any = Http;
  let service: any = new UserService(router, authHttp, http);

  beforeEachProviders(() => [
    LogoutButtonComponent
  ]);

  beforeEach(() => {
    component = new LogoutButtonComponent(service);
  });

  it('should inject UserService', () => {
    expect(component.userService).toBeTruthy();
  });

  it('should logout user', () => {
    localStorage.setItem('token', 'FOO');
    component.logout();
    expect(localStorage.getItem('token')).toBeUndefined();
  });

});

But it seems that even that the DI service is injected and accessible the DIs of the service are not. So now I get this error:

TypeError: this.authHttp.get is not a function

Any ideas?

3
  • I am having similar issues with getting a service that uses http from within a jasmine test. Unfortunately, I haven't found much in the way of documentation on these types of tests with the latest RC. Commented Jul 27, 2016 at 18:59
  • Did you try using a mock for UserService and Router? Commented Aug 3, 2016 at 7:03
  • @tymspy Sorry because of lots of things to do, not yet. but thanks, when I'm gonna try it I'll inform you about the results. Commented Aug 5, 2016 at 7:47

2 Answers 2

3

It looks like you were experiencing a dependencies loop problem, because your UserSerivce also need inject AuthHttp, Http, etc... it really will be disturb once if you need test your component. My way is just create a mock UserSerivce and return the expect mocked value through UserService.logout() method, because you don't have to know what really happened in UserService, all you need is just a return value:

let MockUserService = {
  logout() {
    // return some value you need 
  }
}

Then, in test suite:

import { provide } from '@angular/core'

beforeEachProviders(() => [
  provide(UserService, {useClass: MockUserService})
])

... detail test code here

I hope this works for you. And here is a post that helps me a lot: https://developers.livechatinc.com/blog/testing-angular-2-apps-dependency-injection-and-components/

Sign up to request clarification or add additional context in comments.

Comments

0

With RC4, some workarounds are needed to use http in a test. See also this issue (should be fixed in RC5):

https://github.com/angular/angular/issues/9294

Adding this to my unit-tests.html fixed it for me:

System.import('@angular/platform-browser/src/browser/browser_adapter').then(function(browser_adapter) {
    browser_adapter.BrowserDomAdapter.makeCurrent();
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.