Angular Material 虚拟滚动不在单元测试中呈现项目
Angular Material virtual scroll not rendering items in unit tests
我在我的组件中使用 cdk-virtual-scroll-viewport
+ cdkVirtualFor
,它似乎工作正常。
然而,在该组件的单元测试中,项目不会被渲染。
我制作了一个示例应用程序 based on this example,虽然该示例在您为该应用程序提供服务时有效,但我编写的测试失败了。
app.module.ts
import { ScrollingModule } from '@angular/cdk/scrolling';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
ScrollingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
app.component.html
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
<div *cdkVirtualFor="let item of items" class="example-item">{{ item }}</div>
</cdk-virtual-scroll-viewport>
app.component.spec.ts
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { ScrollingModule } from '@angular/cdk/scrolling';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
ScrollingModule,
],
}).compileComponents();
}));
it('should render at least 4 items', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement as HTMLElement;
expect(compiled.querySelectorAll('.example-item').length).toBeGreaterThanOrEqual(4); // <-- Error: Expected 0 to be greater than or equal 4.
});
});
将单元测试(参见问题)更改为以下解决方法:
it('should render at least 4 items', fakeAsync(() => { // <---
const fixture = TestBed.createComponent(AppComponent);
fixture.autoDetectChanges(); // <---
tick(500); // <---
const compiled = fixture.debugElement.nativeElement as HTMLElement;
expect(compiled.querySelectorAll('.example-item').length).toBeGreaterThanOrEqual(4);
}));
不知何故,上一个答案的解决方案对我的情况不起作用。 github 中提出的替代解决方案 flush()
也不起作用。
所以我最后的方法是检查 Google 如何为虚拟视口组件编写单元测试。在那里我注意到他们在单元测试中使用了一个函数 finishInit
,这是一个本地函数。
/** Finish initializing the virtual scroll component at the beginning of a test. */
function finishInit(fixture: ComponentFixture<any>) {
// On the first cycle we render and measure the viewport.
fixture.detectChanges();
flush();
// On the second cycle we render the items.
fixture.detectChanges();
flush();
// Flush the initial fake scroll event.
animationFrameScheduler.flush();
flush();
fixture.detectChanges();
}
将其复制到我的单元测试中,这似乎适用于我的情况。
它还有点解释了后端发生的事情。
我在我的组件中使用 cdk-virtual-scroll-viewport
+ cdkVirtualFor
,它似乎工作正常。
然而,在该组件的单元测试中,项目不会被渲染。
我制作了一个示例应用程序 based on this example,虽然该示例在您为该应用程序提供服务时有效,但我编写的测试失败了。
app.module.ts
import { ScrollingModule } from '@angular/cdk/scrolling';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
ScrollingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
app.component.html
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
<div *cdkVirtualFor="let item of items" class="example-item">{{ item }}</div>
</cdk-virtual-scroll-viewport>
app.component.spec.ts
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { ScrollingModule } from '@angular/cdk/scrolling';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
ScrollingModule,
],
}).compileComponents();
}));
it('should render at least 4 items', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement as HTMLElement;
expect(compiled.querySelectorAll('.example-item').length).toBeGreaterThanOrEqual(4); // <-- Error: Expected 0 to be greater than or equal 4.
});
});
将单元测试(参见问题)更改为以下解决方法:
it('should render at least 4 items', fakeAsync(() => { // <---
const fixture = TestBed.createComponent(AppComponent);
fixture.autoDetectChanges(); // <---
tick(500); // <---
const compiled = fixture.debugElement.nativeElement as HTMLElement;
expect(compiled.querySelectorAll('.example-item').length).toBeGreaterThanOrEqual(4);
}));
不知何故,上一个答案的解决方案对我的情况不起作用。 github 中提出的替代解决方案 flush()
也不起作用。
所以我最后的方法是检查 Google 如何为虚拟视口组件编写单元测试。在那里我注意到他们在单元测试中使用了一个函数 finishInit
,这是一个本地函数。
/** Finish initializing the virtual scroll component at the beginning of a test. */
function finishInit(fixture: ComponentFixture<any>) {
// On the first cycle we render and measure the viewport.
fixture.detectChanges();
flush();
// On the second cycle we render the items.
fixture.detectChanges();
flush();
// Flush the initial fake scroll event.
animationFrameScheduler.flush();
flush();
fixture.detectChanges();
}
将其复制到我的单元测试中,这似乎适用于我的情况。 它还有点解释了后端发生的事情。