Угловое тестирование: получение HTML-элемента внутри дочернего компонента, который использует ng-content

#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 . Решение может заключаться в коде вокруг фрагментов кода, показанных в этом вопросе