反应式表单模块的 auditTime 方法的订阅块中的测试值



我正试图在使用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>。根据建议,我使用fakeAsynctick(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');
}));

如果有人有类似的问题。

好的,我将在这里发布我的假设,检查它是否有帮助:

  1. 直接调用ngOnInit()或在创建组件
  2. 只有当您使用fakeAsync+tick(600)时,测试才能同步工作
  3. 执行tick(600)后,尝试将值发送到this.form.valueChanges,您可以通过替换FormBuilder使其返回具有您自己的发射器(主题)的对象,或者通过html中查找元素使用DOM事件输入值来实现这一点
  4. 如果您决定使用html进行输入,则删除NO_ERRORS_SCHEMA并查看它是否因为某些错误而未呈现(因为您说过html的该部分不存在)

最新更新