Search code examples
javascriptangularjasminetddangular-directive

testing directive with jasmine


I have this directive but Im struggling with the jasmine test for it, any ideas?

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

@Directive({
   selector: '[ctrlKeys]',
})
export class CtrlKeysDirective {
   @Output() ctrlZ = new EventEmitter();
   @Output() ctrlY = new EventEmitter();

   @HostListener('document:keydown.control.z') onCtrlZ() {
       this.ctrlZ.emit();
   }

   @HostListener('document:keydown.control.y') onCtrlY() {
       this.ctrlY.emit();
   }
}

Solution

  • Usually with directives, I just attach it to a dummy component/HTML element and test from there. I am going all without an IDE so there may be some mistakes.

    describe('CtrlKeysDirective', () => {
      @Component({
        selector: 'dummy',
        template: `<div class="under-test" ctrlKeys>Hello</div>`
      })
      class DummyComponent {}
      
      let fixture: ComponentFixture<DummyComponent>;
      let component: DummyComponent;
      let ctrlKeysDirective: CtrlKeysDirective;
    
      beforeEach(waitForAsync(() => {
       TestBed.configureTestingModule({
         // declare both your directive and dummy component
         declarations: [DummyComponent, CtrlKeysDirective],
       }).compileComponents();
      }));
    
      beforeEach(() => {
        // get a handle on your component
        fixture = TestBed.createComponent(DummyComponent);
        component = fixture.componentInstance;
        // call ngOnInit of the component (not required)
        fixture.detectChanges();
        // get a handle on your directive (inspired from here https://stackoverflow.com/a/40282709/7365461)
        const ctrlKeysDirectiveEls = fixture.debugElement.query(By.directive(CtrlKeysDirective));
        ctrlKeysDirective = ctrlKeysDirectiveEls[0].injector.get(CtrlKeysDirective) as CtrlKeysDirective;
      });
    
      it('should create', () => {
        // expect the component to be truthy. Make sure this test passes to ensure
       // the TestBed was configured correctly.
        expect(component).toBeTruthy();
      });
    
      it('should emit ctrlZ', () => {
        const ctrlZSpy = spyOn(ctrlKeysDirective.ctrlZ, 'emit');
        window.dispatchEvent(new KeyboardEvent('keydown', { key: 'z', ctrlKey: true }));
        // !! try this !!
        const div = fixture.debugElement.query(By.css('.under-test')).nativeElement;
        div.dispatchEvent(new KeyboardEvent('keydown', { key: 'z', ctrlKey: true }));
        fixture.detectChanges();
        expect(ctrlZSpy).toHaveBeenCalled();
      });
    });
    

    I got inspired with the dispatchEvent from here: https://johngrahamdev.com/Unit-Testing-Keyboard-Shortcuts-Angular/