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

Angular Testing: Get HTML Element inside child component that uses ng-content

我在为使用 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 class(而且我不想!),所以我希望它的内容能够正确呈现。是吗,因为 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);

编辑:我不完全确定指令的 class 名称是什么(可能是 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;
});