如何在 Angular 中测试 form.valueChanges?

问题描述 投票:0回答:2

如何正确进行单元测试(Karma、Jasmine),

valueChanges
的发射会调度
FormUpdated
动作?

beforeEach(async(() => {
  TestBed.configureTestingModule({
    imports: [...],
    providers: [
      { provide: Store, useValue: MOCK_STORE },
    ],
    declarations: [FormComponent],
    schemas: [NO_ERRORS_SCHEMA]
  })
    .compileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(FormComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});
export class FormComponent implements OnInit {
    searchForm: FormGroup;

    constructor(private readonly fb: FormBuilder, private readonly store: Store<AppState>) {
    }

    ngOnInit(): void {
        this.searchForm = this.fb.group({});
        this.searchForm.valueChanges.subscribe(value => this.store.dispatch(new FormUpdated(value)));
    }
}

我尝试过这样的事情:

it('should dispatch action for valueChanges', () => {
    const spy = spyOn(component['store'], 'dispatch');
    spyOn(component.searchForm, 'valueChanges').and.returnValue(of({}));

    expect(spy).toHaveBeenCalledTimes(1);
});

但这不起作用——间谍还没有被召唤。

[编辑1] - 基于评论和答案:

问题在于测试的异步性。

ngOnInit
的某些部分调用
setTimeout(() => this.searchForm.get('field').updateValueAndValidity();)
),这会导致发射到
this.searchForm.valueChanges()
,因此
this.store.dispatch
实际上被调用,但在 expect(spy).toHaveBeenCalledTimes(1)
 之后。

我尝试添加

fakeAsync()

tick()
flushMicrotasks()
,但结果相同。

it('should dispatch action for valueChanges', () => { const spy = spyOn(component['store'], 'dispatch'); spyOn(component.searchForm, 'valueChanges').and.returnValue(of({})); tick(); flushMicrotasks(); expect(spy).toHaveBeenCalledTimes(1); });
    
angular karma-jasmine angular-reactive-forms
2个回答
6
投票
您想要在没有输入的情况下测试表单上的更改。 也许可以尝试一下:

this.searchForm = this.fb.group({description: ['your_input']});

.

beforeEach(async(() => { TestBed.configureTestingModule({ imports: [...], providers: [ { provide: Store, useValue: MOCK_STORE }, ], declarations: [FormComponent], schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(FormComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should dispatch action for valueChanges', () => { const spy = spyOn(TestBed.get(Store<AppState>), 'dispatch') component.searchForm.controls['your_input'].setValue('test') // This will trigger change expect(spy).toHaveBeenCalledTimes(1); });
    

0
投票
我也遇到过同样的问题。问题是

valueChanges

无法直接监视,b/c“‘string’类型的参数不可分配给‘never’类型的参数”。

我通过添加一个管道,然后用模拟返回值监视管道来解决这个问题。因此,对于您的情况,请在

valueChanges

 中的 
ngOnInit()
 之前添加一个管道:

this.searchForm.valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(value => this.store.dispatch(new FormUpdated(value)));
然后在单元测试中,监视管道:

spyOn(component.searchForm.valueChanges, 'pipe').and.returnValue(of({}));
    
© www.soinside.com 2019 - 2024. All rights reserved.