【问题标题】:Angular Testing: FormControl valueChanges ObservableAngular 测试:FormControl valueChanges Observable
【发布时间】:2019-01-25 09:30:21
【问题描述】:

我有一个文本输入,我正在监听更改。

组件

name = new FormControl('',Validators.required);

ngOnInit() {
  this.data = 'oldvalue';
  this.checkName();
}

checkName() {
  this.name.valueChanges.subscribe(val=>{
     console.log(val);
     this.data= "newvalue"; // updating Value
  });
}

HTML

<input name="name" formControlName="name">

到目前为止我的尝试:

component.spec.ts

it('should test data field ', () => {
    const fixture = TestBed.createComponent(UserComponent);
    const app=fixture.debugElement.componentInstance;
    const el = fixture.nativeElement.querySelector('input');
    el.value ='something';
    dispatchEvent(new Event(el));
    fixture.detectChanges();
    fixture.whenStable().then(()=>{expect(app.data).toBe('newvalue');
});

问题: 即使填充了输入字段,订阅回调中的代码也永远不会执行。

它总是显示:

预期的“旧值”是“新值”。

我也尝试了setValue() 方法,但没有成功。它永远不会进入订阅回调

app.name.setValue('vikas');
fixture.detectChanges();
fixture.whenStable().then(()=>{expect(app.data).toBe('newvalue');

我提到了Updating input html field from within an Angular 2 test 和Angular2 Component: Testing form input value change 但没有运气:(

我错过了什么?

【问题讨论】:

    标签: angular unit-testing jasmine karma-jasmine


    【解决方案1】:

    乍一看,我认为您错过了 FormControl 未连接到输入的事实,因为您使用的 FormControlName 指令将控件名称作为 @Input。

    如果您想测试 FormControl,那么您可以考虑将 FormControl 视为 @Input 的 FormControlDirective:

    <input name="name" [formControl]="name">
                                      ^^^^^
                          `name` is FormControl instance here not string
    

    现在我们可以确定,每当我们更改输入中的文本时,您的 FormControl 都会触发更改。但是,一旦您编写了这样的模板,Angular 就会在您的测试中要求您提供 ReactiveFormsModule 依赖项:

    import { ReactiveFormsModule } from '@angular/forms';
    ....
    
    TestBed.configureTestingModule({
       imports: [
         ReactiveFormsModule  <=== add this
       ],
       declarations: [TestComponent],
    });
    

    现在关于你的测试。

    1) 您必须通过调用fixture.detectChanges() 告诉TestBed 执行数据绑定:

    const fixture = TestBed.createComponent(TestComponent);
    fixture.detectChanges(); <== add this
    

    2) 您应该正确触发输入更改:

    el.dispatchEvent(new Event('input'));
    

    这是整个代码:

    it('should display original title', () => {
      const fixture = TestBed.createComponent(TestComponent);
      fixture.detectChanges();
      const app = fixture.debugElement.componentInstance;
      const el = fixture.nativeElement.querySelector('input');
      el.value = 'something';
      el.dispatchEvent(new Event('input'));
      fixture.detectChanges();
      fixture.whenStable().then(() => {
        expect(app.data).toBe('newvalue');
      });
    });
    

    Plunker Example

    【讨论】:

    • Thanx Mate 像个魅力一样工作 :)
    • 嗨,我遇到了这种方法的问题,请问你能看到这个问题stackoverflow.com/questions/58355726/…
    • 我正在使用最后一个 Angular 版本和 Jest,我必须等待 fixture.whenStable(),然后执行断言
    • 非常感谢,真的很有帮助。
    • 对于单个表单控件并基于输入,它工作正常。但是如果我们有多个表单控件并且都在同一个输入中,如何区分每个。
    猜你喜欢
    • 1970-01-01
    • 2017-11-20
    • 2019-04-27
    • 2018-07-13
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多