PierreD
PierreD

Reputation: 933

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

I have a workshop-edit component that (in order):

Here is the code:

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 look like:

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

So, all the code above works fine, but i'm trying to unit test the updateFormValues method.

This is what I tried:

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

Everytime I get error: Cannot read property 'patchValue' of undefined (in the updateFormValues method).

I've tried lots of things (and random things like adding fixture.detectChanges()) but I don't find a way to fix it.

What is weird is that addDiscussion is called 2 times, so I wonder why my FormArray control is undefined.

I've console.log() some things and it look like addDiscussion is called but isn't pushing a group like it must does.

I repeat myself but in the real app it's working as intended.

Upvotes: 0

Views: 241

Answers (1)

nash11
nash11

Reputation: 8650

Rather than something being wrong with your test cases, it is in fact your code that has an issue. There is no need for you to use addDiscussion first to create an object with null values and then use patchValue to set the values. Instead, set the values as you create the form group itself. Change your addDiscussion function to accept the discussion parameter.

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

Then in updateFormValues, in your foreach loop, get rid of the patchValue code and pass discussion instead.

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

Apart from this, as already mentioned in the comments, the addDiscussion no longer needs to be spied upon since your test depends on it. Once this is done, your tests should be working.

Upvotes: 1

Related Questions