@ViewChild('scroller')
scroller!: CdkVirtualScrollViewport;
constructor(private ngZone: NgZone) { }
ngAfterViewInit(): void {
this.unsub = this.scroller.elementScrolled().pipe(
map(() => this.scroller.measureScrollOffset('bottom')),
pairwise(),
filter(([y1, y2]) => (y2 < y1 && y2 < 140)),
throttleTime(200)
).subscribe(() => {
this.ngZone.run(() => {
(this.maxItems > this.listItems.length) && this.fetchMore();
});
})
}
<cdk-virtual-scroll-viewport class="example-viewport" #scroller itemSize="72">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Symbol </th>
<td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</cdk-virtual-scroll-viewport>
test case:
it('should check \'ngAfterViewInit\'', () => {
component.ngAfterViewInit();
changeDetectorRef.detectChanges();
spyOn(virtualScrollViewport, 'elementScrolled').and.callThrough();
expect(virtualScrollViewport.elementScrolled).toHaveBeenCalled();
});
The error trace what I got when mocking
Error: Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.
at new CdkVirtualScrollViewport (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/__ivy_ngcc__/fesm2015/scrolling.js:1264:1)
at new MockCdkVirtualScrollViewport (http://localhost:9876/_karma_webpack_/main.js:27773:9)
at Object.factory (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17371:1)
at R3Injector.hydrate (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17247:42)
at R3Injector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:16997:1)
at NgModuleRef$1.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:36383:1)
at TestBedRender3.inject (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:3227:1)
at Function.inject (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:3110:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/components/gridview/gridview.component.spec.ts:112:37)
A possible implementation of the mock class could be like this:
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { Subject } from 'rxjs';
export class MockCdkVirtualScrollViewport implements CdkVirtualScrollViewport {
scrolledIndexChange: Subject<number> = new Subject<number>();
elementScrolled: Subject<Event> = new Subject<Event>();
setRenderedRange(): void { }
getRenderedRange(): any { }
// add any other properties and methods that are needed for your test
}
You can use it in your tests like so:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component } from '@angular/core';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { MockCdkVirtualScrollViewport } from './mock-cdk-virtual-scroll-viewport';
describe('YourComponent', () => {
let component: YourComponent;
let fixture: ComponentFixture<YourComponent>;
let virtualScrollViewport: CdkVirtualScrollViewport;
beforeEach(async () => {
// configure the test module with the mock class
await TestBed.configureTestingModule({
declarations: [ YourComponent ],
providers: [
{ provide: CdkVirtualScrollViewport, useClass: MockCdkVirtualScrollViewport }
]
}).compileComponents();
// create an instance of the component and the mock class
fixture = TestBed.createComponent(YourComponent);
component = fixture.componentInstance;
virtualScrollViewport = TestBed.inject(CdkVirtualScrollViewport);
});
it('should do something', () => {
// use the methods and properties of the mock class in your test
// for example you can call the `setRenderedRange()` method and check that it works as expected
});
});