Unit Testing/mocking Window properties in Angular2 (TypeScript)

穿精又带淫゛_ 提交于 2019-11-30 17:34:47
Klas Mellbourn

In Angular 2 you can use the @Inject() function to inject the window object by naming it using a string token, like this

  constructor( @Inject('Window') private window: Window) { }

In the @NgModule you must then provide it using the same string:

@NgModule({
    declarations: [ ... ],
    imports: [ ... ],
    providers: [ { provide: 'Window', useValue: window } ],
})
export class AppModule {
}

Then you can also mock it using the token string

beforeEach(() => {
  let windowMock: Window = <any>{ };
  TestBed.configureTestingModule({
    providers: [
      ApiUriService,
      { provide: 'Window', useFactory: (() => { return windowMock; }) }
    ]
  });

This worked in Angular 2.1.1, the latest as of 2016-10-28.

Does not work with Angular 4.0.0 AOT. https://github.com/angular/angular/issues/15640

As @estus mentioned in the comment, you'd be better getting the hash from the Router. But to answer your question directly, you need to inject window into the place you're using it, so that during testing you can mock it.

First, register window with the angular2 provider - probably somewhere global if you use this all over the place:

import { provide } from '@angular/core';
provide(Window, { useValue: window });

This tells angular when the dependency injection asks for the type Window, it should return the global window.

Now, in the place you're using it, you inject this into your class instead of using the global directly:

import { Component } from '@angular/core';

@Component({ ... })
export default class MyCoolComponent {
    constructor (
        window: Window
    ) {}

    public myCoolFunction () {
        let hash: string;
        hash = this.window.location.hash;
    }
}

Now you're ready to mock that value in your test.

import {
    beforeEach,
    beforeEachProviders,
    describe,
    expect,
    it,
    inject,
    injectAsync
} from 'angular2/testing';

let myMockWindow: Window;
beforeEachProviders(() => [
    //Probably mock your thing a bit better than this..
    myMockWindow = <any> { location: <any> { hash: 'WAOW-MOCK-HASH' }};
    provide(Window, {useValue: myMockWindow})
]);

it('should do the things', () => {
    let mockHash = myMockWindow.location.hash;
    //...
});

After RC4 method provide() its depracated, so the way to handle this after RC4 is:

  let myMockWindow: Window;

  beforeEach(() => {
    myMockWindow = <any> { location: <any> {hash: 'WAOW-MOCK-HASH'}};
    addProviders([SomeService, {provide: Window, useValue: myMockWindow}]);
  });

It take me a while to figure it out, how it works.

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