Tomer Almog
Tomer Almog

Reputation: 3868

Angular 2 - Testing components with Router and routeParams in constructor

When trying to test a component with routeParams or router in the constructor one gets error:

No provider for RouteParams

Here is my component example:

@Component({
  selector: 'memory',
  template: '',  
})
export class TestedComponent {
  constructor(
    private _someService: SomeService,
    private _routeParams: RouteParams,
    private _router: Router
  ) {
    this.whatever = this._someService.find(this._routeParams.get('id'));
  }
}

It took me a lot of time to find this solution, and I would like to share it!

Upvotes: 1

Views: 1186

Answers (1)

Tomer Almog
Tomer Almog

Reputation: 3868

So we need to mock the router. I have created a separate file called mockRouter.ts:

import {provide} from 'angular2/core';
import {
  Location,
  LocationStrategy,
  ComponentInstruction,
  Router,
  RouteParams
} from 'angular2/router';
import {ResolvedInstruction} from 'angular2/src/router/instruction';
import {SpyObject} from 'angular2/testing_internal';

export class MockRouteParams extends SpyObject {
  private ROUTE_PARAMS = {};

  constructor() { super(RouteParams); }

  set(key: string, value: string) {
    this.ROUTE_PARAMS[key] = value;
  }

  get(key: string) {
    return this.ROUTE_PARAMS[key];
  }
}

export class MockRouter extends SpyObject {
  constructor() { super(Router); }
  isRouteActive(s) { return true; }
  generate(s) {
    return new ResolvedInstruction(new ComponentInstruction('detail', [], null, null, true, '0'), null, {});
  }
}
export class MockLocationStrategy extends SpyObject {
  constructor() { super(LocationStrategy); }
}
export class MockLocation extends SpyObject {
  constructor() { super(Location); }
}

export class MockRouterProvider {
  mockRouter: MockRouter = new MockRouter();
  mockRouteParams: MockRouteParams = new MockRouteParams();
  mockLocationStrategy: MockLocationStrategy = new MockLocationStrategy();
  mockLocation: MockLocation = new MockLocation();

  setRouteParam(key: string, value: any) {
    this.mockRouteParams.set(key, value);
  }

  getProviders(): Array<any> {
    return [
      provide(Router, {useValue: this.mockRouter}),
      provide(RouteParams, {useValue: this.mockRouteParams}),
      provide(Location, {useValue: this.mockLocation}),
      provide(LocationStrategy, {useValue: this.mockLocationStrategy})
    ];
  }
}

Then in my tests I did:

import{MockRouterProvider} from '../services/specs/mockRouter';
describe('Tested component', () => {
  let mockRouterProvider = new MockRouterProvider();
  beforeEachProviders(() => [
    TestedComponent,
    ...all others,

    HTTP_PROVIDERS,
    mockRouterProvider.getProviders(),

  ]);

  let tcb: TestComponentBuilder;

  beforeEach(
    inject(
      [TestComponentBuilder, FakerService], (...injectables) => {
        [tcb] = injectables;
      }
    )
  );
  it('should render',
    injectAsync([], () => {

      mockRouterProvider.setRouteParam('id', '1');
      return tcb.createAsync(MemoryComponent)
        .then((componentFixture) => {
          componentFixture.detectChanges();
          let compiled = componentFixture.nativeElement;

          expect(compiled.firstChild).toHaveCssClass('tested-wrapper');

          componentFixture.destroy();
        }).catch((e) => {
          expect(true).toBeFalsy(`Error: ${e.message}`);
        });
    })
  );

Hope this helps out!

Upvotes: 1

Related Questions