#angular #testing #jasmine #karma-runner #ng-bootstrap
#angular #тестирование #jasmine #карма-бегун #ng-bootstrap
Вопрос:
У меня проблема с написанием модульных тестов для компонента, который использует ngb-accordion для отображения своего содержимого. В этом случае аккордеон используется только для целей стилизации, но я использую его для обеспечения согласованности дизайна во всем приложении.
Самый простой шаблон, который я мог придумать, чтобы показать ошибку:
<ngb-accordion #acc="ngbAccordion" activeIds="sample">
<ngb-panel id="sample">
<ng-template ngbPanelContent>
<p class="myClass">Some Text</p> <!-- I want to access this element -->
</ng-template>
</ngb-panel>
</ngb-accordion>
Тестовый пример выглядит следующим образом:
it('should find my element', () => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
const p = fixture.debugElement.query(By.css('.myClass')).nativeElement;
p.id;
});
который выдает ошибку:
TypeError: Cannot read property 'nativeElement' of null
Вот beforeEach
для моего теста:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent, NgbAccordion ],
providers : [FormBuilder, ...]
})
.compileComponents();
}));
(где LoginComponent
находится тестируемый компонент).
Я не думаю, что это как-то связано с ng-template
тем, что, как и в следующем html, элемент найден правильно:
<div *ngIf="false else always">Should not show</div>
<ng-template #always>
<p class="myClass">Some Text</p>
</ng-template>
Я не знаю, почему это не работает ngbAccordion
, может ли это быть проблемой времени? Поскольку я не издеваюсь над NgbAccordion
классом (и я не хочу!), Я ожидаю, что его содержимое будет отображаться правильно. Это потому, что html, вероятно, отображается с помощью «ng-content» из «NgbAccordion»? Если да, то что я могу сделать, чтобы получить доступ к моему элементу?
Любая помощь приветствуется.
Комментарии:
1. Используете ли вы механизм обнаружения изменений OnPush в компоненте?
2. нет, ничего подобного. компонент (.ts) может быть пустым.
Ответ №1:
Это иногда случается и со мной, когда он находится внутри подобных внешних элементов.
Вместо query
того, чтобы пытаться перейти прямо к nativeElement
использованию или document.querySelector
.
const p = fixture.nativeElement.querySelector('.myClass');
console.log(p); // see if it returns
const p2 = document.querySelector('.myClass');
console.log(p2); // see if it returns
Если это не сработает, проверьте nativeElement
и убедитесь, что элемент есть;
const nativeElement = fixture.nativeElement;
console.log(nativeElement);
Редактировать: я не совсем уверен, каково имя класса директивы (возможно, NgBPanelContent ), но убедитесь, что оно есть в вашем массиве объявлений, чтобы HTML знал, как его нарисовать, когда увидит эту директиву.
Комментарии:
1. к сожалению, нет. При регистрации всего собственного элемента
ngbAccordion
он есть, но моего содержимого нет. При просмотре страницы за пределами тестовой среды это, конечно, отображается.2. Возможно, вам нужно включить
ngbPanelContent
директиву в свои объявления. Я вижу, что вы его импортировали, но я думаю, что он не знает, как рисовать себя.3. вот и все! может быть, вы могли бы отредактировать свой ответ, и тогда я его приму.
Ответ №2:
Я полагаю, вам нужно дождаться рендеринга;
// async added here
it('should find my element', async () => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
// and await rendering
await fixture.whenRenderingDone();
const p = fixture.debugElement.query(By.css('.myClass')).nativeElement;
p.id;
});
Комментарии:
1. Я уже пытался подождать, используя
fakeAsync
иtick(500)
… тоже не помогло.2. Было бы неплохо иметь stackblitz . Решение может заключаться в коде вокруг фрагментов кода, показанных в этом вопросе