user1124378
user1124378

Reputation:

Testing code within addEventHandler

I have the following -

window.addEventListener( "orientationchange", () => {
    // Code to test
});

How can I trigger this event in Jasmine? I have tried the following and it didn't work -

event = document.createEvent("HTMLEvents");
event.initEvent("orientationchange", true, true);

Here is the class -

export class AvailabilityComponent {

    changed: boolean = false;

    constructor(  ) {
        window.addEventListener( "orientationchange", () => {
            this.changed = !this.changed;
        } );
    }

}

Thanks

Upvotes: 0

Views: 3122

Answers (3)

Estus Flask
Estus Flask

Reputation: 222379

orientationchange event listener can be tested with

window.dispatchEvent(new Event('orientationchange'));

The problem is this is functional test, not unit test. Usually this kind of things is tested in E2E tests, this is the place where we want to check that the application plays nicely with browser and real DOM. Also, anonymous listeners cannot be removed, they may affect subsequent test and cause memory leaks.

A proper strategy for unit testing is to test written code line by line. Angular guide is specific on test isolation:

However, it's often more productive to explore the inner logic of application classes with isolated unit tests that don't depend upon Angular. Such tests are often smaller and easier to read, write, and maintain.

To be test-friendly the class can be refactored to

export const WINDOW = new OpaqueToken();

... providers: [..., { provide: WINDOW, useFactory: () => window }];

export class AvailabilityComponent {
    changed: boolean = false;

    constructor(@Inject(WINDOW) window: Window) {        
        window.addEventListener( "orientationchange",  this.orientationChangeListener);
    }

    orientationChangeListener = () => {
         this.changed = !this.changed;
    }
}

So it can be easily tested with

const windowMock = jasmine.createSpyObj(['addEventListener']);
const comp = new AvailabilityComponent(windowMock);
expect(windowMock.addEventListener).toHaveBeenCalledWith("orientationchange",
  comp.orientationChangeListener);

expect(comp.changed).toBe(false);
comp.orientationChangeListener.call(null); // unbind method
expect(comp.changed).toBe(true);

There is builtin DOCUMENT service already, and WINDOW service follows the same way, the recipe similar to $window in AngularJS. Acting on the mocked service allows to provide isolation for unit test and not pollute global scope with changes that have to be cleaned up in afterEach.

Since AvailabilityComponent is a component and will be tested with TestBed anyway, it probably makes sense to incorporate the test into TestBed. See also this answer on isolated vs TestBed unit tests.

Upvotes: 1

user1124378
user1124378

Reputation:

I have managed to this working with the following -

it( 'expect orientationchange to update changed to be truthy', () => {
    event = new Event('orientationchange');
    component.ngOnInit();
    window.dispatchEvent(event);
   // ...
});

Upvotes: 0

solo_assassin
solo_assassin

Reputation: 493

You can use window.dispatchEvent(new Event("orientationchange")) directly instead of

event = document.createEvent("HTMLEvents");
event.initEvent("orientationchange", true, true);

Upvotes: 2

Related Questions