问题描述
我的任务是为使用 Angular 开发的聊天应用程序编写测试.下面是我目前正在为其编写测试的 Angular 模板代码片段:
I've been tasked with writing tests for a chat app developed with Angular. Below is the snippet of Angular template code I'm currently writing tests for:
<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'为真,则显示保存标题按钮,否则显示设置按钮.这是导致问题的测试用例:
Essentially, if the component boolean variable 'titleInputEdit' is true, the save-title-button is displayed, otherwise the settings button is displayed. Here is the test case that is causing problems:
it('save title button should be present', () => {
component.titleInputEdit = true;
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('#save-title-button')).not.toBe(null);
});
我只是模拟"组件变量,调用 .detectChanges(),然后测试按钮是否存在.但是,测试失败并显示预期 null 不为 null".
I simply "mock" the component variable, call .detectChanges(), and then test for the presence of the button. However, the test fails with 'Expected null not to be null.'
通过各种 console.log 调用,我确认 component.titleInputEdit 已正确设置为 true,但 fixture.nativeElement 不包含正确的按钮.
Through various console.log calls, I have confirmed that the component.titleInputEdit is correctly set to true but the fixture.nativeElement DOES NOT contain the correct button.
我注意到的一些事情:
如果我将 'component.titleInputEdit = true' 行移到我的 beforeEach 中并将其删除,并且从我的测试中调用 detectChanges(),则测试通过.
If I move the 'component.titleInputEdit = true' line into my beforeEach and remove it, and the detectChanges() call, from my test, the test passes.
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() 调用,并将其留在测试用例中,则测试通过.
If I remove the .detectChanges() call from beforeEach(), and leave it in the test case, the test passes.
我对 Angular 比较陌生,但我发现有人遇到类似问题.在尝试了这些帖子中推荐的一些东西之后,我仍然摸不着头脑.更奇怪的是,我已经为其他 Angular 组件编写了测试,这些组件几乎可以毫无问题地完成相同的事情.
I'm relatively new to Angular, but I've found instances of people with a similar issue. After trying some of the things recommended in those posts I'm still left scratching my head. What's even stranger is that I have written tests for other Angular components that do almost the exact same thing with no issue.
Angular 文档中提供的示例也显示了非常相似的内容:
The example provided in the Angular docs show something very similar as well:
it('should display a different test title', () => {
component.title = 'Test Title';
fixture.detectChanges();
expect(h1.textContent).toContain('Test Title');
});
推荐答案
原来这是由于在组件中使用了 ChangeDetectionStrategy.OnPush
.使用 OnPush
只允许您调用一次 .detectChanges()
,因此后续调用将无法执行任何操作.我对 Angular 不够熟悉,无法完全理解原因.
It turns out this is due to using ChangeDetectionStrategy.OnPush
in the component. Using OnPush
only allows you to call .detectChanges()
one time, so subsequent calls will fail to do anything. I'm not familiar enough with Angular to fully understand why.
我能够通过覆盖我的 TestBed 配置中的 ChangeDetectionStrategy
来产生所需的行为.
I was able to produce the required behaviour by overriding the ChangeDetectionStrategy
in my TestBed configuration.
TestBed.configureTestingModule({
imports: [],
declarations: [TestComponent],
providers: []
})
.overrideComponent(TestComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
})
.compileComponents();
这篇关于.detectChanges() 在 Angular 测试中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!