为什么反应式控件的更改事件不会在Jasmine Angular单元测试中触发?

我有一个更改函数,我将传递给一个响应式窗体控件的更改事件,该控件评估脏状态并检查控件上是否有任何错误,如果是,则将布尔标志设置为true / false.然后使用该布尔标志来确定是否显示< div>包含错误消息的元素.这在浏览器中运行得很好,但是当单元测试运行时,“脏”永远不会被设置为true.这是我的代码

HTML

<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,请查看它.希望这些解决方案对您有所帮助:)

相关文章

ANGULAR.JS:NG-SELECTANDNG-OPTIONSPS:其实看英文文档比看中...
AngularJS中使用Chart.js制折线图与饼图实例  Chart.js 是...
IE浏览器兼容性后续前言 继续尝试解决IE浏览器兼容性问题,...
Angular实现下拉菜单多选写这篇文章时,引用文章地址如下:h...
在AngularJS应用中集成科大讯飞语音输入功能前言 根据项目...
Angular数据更新不及时问题探讨前言 在修复控制角标正确变...