Skip to main content

How to test a provider of a directive in Angular application

This test is quite similar to "How to test a provider of a component". With difference that we need a bit different template.

Let's prepare TestBed: the service for testing is the first parameter, the directive is the second one:

beforeEach(() => MockBuilder(TargetService, TargetDirective));

A custom template for the test could look like:

const fixture = MockRender(`<div target></div>`);

Once we have the fixture we can extract the service from it and assert its behavior:

const service = fixture.point.injector.get(TargetService);

Live example#

https://github.com/ike18t/ng-mocks/blob/master/examples/TestProviderInDirective/test.spec.ts
import {  Directive,  ElementRef,  Injectable,  OnInit,  TemplateRef,  ViewContainerRef,} from '@angular/core';import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
// A simple service, might have contained more logic,// but it is redundant for the test demonstration.@Injectable()class TargetService {  public readonly value = true;}
// The purpose of the directive is to add a background color// on mouseenter and to remove it on mouseleave.@Directive({  providers: [TargetService],  selector: '[target]',})class TargetDirective implements OnInit {  public constructor(    public readonly service: TargetService,    protected ref: ElementRef,    protected templateRef: TemplateRef<void>,    protected viewContainerRef: ViewContainerRef,  ) {}
  public ngOnInit(): void {    this.viewContainerRef.clear();    if (this.service.value) {      this.viewContainerRef.createEmbeddedView(this.templateRef);    }  }}
describe('TestProviderInDirective', () => {  ngMocks.faster(); // the same TestBed for several its.
  // Because we want to test the service, we pass it as the first  // parameter of MockBuilder.  // Because we do not care about TargetDirective, we pass it as  // the second parameter for being replaced with a mock copy.  // Do not forget to return the promise of MockBuilder.  beforeEach(() => MockBuilder(TargetService, TargetDirective));
  it('has access to the service via a directive', () => {    // Let's render a div with the directive. It provides a point    // to access the service.    const fixture = MockRender(`<div target></div>`);
    // The root element is fixture.point and it has access to the    // context of the directive. Its injector can extract the service.    const service = fixture.point.injector.get(TargetService);
    // Here we go, now we can assert everything about the service.    expect(service.value).toEqual(true);  });
  it('has access to the service via a structural directive', () => {    // Let's render a div with the directive. It provides a point to    // access the service.    const fixture = MockRender(`<div *target></div>`);
    // The root element is fixture.point and it has access to the    // context of the directive. Its injector can extract the service.    const service = fixture.point.injector.get(TargetService);
    // Here we go, now we can assert everything about the service.    expect(service.value).toEqual(true);  });});