angularangular-unit-testangular-signals

How to add unit tests for Signal Queries?


I am using Angular's signal queries (viewChild, viewChildren, contentChild, contentChildren) like the following:

export class MyComponent {
  myScrollContainer = viewChild('scrollContainer', { read: ElementRef });

  scrollToTop() {
    this.myScrollContainer()?.nativeElement.scroll({ top: 0 });
  }
}

The code works fine. However I am struggling to find a good approach how to add unit tests for it and mocking the query value. For signal inputs, we can use the ComponentRef's setInput() function. Is there something similar for signal queries that I have missed?

For now I have implemented the test like the following by overriding the signal:

it('should scroll to the top', () => {
  const mockElement = document.createElement('div');
  const spy = spyOn(mockElement, 'scroll');
  component.myScrollContainer = signal({ nativeElement: mockElement }).asReadonly();
  component.scrollToTop();

  expect(spy).toHaveBeenCalledOnceWith({ top: 0 });
});

It works but feels like a hacky solution. Also it does not allow me to mark the attribute as readonly, which I want.


Solution

  • It can be achieved by directly spying on the object returned by the signal query:

    it('should scroll to the top', () => {
      const mockElement = component.myScrollContainer()!.nativeElement;
      const spy = spyOn(mockElement, 'scroll');
      // if you want to spy on properties, you can use `spyOnProperty`
      component.scrollToTop();
    
      expect(spy).toHaveBeenCalledOnceWith({ top: 0 });
    });