角度测试:在使用ng-content的子组件中获取HTML元素

问题描述

我为使用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可能是从“ NgbAccordion”内部以“ ng-content”呈现的?如果是这样,我该怎么做才能访问我的元素?

非常感谢您的帮助。

解决方法

当它位于诸如此类的外部元素中时,有时也会发生在我身上。

尝试直接进入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看到该指令时会知道如何绘制。

,

我想您需要等待渲染;

// 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;
});