#angular #typescript #jasmine #karma-jasmine
#angular #typescript #jasmine #карма-жасмин
Вопрос:
Контекст
Я тестирую компонент, который использует службу на основе наблюдений, чтобы получить некоторые данные и показать их для целей i18n.
Служба i18n является пользовательской из-за конкретной необходимости.
Компонент работает в режиме разработки (используется в некоторых шаблонах, работает нормально), но тест завершается неудачно.
Источник
Компонент
@Component({
selector : "i18n",
template : '<span [innerHTML]="text"></span><span #wrapper hidden="true"><ng-content></ng-content><span>',
encapsulation: ViewEncapsulation.None
})
export class I18nComponent implements OnChanges {
constructor(private i18n:I18n) {
}
@ViewChild('wrapper')
content:ElementRef;
@Input('key')
key:string;
@Input('domain')
domain:string;
@Input('variables')
variables:Variables = [];
@Input("plural")
plural:number;
text:string;
ngOnChanges():any {
this.i18n.get(this.key, this.content.nativeElement.innerHTML, this.variables, this.domain).subscribe((res) => {
this.text = res;
});
}
}
I18n.get
public get(key:string,
defaultValue?:string,
variables:Variables = {},
domain?:string):Observable<string>{
const catalog = {
"StackOverflowDomain":
{
"my-key":"my-value"
}
};
return Observable.of(catalog[domain][key]).delay(300);
}
с Variables
:
export interface Variables {
[key:string]:any;
}
Тест
describe("I18n component", () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers : [
I18n,
{
provide : I18N_CONFIG,
useValue: {
defaultLocale : "fr_FR",
variable_start: '~',
variable_end : '~'
}
},
{
provide : I18N_LOADERS,
useClass: MockLocaleLoader,
multi : true
}
],
declarations: [
I18nComponent
]
});
fixture = TestBed.createComponent<I18nComponent>(I18nComponent);
comp = fixture.componentInstance;
});
fit("can call I18n.get.", fakeAsync(() => {
comp.content.nativeElement.innerHTML = "nope";
comp.key = "test";
comp.domain = "test domain";
comp.ngOnChanges();
tick();
fixture.detectChanges();
expect(comp.text).toBe("test value");
}));
});
Проблема
Тест завершается ошибкой с сообщением :
Ожидается, что неопределенное значение будет «тестовым значением».
Ошибка: 1 периодический таймер (ы) все еще в очереди.
Потому i18n.get
что не завершил свою работу до проверки утверждения, поэтому comp.text все еще undefined
.
Уже пробовал
- Добавление очень высокого значения в
tick
вызов метода ничего не изменило (пробовал с 5000). - Сделайте
ngOnChanges
возврат aPromise<void>
, который будет разрешен сразу послеthis.text = res;
и изменитеfakeAsync
зону для простого теста, используяdone
метод, указанный вthen
comp.ngOnChanges
. Это работает, ноngOnChanges
не должно возвращать aPromise
, и я хочу чистое решение.
Комментарии:
1. Можете ли вы предоставить достаточный пример реализации
get
метода для воспроизведения проблемы. Я не уверен, как это реализовать, чтобы получить ошибку2. Я отредактировал вопрос, чтобы добавить реализацию макета для
i18n.get
3. Действительно ли используется ваш реальный код
delay
? Причина, по которой я спрашиваю, заключается в том, что я пытаюсь переключиться с использованияfakeAsync
наasync
, чтобы посмотреть, имеет ли это какое-либо значение, но, похожеdelay
, используетsetInterval
, которое нельзя использовать внутриasync
.4. мой код не использует задержку, я просто добавил ее для имитации асинхронного поведения. но из-за асинхронной природы Obervable он должен работать так же без задержек.
5. Вот в чем дело. У меня все работает нормально, просто возвращаясь
Observable.of
. У меня не было проблем. Вот почему я попросил пример воспроизведения проблемы :/
Ответ №1:
Обратите внимание, что async
и fakeasync
не такие мощные и всеобъемлющие, как jasmine.done
Принимая во внимание точное примечание (на момент написания этой статьи): https://angular.io/guide/testing#component-fixture
В нем говорится:
Написание тестовых функций с помощью done, хотя и более громоздкое, чем async и fakeAsync, является жизнеспособным и иногда необходимым методом. Например, вы не можете вызвать async или fakeAsync при тестировании кода, который включает intervalTimer, как это обычно бывает при тестировании async Observable