ngx-virtual-scroller
ngx-virtual-scroller copied to clipboard
Unit testing the virtual scroll
I want to unit test the virtual scroll please suggest the way to test this scenario I have the component.html
<virtual-scroll [items]="items" (update)="viewPortItems = $event">
<list-item *ngFor="let item of viewPortItems" [item]="item">
<div>{item.name}</div>
</list-item>
</virtual-scroll>
in my spec file i'm trying to test the debug element of virtual-scroll to check the childnodes to the length of mock data. but the child nodes doesn't have the <div/>
element inside the <list-item/>
let ListItemElement = riskfixture.debugElement.query(By.css('list-item'));
expect(mdlListItemElement.childNodes.length).toBe(mockData.length);
when i log the ListItemElement i see below
<virtual-scroll _ngcontent-c3="">
<list-item _ngcontent-c3="">
<!--bindings={}-->
</list-item>
<router-outlet _ngcontent-c3=""></router-outlet>
</virtual-scroll>
Please help how can i achieve the unittesting
@sanjaybhaskar You need to test it asynchronously as viewPortItems variable is calculated in requestAnimationFrame. Example:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
...
it('should display logs', async(() => {
fixture.whenStable().then(() => {
fixture.detectChanges();
const logs = fixture.debugElement.queryAll(By.css('.log'));
expect(logs.length).toBe(component.logs.length);
});
}));
I am testing it asynchronously , however the virtual-scroll won't populate at all. I am using ngrx This is the test:
it('should create items', async(() => {
store.dispatch(
new ItemsSuccessAction([
{
name: 'item1',
}
])
);
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.debugElement.query(By.directive(ItemComponent))).toBeTruthy();
});
}))
If I select the state, I can see that the items get saved into the store OK. However in the virtual scroll there are no items at all.
My HTML template:
<virtual-scroll [items]="items$ | async" (update)="items= $event" (change)="fetchMore()">
<div #container>
<item *ngFor="let items of items">
<div>...</div>
</item>
</div>
</virtual-scroll>
What do you think is the reason?
hey @alexanto, did you have any luck with testing the scroll? We're having the same problem. I'd like to be able to test my component, but the virtual scroll isn't adding any rows to the DOM. At this point, even disabling the virtualisation during tests would be preferable
For me the solution was to manually emit the update event in the test:
const virtualScrollComponent = fixture.debugElement.query(By.directive(VirtualScrollComponent)).componentInstance;
component.items$.subscribe(items => {
virtualScrollComponent.update.emit(items);
});
@alexanto thanks for the info! I'll give this a try
I have the same problem, the solution provided by @alexanto works, but it's quite useless in my scenario...I can't test my component properly because my items are runtime filtered by some | pipes. @rintoj any way to test it?
If anyone comes up with a solution to this problem, please submit a pull request and I'll be happy to merge it. Thanks.
VirtualScrollComponent
hi, how u get the dependency for this ? as the library has been changed
@sanjaybhaskar Was it working for you on a previous version of the code? If you can paste your previous code & the version number it was working with, I can help you upgrade it to the latest version.
If this helps anyone, I ended up just creating a fake component.
Do not import the VirtualScrollerModule into the test, instead, just define a component like this:
@Component({
selector: 'virtual-scroller',
template: '<ng-content></ng-content>'
})
export class FakeVirtualScrollerComponent implements OnInit {
@Input() items: any[];
viewPortItems;
ngOnInit(): void {
this.viewPortItems = this.items;
}
}
And add it as a declaration on
TestBed.configureTestingModule({
declarations: [
If this helps anyone, I ended up just creating a fake component.
Do not import the VirtualScrollerModule into the test, instead, just define a component like this:
@Component({ selector: 'virtual-scroller', template: '<ng-content></ng-content>' }) export class FakeVirtualScrollerComponent implements OnInit { @Input() items: any[]; viewPortItems; ngOnInit(): void { this.viewPortItems = this.items; } }
And add it as a declaration on
TestBed.configureTestingModule({ declarations: [
Hi @ataraciuk, can you teach me how to use this fake component ? Thank you.
If this helps anyone, I ended up just creating a fake component. Do not import the VirtualScrollerModule into the test, instead, just define a component like this:
@Component({ selector: 'virtual-scroller', template: '<ng-content></ng-content>' }) export class FakeVirtualScrollerComponent implements OnInit { @Input() items: any[]; viewPortItems; ngOnInit(): void { this.viewPortItems = this.items; } }
And add it as a declaration on
TestBed.configureTestingModule({ declarations: [
Hi @ataraciuk, can you teach me how to use this fake component ? Thank you.
Not much else to do. Add the FakeVirtualScrollerComponent
in your TestBed Module configuration via declations: [FakeVirtualScrollerComponent,...]
This is only so the content you are putting inside the virtual scroller shows as if the scroller wasn't there. I'm not testing scroller behavior, it's just a workaround to test what is inside.
Using the mocked virtual scroller (by @ataraciuk ) seems the easiest option. Include all those @Input or @Output used by your virtual-scroller in the FakeVirtualScrollerComponent. And if the VirtualScrollerModule declared in some shared module imported in the tests, then remove it using overrideModule:
TestBed.configureTestingModule({
imports: [MySharedModule],
declarations: [FakeVirtualScrollerComponent ]
});
TestBed.overrideModule(MySharedModule, {
remove: {
imports: [VirtualScrollerModule],
exports: [VirtualScrollerModule]
}
});