我通过克隆angular2-seed创建了一个新的Angular 2项目。我能够创建一个SearchComponent
及其相关模板,并在我的浏览器中运行它。
这是我的search.component.ts
:
import {Component} from 'angular2/core';
import {CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/common';
import {ROUTER_DIRECTIVES, RouteParams} from 'angular2/router';
import {Person, SearchService} from '../../shared/services/search.service';
@Component({
selector: 'sd-search',
moduleId: module.id,
templateUrl: './search.component.html',
directives: [FORM_DIRECTIVES, CORE_DIRECTIVES, ROUTER_DIRECTIVES]
})
export class SearchComponent {
loading: boolean;
query: string;
searchResults: Array<Person>;
constructor(public searchService: SearchService, params: RouteParams) {
if (params.get('term')) {
this.query = decodeURIComponent(params.get('term'));
this.search();
}
}
search(): void {
this.searchService.search(this.query).subscribe(
data => {this.searchResults = data;},
error => console.log(error)
);
}
}
这是我的search.component.html
:
<h2>Search</h2>
<form>
<input type="search" [(ngModel)]="query" (keyup.enter)="search()">
<button type="button" (click)="search()">Search</button>
</form>
<div *ngIf="loading">loading...</div>
<table *ngIf="searchResults">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr *ngFor="#person of searchResults; #i=index">
<td>{{person.name}}</td>
<td>{{person.phone}}</td>
<td>{{person.address.street}}<br/>
{{person.address.city}}, {{person.address.state}} {{person.address.zip}}
</td>
</tr>
</tbody>
</table>
现在我正在尝试创建单元测试以验证此组件的工作原理。据我所知,angular2-seed要求你有export main function()
缠绕根describe
。见https://github.com/mgechev/angular2-seed/blob/master/test-main.js#L50
以下是search.component.spec.ts
我正在努力工作:
import {
it,
describe,
expect,
injectAsync,
beforeEachProviders,
TestComponentBuilder,
} from 'angular2/testing';
import {MockRouterProvider} from '../../shared/services/mocks/routes';
import {MockSearchService} from '../../shared/services/mocks/search.service';
import {SearchComponent} from './search.component';
export function main() {
describe('Search component', () => {
var mockSearchService:MockSearchService;
var mockRouterProvider:MockRouterProvider;
beforeEachProviders(() => {
mockSearchService = new MockSearchService();
mockRouterProvider = new MockRouterProvider();
return [
mockSearchService.getProviders(), mockRouterProvider.getProviders()
];
});
it('should search when a term is set and search() is called', injectAsync([TestComponentBuilder], (tcb) => {
return tcb.createAsync(SearchComponent).then((fixture) => {
let searchComponent = fixture.debugElement.children[0].componentInstance;
searchComponent.query = 'M';
searchComponent.search();
expect(mockSearchService.searchSpy).toHaveBeenCalledWith('M');
});
}));
it('should search automatically when a term is on the URL', injectAsync([TestComponentBuilder], (tcb) => {
mockRouterProvider.setRouteParam('term', 'peyton');
return tcb.createAsync(SearchComponent).then((fixture) => {
fixture.detectChanges();
expect(mockSearchService.searchSpy).toHaveBeenCalledWith('peyton');
});
}));
});
}
Mock *类基于我在ng-book2中找到的示例。
奇怪的是我在项目中运行npm test
时看到的错误。
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR: Error{stack: null, originalErr: ReferenceError{stack: '
eval code
eval@[native code]
__exec@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:1419:16
execute@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3824:22
linkDynamicModule@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3153:36
getModule@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3121:26
http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3157:25
require@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3791:34
eval code
eval@[native code]
__exec@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:1419:16
execute@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3824:22
linkDynamicModule@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3153:36
link@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:2996:28
execute@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:3333:17
doDynamicExecute@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:727:32
link@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:929:36
doLink@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:581:11
updateLinkSetOnLoad@http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:629:24
http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef:441:30
run@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:1217:29
zoneBoundFn@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:1194:29
lib$es6$promise$$internal$$tryCatch@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:442:25
lib$es6$promise$$internal$$invokeCallback@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:454:53
lib$es6$promise$$internal$$publish@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:425:53
http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:97:12
run@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:1217:29
zoneBoundFn@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:1194:29
lib$es6$promise$asap$$flush@http://localhost:9877/base/node_modules/zone.js/dist/zone-microtask.js?572d97c64312c5d52018e95b072a38b5443b057e:236:18', line: 9}, line: 752, sourceURL: 'http://localhost:9877/base/node_modules/systemjs/dist/system.src.js?4db5a6e7fcabd81638571091a65db6438de248ef'}
ERROR: Error{originalErr: ReferenceError{}}
知道我做错了什么吗?
答案 0 :(得分:0)
我的MockSearchService缺少导入和初始化间谍的构造函数。改变它:
export class MockSearchService extends SpyObject {
getAllSpy;
getByIdSpy;
searchSpy;
saveSpy;
mockObservable;
fakeResponse;
subscribe(callback) {
callback(this.fakeResponse);
}
setResponse(json: any): void {
this.fakeResponse = json;
}
getProviders(): Array<any> {
return [provide(SearchService, {useValue: this})];
}
}
为:
import {provide} from 'angular2/core';
import {SpyObject} from 'angular2/testing_internal';
import {SearchService} from '../search.service';
export class MockSearchService extends SpyObject {
getAllSpy;
getByIdSpy;
searchSpy;
saveSpy;
fakeResponse;
constructor() {
super(SearchService);
this.fakeResponse = null;
this.getAllSpy = this.spy('getAll').andReturn(this);
this.getByIdSpy = this.spy('get').andReturn(this);
this.searchSpy = this.spy('search').andReturn(this);
this.saveSpy = this.spy('save').andReturn(this);
}
subscribe(callback) {
callback(this.fakeResponse);
}
setResponse(json: any): void {
this.fakeResponse = json;
}
getProviders(): Array<any> {
return [provide(SearchService, {useValue: this})];
}
}
导致我收到正确的错误消息。