角2 - 单元测试结合嵌套自定义窗体控件
问题描述:
我得从选择app-date-picker
控件的自定义。它实现了ControlValueAccessor
。我有一个名为MyPage
组件包含通过这种自定义窗体控件:角2 - 单元测试结合嵌套自定义窗体控件
<app-date-picker class="address__from-date" [(ngModel)]="fromDate"></app-date-picker>
我试图写一个单元测试MyPage
,测试的结合两个方向。我这样做对其他表单字段就好了,例如:当我为我的自定义窗体控件做到这一点
it('should bind zip code', fakeAsync(() => {
const formControl = element.query(By.css('.address__zip-code input')).nativeElement;
// model -> view
component.zipCode = 76777;
fixture.detectChanges();
tick();
expect(formControl.value).toEqual('76777');
// view -> model
formControl.value = '89556';
formControl.dispatchEvent(new Event('input'));
expect(component.zipCode).toEqual(89556);
}));
我的问题就出现了。到目前为止,我只能测试结合的一个方向,即便如此,它是需要使用的ng-reflect-model
,这是很可怕:
it('should bind from-date', fakeAsync(() => {
const formControl = element.query(By.css('.address__from-date app-date-picker')).nativeElement;
// model -> view
component.fromDate = '01/2017';
fixture.detectChanges();
tick();
expect(formControl.attributes['ng-reflect-model'].value).toEqual('01/2017');
// view -> model
// Not sure what to do here either
}));
有没有一种更好的方式去这样做呢?我想:
- 能够测试从
MyPage
单元测试结合两个方向,让我知道我正确连接起来,以表单控件 - 没有使用
ng-reflect-*
其他说明:
的MyPage
组件是一个带有fromDate
(和zipCode
)字段的标准组件。
定制表单字段正确实现ControlValueAccessor
,具有date
场,并且使用<input>
内部,其本身是通过ngModel
约束:
<input [(ngModel)]="date" type="date">
DatePickerComponent
@Component({
selector: 'app-date-picker',
templateUrl: './date-picker.component.html',
styleUrls: ['./date-picker.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerComponent),
multi: true
}]
})
export class DatePickerComponent implements ControlValueAccessor {
private propagateChange = (_: any) => {};
private _date: string;
get date(): string {
return this._date;
}
@Input()
set date(value: string) {
this._date = value;
this.propagateChange(value);
}
writeValue(newValue: any) {
if (newValue !== undefined) {
this.date = newValue;
}
}
registerOnChange(fn: any) {
this.propagateChange = fn;
}
registerOnTouched(fn: any) {
// Not used
}
}
UPDATE 8 /二千零十七分之十
到目前为止,我已经接近了什么,我想@ViewChild
:
@Component(...)
MyPageComponent {
@ViewChild('fromDate') fromDatePicker: DatePickerComponent;
...
}
的MyPage
模板变成(注意模板引用变量#fromDate
):
<app-date-picker #fromDate class="address__from-date" [(ngModel)]="fromDate">
</app-date-picker>
然后测试变为:
it('should bind from-date', fakeAsync(() => {
// model -> view
component.info.fromDate = '01/2017';
fixture.detectChanges();
tick();
expect(component.fromDatePicker.date).toEqual('01/2017');
// view -> model
component.fromDatePicker.date = '02/2017';
expect(component.info.fromDate).toEqual('02/2017');
}));
任何人都知道一个更好的办法?尽管这不是最佳的,但是现在我得到了。
答
好了,终于找到了答案我很高兴,因为它避免了既ng-reflect-*
和@ViewChild
。与其说.nativeElement
的,我可以打电话.componentInstance
。然后测试变得简单:
it('should bind from-date', fakeAsync(() => {
const formControl = element.query(By.css('.address__from-date app-date-picker')).componentInstance;
// model -> view
component.fromDate = '01/2017';
fixture.detectChanges();
tick();
expect(formControl.date).toEqual('01/2017');
// view -> model
formControl.date = '02/2017';
expect(component.fromDate).toEqual('02/2017');
}));
我还是如果任何人有一个更好的解决方案开放,但我会记住这为答案现在。希望它能帮助其他任何人遇到这个问题!