Enhetstesting/mocking av Window-egenskaper i Angular2 (TypeScript)
Jeg lager noen enhetstester for en tjeneste i Angular2.
Innenfor min tjeneste har jeg følgende kode:
var hash: string; hash=this.window.location.hash;
Men når jeg kjører en test som inneholder denne koden, vil den feile.
Det hadde vært flott å bruke alle funksjonene i Window, men siden jeg bruker PhantomJs, tror jeg ikke dette er mulig (jeg har også prøvd Chrome som gir de samme resultatene).
I AngularJs ville jeg ha tydd til å mocke $Window (eller i det minste de aktuelle egenskapene), men siden det ikke finnes mye dokumentasjon for enhetstesting i Angular2, er jeg ikke sikker på hvordan jeg skal gjøre dette.
Kan noen hjelpe?
Svar #1
I Angular 2 kan du bruke @Inject()-funksjonen for å injisere vindusobjektet ved å navngi det med en streng-token, slik:
constructor( @Inject('Window') private window: Window) { }
I @NgModule må du deretter gi det ved å bruke den samme strengen:
@NgModule({
declarations: [ ... ],
imports: [ ... ],
providers: [ { provide: 'Window', useValue: window } ],
})
export class AppModule {
}
Da kan du også gjøre narr av det ved å bruke token-strengen
beforeEach(() => {
let windowMock: Window = <any>{ };
TestBed.configureTestingModule({
providers: [
ApiUriService,
{ provide: 'Window', useFactory: (() => { return windowMock; }) }
]
});
Dette fungerte i Angular 2.1.1, den nyeste per 2016-10-28.
Fungerer ikke med Angular 4.0.0 AOT. https://github.com/angular/angular/issues/15640
Svar #2
Som @estus nevnte i kommentaren, ville det være bedre å hente hashen fra ruteren. Men for å svare på spørsmålet ditt direkte, må du injisere window der du bruker det, slik at du kan mocke det under testing.
Først, registrer vinduet med angular2-leverandøren - sannsynligvis et sted globalt hvis du bruker dette overalt:
import { provide } from '@angular/core';
provide(Window, { useValue: window });
Dette forteller Angular at når avhengighetsinjeksjonen spør etter typen Window, bør den returnere den globale window.
Nå, på det stedet du bruker det, injiserer du dette i klassen din i stedet for å bruke globalen direkte:
import { Component } from '@angular/core';
@Component({ ... })
export default class MyCoolComponent {
constructor (
window: Window
) {}
public myCoolFunction () {
let hash: string;
hash = this.window.location.hash;
}
}
Nå er du klar til å gjøre narr av den verdien i testen din.
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;
//...
});
