首页 文章

.detectChanges()在Angular测试中不起作用

提问于
浏览
3

我的任务是为使用Angular开发的聊天应用程序编写测试 . 下面是我正在编写测试的Angular模板代码片段:

<div class="title-menu-container" fxLayoutAlign="center center">
  <button id="save-title-button" mat-icon-button *ngIf="titleInputEdit; else settings">
    <mat-icon class="secondary-text" (click)="saveTitle(titleInput.value)">check</mat-icon>
  </button>
  <ng-template #settings>
    <button mat-icon-button [matMenuTriggerFor]="menu" [disabled]="!(isGroupConversation$ | async)">
      <mat-icon class="secondary-text">settings</mat-icon>
    </button>
  </ng-template>
</div>

实际上,如果组件布尔变量'titleInputEdit'为true,则显示save-title-button,否则显示设置按钮 . 以下是导致问题的测试用例:

it('save title button should be present', () => {
  component.titleInputEdit = true;
  fixture.detectChanges();
  expect(fixture.nativeElement.querySelector('#save-title-button')).not.toBe(null);
});

我只是“模拟”组件变量,调用.detectChanges(),然后测试按钮的存在 . 但是,测试失败,并且“预期的空值不为空” .

通过各种console.log调用,我已经确认component.titleInputEdit正确设置为true但fixture.nativeElement不包含正确的按钮 .

我注意到的一些事情:

  • 如果我将'component.titleInputEdit = true'行移动到我的beforeEach中并将其删除,并从我的测试中调用detectChanges(),则测试通过 .
beforeEach(() => {
  fixture = TestBed.createComponent(TestComponent);
  component = fixture.componentInstance;
  component.titleInputEdit = true
  fixture.detectChanges();
  debugElement = fixture.debugElement;
});     

it('save title button should be present', () => {
    expect(fixture.nativeElement.querySelector('#save-title-button')).not.toBe(null);
});
  • 如果我从beforeEach()中删除.detectChanges()调用,并将其保留在测试用例中,则测试通过 .

我对Angular和StackOverflow(长时间潜伏,第一次海报)相对较新,但我发现了类似问题的人的实例 . 在尝试了那些帖子中推荐的一些东西后,我仍然在摸不着头脑 . 更奇怪的是,我已经为其他Angular组件编写了测试,这些组件几乎完全相同,没有任何问题 .

Angular文档中提供的示例也显示了非常相似的内容:

it('should display a different test title', () => {
  component.title = 'Test Title';
  fixture.detectChanges();
  expect(h1.textContent).toContain('Test Title');
});

2 回答

  • 1

    事实证明这是由于在组件中使用ChangeDetectionStrategy.OnPush . 使用OnPush只允许您调用.detectChanges()一次,因此后续调用将无法执行任何操作 . 我对Angular不太熟悉,无法完全理解为什么 .

    通过覆盖TestBed配置中的ChangeDetectionStrategy,我能够产生所需的行为 .

    TestBed.configureTestingModule({
        imports: [],
        declarations: [TestComponent],
        providers: []
      })
        .overrideComponent(TestComponent, {
          set: { changeDetection: ChangeDetectionStrategy.Default }
        })
        .compileComponents();
    
  • 7

    这里提供的答案https://stackoverflow.com/a/50142134/3765819解决了这个问题 . 但是,还有另一种方法,我认为它可以防止UI上的进一步问题 . 我遇到的问题类似于问题中描述的问题,这意味着在HTML上测试特定字符串时我无法找到它 . 即使运行代码时措辞很好,但在测试时UI也没有相应更新 .

    我必须做的是:

    要将 ChangeDetectorRef 注入 .ts 文件:

    constructor(private changeDetector: ChangeDetectorRef) {}
    

    并在需要时调用它:

    this.changeDetector.markForCheck();
    

相关问题