Kje*_*dal 6 unit-testing typescript angular
我正在Angular 2 RC4中实现一个向导组件,现在我正在尝试编写som单元测试.Angular 2中的单元测试开始得到很好的记录,但我根本无法找到如何在组件中模拟内容查询的结果.
该应用程序有2个组件(除app组件外),WizardComponent和WizardStepComponent.应用程序组件(app.ts)定义向导及其模板中的步骤:
<div>
<fa-wizard>
<fa-wizard-step stepTitle="First step">step 1 content</fa-wizard-step>
<fa-wizard-step stepTitle="Second step">step 2 content</fa-wizard-step>
<fa-wizard-step stepTitle="Third step">step 3 content</fa-wizard-step>
</fa-wizard>
</div>
Run Code Online (Sandbox Code Playgroud)
WizardComponent(wizard-component.ts)通过使用ContentChildren查询获取对步骤的引用.
@Component({
selector: 'fa-wizard',
template: `<div *ngFor="let step of steps">
<ng-content></ng-content>
</div>
<div><button (click)="cycleSteps()">Cycle steps</button></div>`
})
export class WizardComponent implements AfterContentInit {
@ContentChildren(WizardStepComponent) steps: QueryList<WizardStepComponent>;
....
}
Run Code Online (Sandbox Code Playgroud)
问题是如何在单元测试中模拟steps变量:
describe('Wizard component', () => {
it('should set first step active on init', async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.createAsync(WizardComponent)
.then( (fixture) =>{
let nativeElement = fixture.nativeElement;
let testComponent: WizardComponent = fixture.componentInstance;
//how to initialize testComponent.steps with mock data?
fixture.detectChanges();
expect(fixture.componentInstance.steps[0].active).toBe(true);
});
})));
});
Run Code Online (Sandbox Code Playgroud)
我创建了一个plunker实现了一个非常简单的向导来演示这个问题.wizard-component.spec.ts文件包含单元测试.
如果有人能指出我正确的方向,我将非常感激.
Kje*_*dal 20
感谢drewmoore在这个问题上的答案,我已经能够实现这一点.
关键是要创建一个用于测试的包装器组件,它指定向导和向导在其模板中的步骤.然后,Angular将为您执行内容查询并填充变量.
编辑:实现适用于Angular 6.0.0-beta.3
我的完整测试实现如下所示:
//We need to wrap the WizardComponent in this component when testing, to have the wizard steps initialized
@Component({
selector: 'test-cmp',
template: `<fa-wizard>
<fa-wizard-step stepTitle="step1"></fa-wizard-step>
<fa-wizard-step stepTitle="step2"></fa-wizard-step>
</fa-wizard>`,
})
class TestWrapperComponent { }
describe('Wizard component', () => {
let component: WizardComponent;
let fixture: ComponentFixture<TestWrapperComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
schemas: [ NO_ERRORS_SCHEMA ],
declarations: [
TestWrapperComponent,
WizardComponent,
WizardStepComponent
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestWrapperComponent);
component = fixture.debugElement.children[0].componentInstance;
});
it('should set first step active on init', () => {
expect(component.steps[0].active).toBe(true);
expect(component.steps.length).toBe(3);
});
});
Run Code Online (Sandbox Code Playgroud)
如果您有更好的/其他解决方案,我们非常欢迎您添加答案.我会把这个问题留一段时间.
对于最近遇到这个问题的任何人,情况略有变化,有一种不同的方法可以做到这一点,我觉得这更容易一些。它是不同的,因为它使用模板引用并 @ViewChild访问被测组件而不是fixture.debugElement.children[0].componentInstance. 此外,语法也发生了变化。
假设我们有一个 select 组件,它需要传入一个选项模板。ngAfterContentInit如果没有提供该选项模板,我们想测试我们的方法是否会抛出错误。
这是该组件的最小版本:
@Component({
selector: 'my-select',
template: `
<div>
<ng-template
*ngFor="let option of options"
[ngTemplateOutlet]="optionTemplate"
[ngOutletContext]="{$implicit: option}">
</ng-template>
</div>
`
})
export class MySelectComponent<T> implements AfterContentInit {
@Input() options: T[];
@ContentChild('option') optionTemplate: TemplateRef<any>;
ngAfterContentInit() {
if (!this.optionTemplate) {
throw new Error('Missing option template!');
}
}
}
Run Code Online (Sandbox Code Playgroud)
首先,创建一个WrapperComponent包含被测组件的文件,如下所示:
@Component({
template: `
<my-select [options]="[1, 2, 3]">
<ng-template #option let-number>
<p>{{ number }}</p>
</ng-template>
</my-select>
`
})
class WrapperComponent {
@ViewChild(MySelectComponent) mySelect: MySelectComponent<number>;
}
Run Code Online (Sandbox Code Playgroud)
注意@ViewChild在测试组件中使用装饰器。这允许MySelectComponent按名称作为TestComponent类的属性进行访问。然后在测试设置中,同时声明TestComponent和MySelectComponent.
describe('MySelectComponent', () => {
let component: MySelectComponent<number>;
let fixture: ComponentFixture<WrapperComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
/*
Declare both the TestComponent and the component you want to
test.
*/
declarations: [
TestComponent,
MySelectComponent
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WrapperComponent);
/*
Access the component you really want to test via the
ElementRef property on the WrapperComponent.
*/
component = fixture.componentInstance.mySelect;
});
/*
Then test the component as normal.
*/
describe('ngAfterContentInit', () => {
component.optionTemplate = undefined;
expect(() => component.ngAfterContentInit())
.toThrowError('Missing option template!');
});
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7332 次 |
| 最近记录: |