TestComponentBuilder 可以测试组件中的 angular 组件吗?
Can TestComponentBuilder test an angular component within a component?
所以,我正在尝试为我的组件编写单元测试。我的组件是一个动态创建的列表,当用户单击某些项目时,我希望我的测试能够验证组件是否正确生成输出。
为了对此进行测试,我编写了一个演示组件,在其模板中创建我的组件,然后尝试让 TestComponentBuilder 创建该演示组件并单击列表中的项目。不幸的是,我的单元测试用例找不到组件的 html 元素来单击它们。我可以找到演示组件的元素,但测试似乎无法访问我的嵌套组件。
我的问题是:
我能让这种方法起作用吗?
或者是否有更好的方法来对我的组件的输入和输出进行单元测试?
如有任何帮助,我们将不胜感激。这是我正在做的事情:
<== 根据 Gunter 的回答更新 ==>
CustomListComponent.ts(我的组件):
import {Component, EventEmitter} from "angular2/core";
import {CustomListItem} from "./CustomListItem";
@Component({
selector: 'custom-list-component',
inputs: ['itemClass', 'items'],
outputs: ['onChange'],
template: `
<ul class="list-unstyled">
<li *ngFor="#item of items" [hidden]="item.hidden">
<div [class]="itemClass" (click)="onItemClicked(item)">
{{item.text}}
</div>
</li>
</ul>
`
})
export class CustomListComponent {
itemClass: String;
items: CustomListItem[];
onChange: EventEmitter<CustomListItem>;
constructor() {
this.items = new Array<CustomListItem>();
this.onChange = new EventEmitter();
}
onItemClicked(item: CustomListItem): void {
let clone = new CustomListItem(item.text, item.hidden);
this.onChange.emit(clone);
}
}
CustomListItem.ts:
export class CustomListItem {
text: String;
hidden: boolean;
constructor(text: String, hidden: boolean) {
this.text = text;
this.hidden = hidden;
}
}
CustomListSpec.ts(这是我挣扎的地方):
import {CustomListComponent} from './CustomListComponent';
import {ComponentFixture, describe, expect, fakeAsync, inject, injectAsync, it, TestComponentBuilder} from 'angular2/testing'
import {Component} from "angular2/core";
import {CustomListItem} from "./CustomListItem";
import {By} from "angular2/src/platform/dom/debug/by";
describe('CustomListComponent', () => {
var el;
var dropdownToggleBtn, dropdownListEl;
var regularListEl;
it('Event output properly when list item clicked', injectAsync([TestComponentBuilder], (tcb) => {
return createComponent(tcb).then((fixture) => {
console.log("el (" + el + ")"); // => [object HTMLDivElement]
console.log("dropdownToggleBtn (" + dropdownToggleBtn + ")"); // => [object HTMLButtonElement]
console.log("dropdownListContainer(" + dropdownListContainer + ")"); // => [object HTMLDivElement]
console.log("dropdownListEl(" + dropdownListEl + ")"); // => [object HTMLUListElement]
//console.log("regularListEl (" + regularListEl+ ")");
//...further testing...
});
}));
function createComponent(tcb: TestComponentBuilder): Promise<ComponentFixture> {
return tcb.createAsync(CustomListComponentDemo).then((fixture) => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement;
dropdownToggleBtn = fixture.debugElement.query(By.css(".btn")).nativeElement;
dropdownListContainer = fixture.debugElement.query(By.css(".dropdown-menu")).nativeElement;
dropdownListEl = dropdownListContainer.children[0].children[0];
//regularListEl = fixture.debugElement.query(By.css(".list-unstyled")); //TIMES OUT unfortunately. Maybe because there are 2.
return fixture;
})
}
});
@Component({
directives: [CustomListComponent],
template: `
<div class="btn-group" dropdown>
<button id="dropdown-toggle-id" type="button" class="btn btn-light-gray" dropdownToggle>
<i class="glyphicon icon-recent_activity dark-green"></i> Dropdown <span class="caret"></span>
</button>
<div class="dropdown-menu" role="menu" aria-labelledby="dropdown-toggle-id">
<custom-list-component id="dropdown-list-id"
[items]="dropdownListItems" [itemClass]="'dropdown-item'"
(onChange)="onDropdownListChange($event)">
</custom-list-component>
</div>
<span class="divider"> </span>
</div>
<custom-list-component id="regular-list-id"
[items]="regularListItems"
(onChange)="onRegularListChange($event)">
</custom-list-component>
`
})
class CustomListComponentDemo {
dropdownListItems: CustomListItem[];
regularListItems: CustomListItem[];
constructor() {
//intialize the item lists
}
onDropdownListChange(item: CustomListItem): void {
//print something to the console logs
}
onRegularListChange(item: CustomListItem): void {
//print something to the console logs
}
}
在查询动态创建的元素之前调用 detectChanges()
。它们不是在更改检测 运行.
之前创建的
function createComponent(tcb: TestComponentBuilder): Promise<ComponentFixture> {
return tcb.createAsync(CustomListComponentDemo).then((fixture) => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement;
regularListEl = fixture.debugElement.query(By.css(".list-unstyled"));
dropdownListEl = fixture.debugElement.query(By.css(".dropdown-menu")).nativeElement;
dropdownToggleBtn = fixture.debugElement.query(By.css(".btn")).nativeElement;
return fixture;
})
}
所以,我正在尝试为我的组件编写单元测试。我的组件是一个动态创建的列表,当用户单击某些项目时,我希望我的测试能够验证组件是否正确生成输出。
为了对此进行测试,我编写了一个演示组件,在其模板中创建我的组件,然后尝试让 TestComponentBuilder 创建该演示组件并单击列表中的项目。不幸的是,我的单元测试用例找不到组件的 html 元素来单击它们。我可以找到演示组件的元素,但测试似乎无法访问我的嵌套组件。
我的问题是: 我能让这种方法起作用吗? 或者是否有更好的方法来对我的组件的输入和输出进行单元测试?
如有任何帮助,我们将不胜感激。这是我正在做的事情:
<== 根据 Gunter 的回答更新 ==>
CustomListComponent.ts(我的组件):
import {Component, EventEmitter} from "angular2/core";
import {CustomListItem} from "./CustomListItem";
@Component({
selector: 'custom-list-component',
inputs: ['itemClass', 'items'],
outputs: ['onChange'],
template: `
<ul class="list-unstyled">
<li *ngFor="#item of items" [hidden]="item.hidden">
<div [class]="itemClass" (click)="onItemClicked(item)">
{{item.text}}
</div>
</li>
</ul>
`
})
export class CustomListComponent {
itemClass: String;
items: CustomListItem[];
onChange: EventEmitter<CustomListItem>;
constructor() {
this.items = new Array<CustomListItem>();
this.onChange = new EventEmitter();
}
onItemClicked(item: CustomListItem): void {
let clone = new CustomListItem(item.text, item.hidden);
this.onChange.emit(clone);
}
}
CustomListItem.ts:
export class CustomListItem {
text: String;
hidden: boolean;
constructor(text: String, hidden: boolean) {
this.text = text;
this.hidden = hidden;
}
}
CustomListSpec.ts(这是我挣扎的地方):
import {CustomListComponent} from './CustomListComponent';
import {ComponentFixture, describe, expect, fakeAsync, inject, injectAsync, it, TestComponentBuilder} from 'angular2/testing'
import {Component} from "angular2/core";
import {CustomListItem} from "./CustomListItem";
import {By} from "angular2/src/platform/dom/debug/by";
describe('CustomListComponent', () => {
var el;
var dropdownToggleBtn, dropdownListEl;
var regularListEl;
it('Event output properly when list item clicked', injectAsync([TestComponentBuilder], (tcb) => {
return createComponent(tcb).then((fixture) => {
console.log("el (" + el + ")"); // => [object HTMLDivElement]
console.log("dropdownToggleBtn (" + dropdownToggleBtn + ")"); // => [object HTMLButtonElement]
console.log("dropdownListContainer(" + dropdownListContainer + ")"); // => [object HTMLDivElement]
console.log("dropdownListEl(" + dropdownListEl + ")"); // => [object HTMLUListElement]
//console.log("regularListEl (" + regularListEl+ ")");
//...further testing...
});
}));
function createComponent(tcb: TestComponentBuilder): Promise<ComponentFixture> {
return tcb.createAsync(CustomListComponentDemo).then((fixture) => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement;
dropdownToggleBtn = fixture.debugElement.query(By.css(".btn")).nativeElement;
dropdownListContainer = fixture.debugElement.query(By.css(".dropdown-menu")).nativeElement;
dropdownListEl = dropdownListContainer.children[0].children[0];
//regularListEl = fixture.debugElement.query(By.css(".list-unstyled")); //TIMES OUT unfortunately. Maybe because there are 2.
return fixture;
})
}
});
@Component({
directives: [CustomListComponent],
template: `
<div class="btn-group" dropdown>
<button id="dropdown-toggle-id" type="button" class="btn btn-light-gray" dropdownToggle>
<i class="glyphicon icon-recent_activity dark-green"></i> Dropdown <span class="caret"></span>
</button>
<div class="dropdown-menu" role="menu" aria-labelledby="dropdown-toggle-id">
<custom-list-component id="dropdown-list-id"
[items]="dropdownListItems" [itemClass]="'dropdown-item'"
(onChange)="onDropdownListChange($event)">
</custom-list-component>
</div>
<span class="divider"> </span>
</div>
<custom-list-component id="regular-list-id"
[items]="regularListItems"
(onChange)="onRegularListChange($event)">
</custom-list-component>
`
})
class CustomListComponentDemo {
dropdownListItems: CustomListItem[];
regularListItems: CustomListItem[];
constructor() {
//intialize the item lists
}
onDropdownListChange(item: CustomListItem): void {
//print something to the console logs
}
onRegularListChange(item: CustomListItem): void {
//print something to the console logs
}
}
在查询动态创建的元素之前调用 detectChanges()
。它们不是在更改检测 运行.
function createComponent(tcb: TestComponentBuilder): Promise<ComponentFixture> {
return tcb.createAsync(CustomListComponentDemo).then((fixture) => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement;
regularListEl = fixture.debugElement.query(By.css(".list-unstyled"));
dropdownListEl = fixture.debugElement.query(By.css(".dropdown-menu")).nativeElement;
dropdownToggleBtn = fixture.debugElement.query(By.css(".btn")).nativeElement;
return fixture;
})
}