Подтвердить что ты не робот

Angular 2 Final Release Router Unit Test

Как я unit test маршрутизаторы в Angular версии 2.0.0 с кармой и жасмином?

Здесь мой старый unit test выглядит как в версии 2.0.0-beta.14

import {
  it,
  inject,
  injectAsync,
  beforeEach,
  beforeEachProviders,
  TestComponentBuilder
} from 'angular2/testing';

import { RootRouter } from 'angular2/src/router/router';
import { Location, RouteParams, Router, RouteRegistry, ROUTER_PRIMARY_COMPONENT } from 'angular2/router';
import { SpyLocation } from 'angular2/src/mock/location_mock';
import { provide } from 'angular2/core';

import { App } from './app';

describe('Router', () => {

  let location, router;

  beforeEachProviders(() => [
    RouteRegistry,
    provide(Location, {useClass: SpyLocation}),
    provide(Router, {useClass: RootRouter}),
    provide(ROUTER_PRIMARY_COMPONENT, {useValue: App})
  ]);

  beforeEach(inject([Router, Location], (_router, _location) => {
    router = _router;
    location = _location;
  }));

  it('Should be able to navigate to Home', done => {
    router.navigate(['Home']).then(() => {
      expect(location.path()).toBe('');
      done();
    }).catch(e => done.fail(e));
  });

});
4b9b3361

Ответ 1

Для тестирования мы теперь создаем модуль тестирования, используя TestBed. Мы можем использовать его TestBed#configureTestingModule и передать ему объект метаданных так же, как мы переходим к @NgModule

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [ /* modules to import */ ],
    providers: [ /* add providers */ ],
    declarations: [ /* components, directives, and pipes */ ]
  });
});

Для маршрутизации вместо обычного RouterModule вместо этого мы будем использовать RouterTestingModule. Это устанавливает Router и Location, поэтому вам не нужно самостоятельно. Вы также можете передавать маршруты к нему, вызывая RouterTestingModule.withRoutes(Routes)

TestBed.configureTestingModule({
  imports: [
    RouterTestingModule.withRoutes([
      { path: 'home', component: DummyComponent }
    ])
  ]
})

Чтобы получить Location и Router в тесте, то же самое работает, как и в вашем примере.

let router, location;

beforeEach(() => {
  TestBed...
});

beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
  router = _router;
  location = _location;
}));

Вы также можете при необходимости вводить в каждый тест

it('should go home',
    async(inject([Router, Location], (router: Router, location: Location) => {
})));

async выше используется как done, за исключением того, что нам не нужно явно вызывать done. Angular на самом деле сделает это для нас после завершения асинхронных задач вызова.

Другой способ получить провайдеров - это тестовая кровать.

let location, router;

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [RouterTestingModule.withRoutes([
      { path: 'home', component: DummyComponent }
    ])],
  });
  let injector = getTestBed();
  location = injector.get(Location);
  router = injector.get(Router);
});

Здесь полный тест, рефакторинг вашего примера

import { Component } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { fakeAsync, async, inject, TestBed, getTestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

@Component({
  template: `
    <router-outlet></router-outlet>
  `
})
class RoutingComponent { }

@Component({
  template: ''
})
class DummyComponent { }

describe('component: RoutingComponent', () => {
  let location, router;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule.withRoutes([
        { path: 'home', component: DummyComponent }
      ])],
      declarations: [RoutingComponent, DummyComponent]
    });
  });

  beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
    location = _location;
    router = _router;
  }));

  it('should go home', async(() => {
    let fixture = TestBed.createComponent(RoutingComponent);
    fixture.detectChanges();
    router.navigate(['/home']).then(() => {
      expect(location.path()).toBe('/home');
      console.log('after expect');
    });
  }));
});

UPDATE

Кроме того, если вы хотите просто издеваться над маршрутизатором, который на самом деле может быть лучшим способом в unit test, вы могли бы просто сделать

let routerStub;

beforeEach(() => {
  routerStub = {
    navigate: jasmine.createSpy('navigate'),
  };
  TestBed.configureTestingModule({
    providers: [ { provide: Router, useValue: routerStub } ],
  });
});

И в ваших тестах все, что вы хотите сделать, это проверить, что заглушка вызывается с правильным аргументом, когда компонент взаимодействует с ним

expect(routerStub.navigate).toHaveBeenCalledWith(['/route']);

Если вы действительно не хотите протестировать некоторую маршрутизацию, это, вероятно, предпочтительный путь. Не нужно настраивать маршрутизацию. В unit test, если вы используете настоящую маршрутизацию, вы включаете ненужные побочные эффекты, которые могут повлиять на то, что вы действительно пытаетесь протестировать, а это просто поведение компонента. А поведение компонента состоит в том, чтобы просто вызвать метод navigate. Нет необходимости проверять, работает ли маршрутизатор. Angular уже гарантирует это.