#native_company# #native_desc#
#native_cta#

Testing Directives


Learning Objectives

  • Understand how to test directives using wrapper components.

Test Setup

We are going to test a directive called the HoverFocusDirective. It has an attribute selector of hoverfocus and if it’s attached to an element hovering over that element sets the background color to blue.

import {
    Directive,
    HostListener,
    HostBinding
} from '@angular/core';

@Directive({
  selector: '[hoverfocus]'
})
export class HoverFocusDirective {

  @HostBinding("style.background-color") backgroundColor: string;

  @HostListener('mouseover') onHover() {
    this.backgroundColor = 'blue';
  }

  @HostListener('mouseout') onLeave() {
    this.backgroundColor = 'inherit';
  }
}

It uses @HostListener to listen to mouseover and mouseout events on its host element and it also uses @HostBinding to set the style property of its host element.

The starting point for our test suite is very similar to our previous examples:

import {TestBed} from '@angular/core/testing';
import {HoverFocusDirective} from './hoverfocus.directive';

describe('Directive: HoverFocus', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [HoverFocusDirective]
    });
  });
});

Test Wrapper Component

To test a directive we typically create a dummy testing component so we can interact with the directive and test it’s effect on the component’s view, like so:

@Component({
  template: `<input type="text" hoverfocus>` (1)
})
class TestHoverFocusComponent {
}
1 The directive is associated with an input control in the component’s view.

Now we have a component to work with we can configure the test bed and get the required references for the tests, like so:

describe('Directive: HoverFocus', () => {

  let component: TestHoverFocusComponent;
  let fixture: ComponentFixture<TestHoverFocusComponent>;
  let inputEl: DebugElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TestHoverFocusComponent, HoverFocusDirective] (1)
    });
    fixture = TestBed.createComponent(TestHoverFocusComponent); (2)
    component = fixture.componentInstance;
    inputEl = fixture.debugElement.query(By.css('input'));
  });
});
1 We declare both the directive we want to test and the dummy test component.
2 We grab a reference to the component fixture as well as the component and the input DebugElement from the component view.

Interacting and Inspecting the View

We now have all the pieces we need to create a test spec for the directive itself:

it('hovering over input', () => {
  inputEl.triggerEventHandler('mouseover', null); (1)
  fixture.detectChanges();
  expect(inputEl.nativeElement.style.backgroundColor).toBe('blue'); (2)

  inputEl.triggerEventHandler('mouseout', null);
  fixture.detectChanges();
  console.log(inputEl.nativeElement.style.backgroundColor);
  expect(inputEl.nativeElement.style.backgroundColor).toBe('inherit');
});
1 We use triggerEventHandler to simulate events.
2 The style property on the nativeElement is what we can inspect to see the current style applied to an element.

Summary

To test directives we use dummy test components which we can create using the Angular Test Bed and which we can interact with by using a component fixture.

We can trigger events on DebugElements by using the triggerEventHandler function and if we want to see what styles are applied to it we can find it via the nativeElement.style property.

Listing

Listing 1. hoverfocus.directive.ts
import {
    Directive,
    HostListener,
    HostBinding
} from '@angular/core';

@Directive({
    selector: '[hoverfocus]'
})
export class HoverFocusDirective {

    @HostBinding("style.background-color") backgroundColor: string;

    @HostListener('mouseover') onHover() {
        this.backgroundColor = 'blue';
    }

    @HostListener('mouseout') onLeave() {
        this.backgroundColor = 'inherit';
    }
}
Listing 2. hoverfocus.directive.spec.ts
/* tslint:disable:no-unused-variable */
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { Component, DebugElement } from "@angular/core";
import { By } from "@angular/platform-browser";
import { HoverFocusDirective } from './hoverfocus.directive';

@Component({
    template: `<input type="text" hoverfocus>`
})
class TestHoverFocusComponent {
}


describe('Directive: HoverFocus', () => {

    let component: TestHoverFocusComponent;
    let fixture: ComponentFixture<TestHoverFocusComponent>;
    let inputEl: DebugElement;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [TestHoverFocusComponent, HoverFocusDirective]
        });
        fixture = TestBed.createComponent(TestHoverFocusComponent);
        component = fixture.componentInstance;
        inputEl = fixture.debugElement.query(By.css('input'));
    });

    it('hovering over input', () => {
        inputEl.triggerEventHandler('mouseover', null);
        fixture.detectChanges();
        expect(inputEl.nativeElement.style.backgroundColor).toBe('blue');

        inputEl.triggerEventHandler('mouseout', null);
        fixture.detectChanges();
        expect(inputEl.nativeElement.style.backgroundColor).toBe('inherit');
    });
});

Caught a mistake or want to contribute to the book? Edit this page on GitHub!



Advanced JavaScript

This unique course teaches you advanced JavaScript knowledge through a series of interview questions. Bring your JavaScript to the 2021's today.

Level up your JavaScript now!