Unit Testing/mocking Свойства окна в Angular2 (TypeScript)
Я строю некоторые модульные тесты для службы в Angular2.
В моей службе у меня есть следующий код:
var hash: string;
hash = this.window.location.hash;
Однако, когда я запускаю тест, содержащий этот код, он не работает.
Было бы здорово использовать все возможности Window, но поскольку я использую PhantomJs, я не думаю, что это возможно (я также пробовал Chrome, который дает те же результаты).
В AngularJs я бы прибегнул к издевательскому $Window (или, по крайней мере, к рассматриваемым свойствам), но поскольку для тестирования Angular2 не было много документации, я не уверен, как это сделать.
Может ли кто-нибудь помочь?
Ответы
Ответ 1
В Angular 2 вы можете использовать функцию @Inject()
, чтобы внедрить объект окна, назвав его с помощью строкового токена, например, так:
constructor( @Inject('Window') private window: Window) { }
В @NgModule
вы должны предоставить его, используя ту же строку:
@NgModule({
declarations: [ ... ],
imports: [ ... ],
providers: [ { provide: 'Window', useValue: window } ],
})
export class AppModule {
}
Затем вы также можете высмеивать его, используя строку токена
beforeEach(() => {
let windowMock: Window = <any>{ };
TestBed.configureTestingModule({
providers: [
ApiUriService,
{ provide: 'Window', useFactory: (() => { return windowMock; }) }
]
});
Это работало в Angular 2.1.1, самое позднее на 2016-10-28.
Не работает с Angular 4.0.0 AOT.https://github.com/angular/angular/issues/15640
Ответ 2
Как упоминалось в комментарии @estus, вам лучше получить хэш от маршрутизатора. Но, чтобы ответить на ваш вопрос напрямую, вам нужно ввести окно в то место, где вы его используете, чтобы во время тестирования вы могли издеваться над ним.
Сначала зарегистрируйте окно с провайдером angular2 - возможно, где-то глобальным, если вы используете его повсеместно:
import { provide } from '@angular/core';
provide(Window, { useValue: window });
Это сообщает angular, когда инъекция зависимостей запрашивает тип Window
, он должен вернуть глобальный Window
.
Теперь, в том месте, где вы его используете, вы вводите это в свой класс, вместо того чтобы напрямую использовать глобальный:
import { Component } from '@angular/core';
@Component({ ... })
export default class MyCoolComponent {
constructor (
window: Window
) {}
public myCoolFunction () {
let hash: string;
hash = this.window.location.hash;
}
}
Теперь вы готовы высмеять это значение в своем тесте.
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;
//...
});
Ответ 3
После того, как RC4-метод provide()
, его развращают, поэтому способ справиться с этим после RC4:
let myMockWindow: Window;
beforeEach(() => {
myMockWindow = <any> { location: <any> {hash: 'WAOW-MOCK-HASH'}};
addProviders([SomeService, {provide: Window, useValue: myMockWindow}]);
});
Мне нужно время, чтобы понять, как это работает.