我正试图在使用rxjs auditTime
方法的angular4/typescript茉莉花单元测试中测试.subscribe
块内部的值。我读过很多类似于这篇文章的帖子,但似乎都没有让我进入这个圈子。
我有以下示例组件:
地址.组件.ts:
export class AddressComponent implements OnInit {
public form: FormGroup;
constructor (
private fb: FormBuilder
) {}
public ngOnInit (): void {
this.createForm();
}
public createForm (): void {
this.form = this.fb.group({
lineOne: [this.address.lineOne],
});
this.form.valueChanges.auditTime(500).subscribe(() => {
this.address.lineOne = this.form.value.lineOne;
});
}
}
address.component.html:
<div class="address">
<form [formGroup]="form">
<div class="row">
<div class="col-12 address-body">
<div class="form-group-main">
<div class="row">
<div class="address-input col-12">
<label for="address-line-one" [class.required]="isMandatory">Address Line 1</label>
<input class="form-control" id="address-line-one" type="text" formControlName="lineOne">
</div>
</div>
</div>
</div>
<div class="col-12 address-body">
<display-address [body]="address.lineOne"></display-address>
</div>
<div class="col-12">
<button class="btn btn-full-width btn-primary btn-sm btn-edit" id="address-edit" type="button" (click)="...">Edit</button>
</div>
</div>
</form>
</div>
地址.组件.规范:
describe('Address Component', () => {
let component: AddressComponent;
let fixture: ComponentFixture<AddressComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AddressComponent],
imports: [ReactiveFormsModule],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AddressComponent);
component = fixture.componentInstance;
});
}));
it('should update address', fakeAsync(() => {
component.address = {lineOne: 'street'};
fixture.detectChanges();
//do something..
}));
});
假设上面的设置是正确的,并且我没有错过一些显而易见的东西,这就是为什么我的测试从来没有提供正确的结果,我尝试用以下想法修改我的测试:
监视auditTime并通过呼叫
spyOn(component.form.valueChanges, 'auditTime').and.callThrough();
监视auditTime并调用伪函数:
spyOn(component.form.valueChanges,'auditTime').and.callFake(()=> {
return {
subscribe: () => {}
}
});
监视auditTime并返回值Observable.of:
spyOn(component.form.valueChanges,'auditTime').and.returnValue(Observable.of('hello'));
直接调用:
component.form.valueChanges.auditTime().subscribe(result => {
//never get in here
});
尝试使用:tick()
等待,并尝试使用:flushMicrotasks()
刷新。
监视createForm函数:
spyOn(component, 'createForm').and.callFake(() => {
return Observable.of('hello');
});
如果我使用以下内容,使用debugElement访问和更新lineOne总是返回错误:
const el = fixture.nativeElement.querySelector(By.css('#address-line-one'));
el.value = 'something';
el.dispatchEvent(new Event('input'));
fixture.detectChanges();
看起来它只能看到html和<display-address></display-address>
的编辑按钮,这表明它当时可能还没有编译。
我还试着把所有东西都包起来:
fixture.whenStable().then(() => {
// do something..
});
现在我已经无计可施了,如果有人能理解以上内容并为我指明正确的方向,那就太好了。。
解决方案
多亏了Amir,在这个特殊的例子中,我似乎想得太多了,而使用NO_ERRORS_SCHEMA
隐藏了真正的问题。事实证明,我需要导入<display-address>
所需的组件:
imports: [ReactiveFormsModule, DisplayAddressComponent],
这允许模板正确编译,这意味着我可以看到所有的表单值,而不仅仅是<display-address>
。根据建议,我使用fakeAsync
和tick(600)
的组合来发射形式的变化:
it('should update address', fakeAsync(() => {
component.address = {lineOne: 'street'};
fixture.detectChanges();
expect(component.address.lineOne).toBe('street');
component.form.controls['lineOne'].setValue('test');
tick(600);
expect(component.address.lineOne).toBe('test');
}));
如果有人有类似的问题。
好的,我将在这里发布我的假设,检查它是否有帮助:
- 直接调用ngOnInit()或在创建组件
- 只有当您使用fakeAsync+tick(600)时,测试才能同步工作
- 执行tick(600)后,尝试将值发送到this.form.valueChanges,您可以通过替换FormBuilder使其返回具有您自己的发射器(主题)的对象,或者通过html中查找元素并使用DOM事件输入值来实现这一点
- 如果您决定使用html进行输入,则删除NO_ERRORS_SCHEMA并查看它是否因为某些错误而未呈现(因为您说过html的该部分不存在)