web-dev-qa-db-fra.com

Propriétés de la fenêtre de test / simulation unitaire dans Angular2 (TypeScript)

Je construis des tests unitaires pour un service dans Angular2.

Dans mon service, j'ai le code suivant:

var hash: string; hash = this.window.location.hash;

Cependant, lorsque j'exécute un test qui contient ce code, il échoue.

Ce serait génial d'utiliser toutes les fonctionnalités de Windows, mais comme j'utilise PhantomJs, je ne pense pas que ce soit possible (j'ai également essayé Chrome qui donne les mêmes résultats) .

Dans AngularJs, j'aurais eu recours à moquer $ Window (ou au moins les propriétés en question), mais comme il n'y a pas beaucoup de documentation pour les tests unitaires Angular2, je ne sais pas comment faire.

Quelqu'un peut-il aider?

14
Rhys

Dans Angular 2, vous pouvez utiliser la fonction @Inject() pour injecter l'objet window en le nommant à l'aide d'un jeton de chaîne, comme ceci

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

Dans le @NgModule vous devez alors le fournir en utilisant la même chaîne:

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

Ensuite, vous pouvez également vous en moquer en utilisant la chaîne de jeton

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

Cela a fonctionné dans Angular 2.1.1, le dernier en date du 2016-10-28.

Ne fonctionne pas avec Angular 4.0.0 AOT. https://github.com/angular/angular/issues/1564

23
Klas Mellbourn

Comme @estus l'a mentionné dans le commentaire, vous feriez mieux d'obtenir le hachage du routeur. Mais pour répondre directement à votre question, vous devez injecter la fenêtre à l'endroit où vous l'utilisez, de sorte que pendant le test, vous puissiez vous en moquer.

Tout d'abord, enregistrez la fenêtre avec le fournisseur angular2 - probablement quelque part dans le monde si vous l'utilisez partout:

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

Cela indique angular lorsque l'injection de dépendances demande le type Window, elle doit renvoyer le global window.

Maintenant, à l'endroit où vous l'utilisez, vous l'injectez dans votre classe au lieu d'utiliser directement le global:

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

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

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

Vous êtes maintenant prêt à vous moquer de cette valeur dans votre 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;
    //...
});
6
elwyn

Après la méthode RC4 provide() son obsolète, donc la façon de gérer cela après RC4 est:

  let myMockWindow: Window;

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

Il me faut un certain temps pour comprendre comment cela fonctionne.

4
ulou