由于未定义 FormArray 控件而必须定义控件,因此 UT 未通过

UT not pass due to undefined FormArray control while the control must be defined

我有一个创意工坊编辑组件(按顺序):

代码如下:

ngOnInit() {
  this.buildForms();
  this.initialize();
}

async initialize(): Promise<void> {
  const id = this.route.snapshot.params.id;

  this.workshop = await this.workshopService.find(id); // in real this is in a trycatch block
  this.updateFormValues();
}

buildForms(): void {
  this.form = ... // not important, this is not the problem
  this.discussesForm = this.formBuilder.group({
    array: this.formBuilder.array([], Validators.required),
  });
}

updateFormValues(): void {
  this.form.patchValue(this.workshop);
  this.workshop.ListDebates.forEach((discussion, index) => {
    this.addDiscussion();
    (this.discussesForm.get('array') as FormArray).at(index).patchValue({ // This line will throw error while UT.
      title: discussion.Title, description: discussion.Description, key: discussion.Key,
    });
  });
}

addDiscussion(): void {
  (this.discussesForm.get('array') as FormArray).push(this.formBuilder.group({
    title: [null],
    description: [null],
    key: [null],
  });
}

workshop.ListDebates 看起来像:

[
  {
    Key: 1,
    Title: 'title',
    Description: 'description',
  },
]

所以,上面的所有代码都可以正常工作,但我正在尝试对 updateFormValues 方法进行单元测试。

这是我试过的:

it('should update form values', () => {
  spyOn(component, 'addDiscussion');
  component.workshop = { Title: 'fake title', ListDebates: [
    { Key: 1, Title: 'fake', Description: 'fake' },
    { Key: 2, Title: 'fake', Description: 'fake' },
  ]} as any as IColabEvent;
  component.updateFormValues();
  expect(component.form.value.Title).toEqual('fake title'); // test OK
  expect((component.discussesForm.get('array') as FormArray).controls.length).toEqual(2); // test KO, expected 0 to be 2
  expect((component.discussesForm.get('array') as FormArray).at(0).value).toEqual(...); // test KO (not runned)
});

每次出现错误:无法读取未定义的 属性 'patchValue'(在 updateFormValues 方法中)。

我尝试了很多东西(以及随机的东西,比如添加 fixture.detectChanges()),但我找不到修复它的方法。

奇怪的是addDiscussion被调用了2次,所以我想知道为什么我的FormArray控件是未定义的。

我已经 console.log() 做了一些事情,看起来 addDiscussion 被调用了,但并没有像它必须做的那样推动一个小组。

我重复一遍,但在实际应用中它按预期工作。

不是您的测试用例有问题,实际上是您的代码有问题。您无需先使用 addDiscussion 创建具有 null 值的对象,然后使用 patchValue 设置值。相反,在您创建表单组本身时设置值。更改 addDiscussion 函数以接受 discussion 参数。

addDiscussion(discussion = {}): void {
    this.discussesForm.get('array').push(this.formBuilder.group({
        title: discussion.Title || null,
        description: discussion.Description || null,
        key: discussion.Key || null
    }));
}

然后在 updateFormValues 中,在 foreach 循环中,去掉 patchValue 代码并传递 discussion

this.workshop.ListDebates.forEach(discussion => {
    this.addDiscussion(discussion);
});

除此之外,正如评论中已经提到的,addDiscussion 不再需要被监视,因为您的测试依赖于它。完成后,您的测试应该可以正常工作了。