当使用Angular中的*ngIf指令时,我如何使用Jasmine进行单元测试以确定一个元素是否可见?

39

我有一个 Angular 6 应用程序,并编写了一些单元测试,尝试仅基于 *ngIf 指令的布尔结果来确定元素是否可见。

标记:

<div class="header" *ngIf="show">
    <div>...</div>
</div>

规格文件:

it('should hide contents if show is false', () => {
    const button = debugElement.query(By.css('button')).nativeElement;
    button.click();   // this will change show to false
    fixture.detectChanges();
    expect(debugElement.query(By.css('.header')).nativeElement.style.hidden).toBe(true);
});

我似乎无法获取div的hidden属性。 Angular是否使用另一种方法使用*ngIf指令将元素隐藏在DOM中? 我需要从nativeElement获取另一个属性吗?

谢谢!

5个回答

59
如果元素被隐藏,那么它不会在DOM中呈现。
你可以检查。
expect(fixture.debugElement.query(By.css('.header'))).toBeUndefined();

编辑:在上述情况下,toBeNull() 更好地工作。

expect(fixture.debugElement.query(By.css('.header'))).toBeNull();

而且在获取按钮元素时,您有一个语法错误。nativeElement不是一个函数。

请按照以下方式更改:

const button = fixture.debugElement.query(By.css('button')).nativeElement;

8
最终对我有效的方法是检查节点本身,就像您在此答案的第一行所做的那样。有趣的是,我最终使用toBeNull()函数来检查节点是否为null,而不是检查undefined。这对我起作用了。 - J-man
2
在结合 fixture.debugElement.queryexpect(...) 的时候要小心。这可能会导致浏览器出现内存不足的错误。我曾经遇到过这种情况。请参考 https://dev59.com/DFcP5IYBdhLWcg3wf6Kb#48606192。 - joecracker
我有同样的疑问,这确实是正确的答案。然而,由于某种原因,我们没有默认的变更检测:ChangeDetectionStrategy.OnPush.。在浏览器中,元素会自动被移除,但在单元测试中,我必须手动调用 `ChangeDetectorRef.detectChanges()' 才能让它运行。 - Michel
这里的代码似乎在 ngIf 评估为 false 时也能通过我的测试... - Jim

12

当使用ngIf测试组件是否显示时,我尝试获取元素(在这种情况下,您使用debugElement.query(By.css('.header')).nativeElement),如果它应该显示,我期望它是真实的,否则为假。

类似于这样:

it('should hide contents if show is false', () => {
    // should be rendered initially
    expect(debugElement.query(By.css('.header')).nativeElement).toBeTruthy();
    //trigger change
    const button = debugElement.query(By.css('button')).nativeElement;
    button.click();   // this will change show to false
    fixture.detectChanges();
    // should not be rendered
    expect(debugElement.query(By.css('.header')).nativeElement).toBeFalsy();
});

请注意,有时需要使用ComponentFixture#whenStable来检测 fixture 何时稳定,就像这样:

  it('should hide contents if show is false', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.whenStable().then(() => {
      // same test code here
    });
  });

查看这个工作测试,获取一个与此场景相似组件

请见[GitHub存储库]


第二个示例测试函数应该标记为“async”,因为我们在那里使用了Promise,不是吗? - Werek
@Werek - 因为我们不是在等待 Promise,而是利用 then 跳转到回调函数世界,所以函数签名不必标记为 async - paulroho

10
在将'show'的值更改为true后,您需要添加fixture.detectChanges()。
component.show = true;
fixture.detectChanges()

1
谢谢!在我的情况下,我有一个Observable,因此不能将其分配为true。我必须模拟这个observable并将其分配给component.thePropertyOnWhichTheConditionDependsfixture.detectChanges()是最后一点让测试工作的关键! - MikhailRatner

4

*ngIf条件编写测试用例,使用toBeNull条件。

尝试使用下面的代码,它对我有效。

expect(fixture.debugElement.query(By.css('.header'))).toBeNull();

3
使用ngIf时,Angular会完全从标记中删除节点。因此,您需要检查该元素不存在。 文档说: ngIf评估表达式,然后在表达式为真或假时分别渲染then或else模板。
更精确地说,它只是不呈现。

谢谢!我还尝试测试nativeElement是否未定义,但测试一直失败,显示“预期HTMLNode为未定义”,因此似乎是在检查节点的值而不是它是否存在于DOM中。 - J-man
2
@J-man 检查 fixture.debugElement.query(By.css('.header')).nativeElement。 - Drag13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接