Mock ViewChild Element in Angular Test (of components in packages)

Viewed 51

In my component's class, I have ViewChild variables, like so:

@ViewChild("chipList") chipList;
@ViewChild("autocompleteChipInput") autocompleteChipInput: ElementRef<HTMLInputElement>;
@ViewChild("autocompleteTrigger") autocompleteTrigger: MatAutocompleteTrigger;

Here is (some of) the component template:

<mat-form-field>
   <mat-chip-list #chipList>
      <mat-chip>...</mat-chip>
      <input matInput #autocompleteChipInput #autocompleteTrigger="matAutocompleteTrigger" .../>
   </mat-chip-list>
   <mat-autocomplete #autocompleteChips="matAutocomplete">...</mat-autocomplete>
</mat-form-field>

I'm now writing unit tests, and in my class logic I'm using the chipList, autocompleteChipInput, and autocompleteTrigger variables. In my current tests, they're showing as undefined, so I can't trigger certain logic.
How can I mock out these elements in my tests? I've seen lots of examples on how to mock a childComponent, but those components are coming from external packages and I can't figure out how to apply it to them.

1 Answers

You need to use a mocking library. For example, such as ng-mocks.

An example with Angular Material: https://ng-mocks.sudo.eu/guides/libraries/angular-material

It will replace all dependencies with mocks, so @ViewChild is still to find related instances and build the properties of your component correctly:

// ItsModule should import / declare all dependencies of YourComponent.
beforeEach(() => MockBuilder(YourComponent, ItsModule));

// This call let you customize mock instances in tests.
MockInstance.scope();

it('should do something', () => {
  // creating a spy
  const spy = MockInstance(MatChipList, 'autocompleteTrigger', jasmine.createSpy());

  const fixture = MockRender(YourComponent);

  // an example, not sure if the spy has been triggered somehow.
  expect(spy).toHaveBeenCalled();
});
Related