0

I am having the hardest time trying to figure out how to write unit tests for this simple directive. Any help would be greatly appreciated.

Quick description: left and right arrow keys will change the focus of the test component.

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

@Directive({
  selector: '[giTabMenuKeyboardControls]'
})

export class TabMenuKeyboardControlsDirective {
  constructor(private el: ElementRef) { }

  @HostListener('keyup', ['$event']) onkeyup(e: KeyboardEvent) {
    const tabs: QueryList<any> = this.el.nativeElement.querySelectorAll('[role="tab"]');
    const currentFocused = document.activeElement;
    const index = Array.prototype.indexOf.call(tabs, currentFocused);

    // Left Arrow
    if (e.keyCode === 37) {
      currentFocused.previousElementSibling ? tabs[index - 1].focus() : tabs[tabs.length - 1].focus();
    }
    // Right Arrow
    if (e.keyCode === 39) {
      currentFocused.nextElementSibling ? tabs[index + 1].focus() : tabs[0].focus();
    }
  }
}

Here's what it looks like while i'm getting started.

import { TestBed, ComponentFixture} from '@angular/core/testing';
import { Component, DebugElement, Input} from '@angular/core';
import { By } from '@angular/platform-browser';
import { TabMenuKeyboardControlsDirective } from './tab-menu-keyboard-controls.directive';

// When creating test for a directive we need to provide a dummy component
@Component({
  template: `<div class="tab-menu" role="tablist" giTabMenuKeyboardControls>
  <button role="tab">test 1</button>
  <button role="tab">test 2</button>
</div>`
})

class TestTabMenuKeyboardControlsComponent {
}

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

  let component: TestTabMenuKeyboardControlsComponent;
  let fixture: ComponentFixture<TestTabMenuKeyboardControlsComponent>;
  let buttonElement: DebugElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ TabMenuKeyboardControlsDirective, TestTabMenuKeyboardControlsComponent ]
    });

    fixture = TestBed.createComponent(TestTabMenuKeyboardControlsComponent);
    component = fixture.componentInstance;
    buttonElement = fixture.debugElement.query(By.css('button'));
  });

  it('on key press', () => {
    buttonElement.triggerEventHandler('keyup', null);
    fixture.detectChanges();
  });

});

How do I check for the individual keys and focus?

Thanks again.

6
  • Why are you testing JavaScript implementations' event loops? Just call your method directly and see that it does the right thing. Commented Feb 12, 2018 at 19:48
  • All i needed was a little time away from the code. I got it, thanks.
    – user2283403
    Commented Feb 13, 2018 at 16:44
  • glad to hear. I still think my comment is worth thinking over. Many component and directive tests are just cruft that interacts with the runtime of the framework but doesn't really test anything you've written. Having a massively complicated testing framework like Angular's makes this more likely. Of course it's good to test but what you have here is really an integration test and a questionable one at that. Also, you can validate that your directive actually registers for the desired event by enumerating the class properties Commented Feb 13, 2018 at 16:51
  • Anyway just some stuff for you to think about if you wish Commented Feb 13, 2018 at 16:51
  • 1
    Oh, definitely! unfortunately, i work for one of those places that only look at the coverage percentages as a metric of success. IMO this is one for e2e. Thanks for your comment!
    – user2283403
    Commented Feb 14, 2018 at 15:20

0