Угловое модульное тестирование - заглушка / насмешка над директивой со ссылкой в ViewChild
Как вы заглушаете / макете директиву / компонент, который читается как ViewChild?
Например, используя простую директиву из angular.io:
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor() { }
}
Допустим, я тестирую AppComponent
и читает HighlightDirective
с помощью ViewChild
как:
@ViewChild(HighlightDirective) theHighlightDirective: HighlightDirective
И заглушенная директива:
@Directive({
selector: '[appHighlight]'
})
export class StubbedHighlightDirective {
constructor() { }
}
Поскольку компонент пытается прочитать HighlightDirective
, даже если вы объявите StubbedHighlightDirective
в ваших юнит-тестах, theHighlightDirective
будет неопределенным
Пример:
it('HighlightDirective is defined', () => {
// This test fails
expect(component.theHighlightDirective).toBeDefined();
});
Вы можете обойти это, если игнорируете некоторые вещи в tslint или используете as
ключевое слово:
Version 1: Just ignore some things in tslint so compiler doesn't complain
it('HighlightDirective is defined', () => {
// Compiler will typically complain saying that
// StubbedHighlightDirective isn't assignable to type of HighlightDirective
component.theHighlightDirective = new StubbedHighlightDirective();
// this passes
expect(component.theHighlightDirective).toBeDefined();
});
Version 2: Use "as" keyword
it('HighlightDirective is defined', () => {
// Actually compiler will still complain with warnings
component.theHighlightDirective = new StubbedHighlightDirective() as HighlightDirective;
// this passes
expect(component.theHighlightDirective).toBeDefined();
});
Есть ли другой способ полностью заглушить эти виды ссылок ViewChild?
1 ответ
Проблема в том, что вы используете класс для поиска ребенка, и этот класс был заменен вашей заглушкой. Вы можете использовать соответствующий exportAs
ссылка в вашей директиве ( документы, запись в блоге), чтобы убедиться, что реальная версия и заглушка имеют одинаковое имя.
В оригинальной директиве декоратора:
@Directive({
selector: '[appHighlight]',
exportAs: 'appHighlight'
})
export class HighlightDirective {
В заглушенной директиве:
@Directive({
selector: '[appHighlight]',
exportAs: 'appHighlight'
})
export class StubbedHighlightDirective {
И затем в шаблоне, где используется директива:
<div appHighlight #appHighlight="appHighlight">
После всего этого вам нужно обновить @ViewChild
определение использовать строку вместо класса:
@ViewChild('appHighlight') theHighlightDirective: HighlightDirective