Testing code within addEventHandler

社会主义新天地 提交于 2019-12-25 09:10:05

问题


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


回答1:


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

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



回答2:


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.




回答3:


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);
   // ...
});


来源:https://stackoverflow.com/questions/43347346/testing-code-within-addeventhandler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!