具有sinon的Angular 2测试组件 - 组件未定义

时间:2017-03-27 21:21:55

标签: angular karma-runner

我试图比Angular团队的quickstart教程测试一个简单(但更复杂 - 看似)。我试过看了十几篇其他文章,但也许​​是因为"流体"过去6到12个月的ng2框架的性质,现在有相当多的资源似乎已经过时了。

我使用Angular 2版本2.4.10,Typescript,Sinon版本2.1.0和Webpack 2(如果重要的话,也是ag-grid)。

组件代码:

更新了问题,在构造函数中包含了OtherService,我在第一次复制时错过了

import { Component, OnInit } from "@angular/core";
import { GridOptions } from "ag-grid";
import { EventDataService } from "./data-service/event-data.service";
import { OtherService } from "./data-service/other.service";
import { ColumnDefs } from "../shared/event-grid/event-grid-column-defs";
import { Event } from "./event/event.interface";
import { Observable } from "rxjs/Rx";

@Component({
    templateUrl: "./event-list.component.html",
    styleUrls: ["./event-list.component.scss"]
})

export class EventListComponent implements OnInit {

    // grid data & settings
    private gridOptions: GridOptions;
    private columnDefs: any;

    // auto refresh / event-service messaging settings
    public loadingEvents: boolean;

    // main data array = holds event list displayed by grid
    private events: Event[];

    // updated question with privateOtherService, which I had missed when I first copied this over
    constructor(private eventDataService: EventDataService, private otherService: OtherService) {

        // initialize grid
        this.gridOptions = <GridOptions>{};
        this.gridOptions.columnDefs = ColumnDefs;

        // initialize flag to indicate we are waiting for events from service
        this.loadingEvents = false;
    }

    beginPollingLoop(): void {
        this.getEvents();

        // ... other logic that will repeat the getEvents call periodically...
    };

    getEvents() {
        this.loadingEvents = true;

        // treats response from event service as an observable to subscribe to
        return this.eventDataService.getEvents()
            .subscribe(
            (events: Event[]) => { this.events = events; },
            (error: any) => // handle errors,
            () => {this.loadingEvents = false; });
    };

    ngOnInit(): void {
        // begin polling loop (using defaults) once component loads
        this.beginPollingLoop();
    }
}    

规范代码:

import { ComponentFixture, TestBed } from "@angular/core/testing";
import { expect } from "chai";
import { spy } from "sinon";
import { EventListComponent } from "./event-list.component";

// dependency of component
import { EventDataService } from "./data-service/event-data.service";
import { AgGridModule } from "ag-grid-angular/main";

let component: EventListComponent;
let fixture: ComponentFixture<EventListComponent>;

let spies = {
    beginPollingLoop: {}
};

let eventServiceStub = {
    getEvents: Observable.from([])
};

describe("EventListComponent", () => {

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [AgGridModule.withComponents([])],
            declarations: [ EventListComponent ],
            providers: [{ provide: EventDataService, useValue: eventServiceStub }]
        });
        fixture = TestBed.createComponent(EventListComponent);
        component = fixture.componentInstance; // component is undefined

        spies.beginPollingLoop = spy(component, "beginPollingLoop");
    });

    describe("EventListComponent", () => {
        describe("When the component initializes", () => {
            it("should set loadingEvents to 'false'", () => {
                expect(component.loadingEvents).to.be.true;
            });
        });

        describe("when OnInit() runs", () => {
            let beginPollingLoop = spy(component, "beginPollingLoop");
            expect(beginPollingLoop.called).to.equal(true);
        });    
    });
});

我在我的控制台中遇到的具体错误是&#34; Uncaught TypeError:无法读取属性&#39; beginPollingLoop&#39;未定义&#34;。根据调试器,component是未定义的。在我的屏幕上,Karma的测试输出错误信息是:&#34; TypeError:无法读取属性&#39;进样器&#39; of null&#34;

我觉得我正在按照文档的说明构建Testbed,所以我只能假设我不能正确地注册我的组件的所有依赖项。这导致我的component无法正确创建。

谢谢!

1 个答案:

答案 0 :(得分:1)

我想出了这个问题。在规范中,component是“未定义的”,因为当TestBed尝试创建component时,它失败了,因为我在EventListComponent的构造函数中使用了其他服务我的规格中没有考虑到这一点。一旦我意识到这一点,并在我的规范中删除了该服务,该组件创建良好。

这就是问题的根源 - 我只是没有看到它,因为Angular抛出的错误被埋没在它自己的代码深处。而不是像“TestBed无法创建组件:构造函数参数不匹配”或其他有用的东西,我看到与其他事情有关的错误试图使用我认为已成功创建的组件。这使得不清楚组件是否已经创建,并且为什么它已经失败了:我创建的组件没有被提供给构造函数所期望的参数。

所以最终规范看起来像:

import { ComponentFixture, TestBed } from "@angular/core/testing";
import { expect } from "chai";
import { spy } from "sinon";
import { EventListComponent } from "./event-list.component";

// dependency of component
import { EventDataService } from "./data-service/event-data.service";
import { OtherService } from "./data-service/other.service";

let component: EventListComponent;
let fixture: ComponentFixture<EventListComponent>;

let eventServiceStub = {
    getEvents: Observable.from([])
};

// forgot this one
let otherServiceStub = {
    getStuff: () => {}
};

describe("EventListComponent", () => {

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [],
            declarations: [ EventListComponent ],
            providers: [
                { provide: EventDataService, useValue: eventServiceStub },
                { provide: OtherDataService, useValue: otherServiceStub } // this was missing
            ]
        });
        fixture = TestBed.createComponent(EventListComponent);
        component = fixture.componentInstance; // component is undefined
    });

    describe("EventListComponent", () => {
        describe("when OnInit() runs", () => {
            let beginPollingLoop = spy(component, "beginPollingLoop");
                expect(beginPollingLoop.called).to.equal(true);
            });    
        });
    });
});