Angular How to test @HostListener

10,160

I found a solution. Instead of checking for value (which never changes), I just check the defaultPrevented property on the event.

I was also missing two things :

  • fixture.detectChanges(); in the beforeEach

  • event should be cancelable

Here's the full test :

     describe('PreventInputDirective', () => {
      let fixture;
      let input: DebugElement;
    
      beforeEach(() => {
        fixture = TestBed.configureTestingModule({
          declarations: [PreventInputDirective, TestComponent]
        }).createComponent(TestComponent);
    
        input = fixture.debugElement.query(By.directive(PreventInputDirective));
        fixture.detectChanges();
      });
    
      it('should create an instance', () => {
        const directive = new PreventInputDirective();
        expect(directive).toBeTruthy();
      });
    
      it('should prevent keypress event', () => {
        const event = new KeyboardEvent('keypress', {
          'key': '.',
          cancelable: true
        });
    
        input.nativeElement.dispatchEvent(event);
        expect(event.defaultPrevented).toBeTruthy();
      });
    
      it('should not prevent keypress event', () => {
        const event = new KeyboardEvent('keypress', {
          'key': '5',
          cancelable: true
        });
    
        input.nativeElement.dispatchEvent(event);
        expect(event.defaultPrevented).toBeFalsy();
      });
    
      @Component({
        template: `<input cdtPreventInput="." />`
      })
      class TestComponent { }
    });
Share:
10,160
Sam
Author by

Sam

Everything related to web development.

Updated on June 28, 2022

Comments

  • Sam
    Sam about 2 years

    I have the following directive. When applied to an input element, it checks for characters and calls preventDefault when the character is forbidden:

    @Directive({
     selector: '[cdtPreventInput]'
    })
      export class PreventInputDirective implements OnInit {
    
      // the list of characters that are to be prevented
      @Input() cdtPreventInput: String;
    
      constructor() { }
    
      ngOnInit() {
        if (!this.cdtPreventInput) {
          throw new Error('cdtPreventInput cannot be used without providing a 
              list of characters.');
        }
      }
    
     @HostListener('keypress', ['$event']) onKeyPress(event) {
       if (_.includes(this.cdtPreventInput.split(','), event.key)) {
        event.preventDefault();
      }
    }
    

    Works fine, but I can't figure out how to test it. I have the following so far:

    describe('PreventInputDirective', () => {
      let fixture;
      let input: DebugElement;
    
      beforeEach(() => {
        fixture = TestBed.configureTestingModule({
          declarations: [PreventInputDirective, TestComponent]
        }).createComponent(TestComponent);
    
        input = fixture.debugElement.query(By.directive(PreventInputDirective));
      });
    
      it('should create an instance', () => {
        const directive = new PreventInputDirective();
        expect(directive).toBeTruthy();
      });
    
     it('should prevent default keypress event', () => {
        const event = new KeyboardEvent('keypress', {
          'key': '.'
        });
         input.nativeElement.dispatchEvent(event);
    
         expect(input.nativeElement.value).toEqual('');
      });
    
      @Component({
        template: `<input cdtPreventInput="." />`
      })
      class TestComponent { }
    });
    

    It's not working though. The keypress event is not triggered. Any idea how to test this directive ?