如何在Angular中测试form.valueChanges?

时间:2018-10-17 14:07:11

标签: angular karma-jasmine angular-reactive-forms

如何正确进行单元测试(因果报应,茉莉花),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);
});

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

[Edit1]-基于评论和答案:

问题在于测试异步性。 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);
});

1 个答案:

答案 0 :(得分:1)

您要在没有输入的情况下测试表单上的更改。 也许尝试一下:

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);
});