我有一个更改函数,我将传递给一个响应式窗体控件的更改事件,该控件评估脏状态并检查控件上是否有任何错误,如果是,则将布尔标志设置为true / false.然后使用该布尔标志来确定是否显示< div>包含错误消息的元素.这在浏览器中运行得很好,但是当单元测试运行时,“脏”永远不会被设置为true.这是我的代码:
<form [formGroup]="myForm" novalidate> <input id="age" formControlName="age" (change)="onChange()" /> <div id="ageError" *ngIf="ageIsError()"> <label>Age has errored</label> </div> </form>
零件
constructor(private fb: FormBuilder) {} ngOnInit() { this.myForm = this.fb.group({ age: [null,[Validators.min(18)]] }); } onChange() { if (this.ageIsError()) // do something } ageIsError() { return this.myForm.controls.age.hasError('min') && this.myForm.controls.age.dirty; }
单元测试
it('should show error message when age is less than 18',fakeAsync(() => { let age = component.myForm.controls.age; age.setValue('10',{ emitEvent: true }); fixture.detectChanges(); fixture.whenStable().then(() => { let ageError = debugElement.query(By.css('#ageError')).nativeElement; expect(component.ageIsError()).toBe(true); expect(ageError.innerText).toContain('Age has errored'); }); }));
同样,实际的实现在浏览器中工作,但单元测试失败.有没有人知道锄头在茉莉花中发出事件以将控制设置为脏状态,还是有更好的方法来实现这一点?谢谢!
解决方法
在您的示例中,age.setValue(…)实际上为输入设置了正确的值,但它没有将ageError附加到DOM – 因为没有真实/模拟事件将控件标记为脏.这就是为什么方法ageIsError在这种情况下总是返回false.
作为一种解决方法,我只是使用document.createEvent(‘Event’)模拟输入事件,看起来它工作正常:
it('should show error message when age is less than 18',async(() => { const customEvent: Event = document.createEvent('Event'); customEvent.initEvent('input',false,false); const ageInput = fixture.debugElement.query(By.css('input#age')).nativeElement; ageInput.value = 10; ageInput.dispatchEvent(customEvent); fixture.detectChanges(); fixture.whenStable().then(() => { let ageError = fixture.debugElement.query(By.css('#ageError')).nativeElement; expect(component.ageIsError()).toBe(true); expect(ageError.innerText).toContain('Age has errored'); }); }));
我还找到了解决方案的修复程序 – 只需在detectChanges之前调用age.markAsDirty():
it('should show error message when age is less than 18',async(() => { let age = component.myForm.controls.age; age.setValue('10'); // { emitEvent: true } is by default age.markAsDirty(); // add this line fixture.detectChanges(); fixture.whenStable().then(() => { let ageError = fixture.debugElement.query(By.css('#ageError')).nativeElement; expect(component.ageIsError()).toBe(true); expect(ageError.innerText).toContain('Age has errored'); }); }));
我还创建了一个stackblitz example,请查看它.希望这些解决方案对您有所帮助:)