web-dev-qa-db-ja.com

Angular2-コンポーネントでのngOninitのテスト

次のコードのリストコンポーネントがあります。

///<reference path="../../node_modules/angular2/typings/browser.d.ts"/>
import { Component, OnInit } from 'angular2/core';
import { ROUTER_DIRECTIVES } from 'angular2/router';

import { Employee } from '../models/employee';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';

@Component({
  selector: 'employee-list',
  template: `
    <ul class="employees">
  <li *ngFor="#employee of employees">
    <a [routerLink]="['EmployeeDetail', {id: employee.id}]">
      <span class="badge">{{employee.id}}</span>
      {{employee.name}}
    </a>
  </li>
</ul>
  `,
  directives: [ROUTER_DIRECTIVES],
  providers: [EmployeeListServiceComponent]
})

export class EmployeeListComponent implements OnInit {
  public employees: Employee[];
  public errorMessage: string;

  constructor(
    private _listingService: EmployeeListServiceComponent
  ){}

  ngOnInit() {
    this._listingService.getEmployees().subscribe(
                     employees => this.employees = employees,
                     error =>  this.errorMessage = <any>error
                   );
  }
}

ngOninitフックの単体テストを作成したいと思います。私は次のテストを書きました:

/// <reference path="../../typings/main/ambient/jasmine/jasmine.d.ts" />

import {
    it,
    describe,
    expect,
    TestComponentBuilder,
    injectAsync,
    setBaseTestProviders,
    beforeEachProviders,
} from "angular2/testing";
import { Component, provide, ApplicationRef, OnInit } from "angular2/core";
import {
    TEST_BROWSER_PLATFORM_PROVIDERS,
    TEST_BROWSER_APPLICATION_PROVIDERS
} from "angular2/platform/testing/browser";
import {
    ROUTER_DIRECTIVES,
    ROUTER_PROVIDERS,
    ROUTER_PRIMARY_COMPONENT,
    APP_BASE_HREF
} from 'angular2/router';
import {XHRBackend, HTTP_PROVIDERS} from "angular2/http";
import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref';
import {MockBackend } from "angular2/src/http/backends/mock_backend";
import {Observable} from 'rxjs/Rx';
import 'rxjs/Rx';

import { Employee } from '../models/employee';
import { EmployeeListComponent } from './list.component';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';


class MockEmployeeListServiceComponent {

    getEmployees () {
        return Observable.of([
            {
                "id": 1,
                "name": "Abhinav Mishra"
            }
        ]);
    }
}


@Component({
    template: '<employee-list></employee-list>',
    directives: [EmployeeListComponent],
    providers: [MockEmployeeListServiceComponent]
})
class TestMyList {}


describe('Employee List Tests', () => {
    setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);

    beforeEachProviders(() => {
        return [
            ROUTER_DIRECTIVES,
            ROUTER_PROVIDERS,
            HTTP_PROVIDERS,
            provide(EmployeeListServiceComponent, {useClass: MockEmployeeListServiceComponent}),
            provide(XHRBackend, {useClass: MockBackend}),
            provide(APP_BASE_HREF, {useValue: '/'}),
            provide(ROUTER_PRIMARY_COMPONENT, {useValue: EmployeeListComponent}),
            provide(ApplicationRef, {useClass: MockApplicationRef})
        ]
    });

    it('Should be true',
        injectAsync([TestComponentBuilder], (tcb) => {
            return tcb
                .createAsync(TestMyList)
                .then((fixture) => {
                    fixture.detectChanges();
                    var compiled = fixture.debugElement.nativeElement;
                    console.log(compiled.innerHTML);
                    expect(true).toBe(true);
                });
        })
    );
});

ただし、テストでのconsole.logの出力は、次のように空のulタグです。

 '<employee-list>
    <ul class="employees">
  <!--template bindings={}-->
</ul>
  </employee-list>'

コンポーネントフックのユニットテストを書く適切な方法を誰かが私に提案できますか?

[〜#〜]ソリューション[〜#〜]

次のように、injectAsyncブロックのhttpリクエストをモックします。

backend.connections.subscribe(
                (connection:MockConnection) => {
                    var options = new ResponseOptions({
                        body: [
                            {
                                "id": 1,
                                "name": "Abhinav Mishra"
                            }
                        ]
                    });

                    var response = new Response(options);

                    connection.mockRespond(response);
                }
            );

しかし今、私は次のような別のエラーが発生しています:

Failed: EXCEPTION: Component "EmployeeListComponent" has no route config. in [['EmployeeDetail', {id: employee.id}] in EmployeeListComponent@3:7]
        ORIGINAL EXCEPTION: Component "EmployeeListComponent" has no route config.
        ORIGINAL STACKTRACE:
        Error: Component "EmployeeListComponent" has no route config.
9
abhinavmsra

ngOnInit()で非同期コードを呼び出す場合、console.log(...)が実行されたときに非同期コードが完了したとは限りません。 _this.employees_は、応答が到着した後にsubscribe(...)に渡したコールバックが呼び出された場合にのみ設定されます。

MockBackend を使用すると、応答を制御でき、応答が渡された後、fixture.detectChanges()を再度実行して、更新されたデータでコンポーネントを再レンダリングする必要があります。 innerHTMLそして、レンダリングされたコンテンツが含まれていることを期待します。

3