How can i simulate browser focus when testing using angular and jasmine?

10,932

To trigger an event on an Angular element, you can use the built-in JavaScript ES6 method dispatchEvent with a subsequent call of Angular's change detection mechanism to get your DOM updated:

inputElement.dispatchEvent(new Event('focus'));
fixture.detectChanges();

A more elegant way to achieve the same thing is to use angular's wrapper method:

import { dispatchEvent } from '@angular/platform-browser/testing/src/browser_util'

dispatchEvent(inputElement, 'focus');
fixture.detectChanges();

An interesting one is when you want to set a value to your input element. You will need to first assign a string to the input's value property and then trigger an 'input' change event:

inputElement.value = 'abcd';
dispatchEvent(inputElement, 'input');
fixture.detectChanges();

Note: There are events that do not act the way you may expect. For example, dispatching a 'click' event will NOT give the focus to your input element! A workaround could be to first trigger a 'focus' event and then a 'click' event as follows:

dispatchEvent(inputElement, 'focus');
dispatchEvent(inputElement, 'input');
fixture.detectChanges();

All the available JavaScript events are here.

Share:
10,932
Admin
Author by

Admin

Updated on June 18, 2022

Comments

  • Admin
    Admin about 2 years

    I am trying to write a unit test that checks whether or not the effect of a focus event takes place. My actual test case is more complicated, but I have created a minimal reproduction with the following code:

    it('testing input focus', async(() => {
      let showDiv = false;
      const template = `<div *ngIf="shouldShow" class='hidden-div'>
                           SHOW ME WHAT YOU GOT
                        </div>
                        <input (focus)="shouldShow = !shouldShow" name="input">`;
      buildTestComponent(template, {shouldShow: showDiv}).then((fixture) => {
        fixture.detectChanges();
        const inputEl: HTMLInputElement = fixture.nativeElement.querySelector('input');
    
        expect(fixture.nativeElement.querySelector('.hidden-div')).toBe(null);
    
        inputEl.focus();
        fixture.detectChanges();
    
        expect(fixture.nativeElement.querySelector('.hidden-div')).not.toBe(null);
      });
    }));
    

    When I run this test with karma the test passes as long as I have focus on the chrome tab that is running the karma target. However, if the browser does not have focus the test fails (even if the browser is visible, but I click on another window) with error message:

    Expected null not to be null.
    

    I assume that when the Chrome tab doesn't have focus, the inputEl.focus() call doesn't actually get called but I don't know how to fix it. All other unit tests I have written pass regardless of browser focus. Has anyone run into this or have any ideas?

  • Alex C
    Alex C over 4 years
    import { dispatchEvent } from '@angular/platform-browser/testing/src/browser_util' => that dependency doesnt exist.
  • MarshHawk
    MarshHawk over 3 years
    this answer was very helpful, saved me when something like inputElement.focus() didn't work.