TypeError: Cannot read properties of undefined (reading 'clientHeight')

Posted by: kamil.skrouba on 7 August 2024, 4:10 am EST

  • Posted 7 August 2024, 4:10 am EST - Updated 7 August 2024, 4:24 am EST

    After upgrading from version 5.20231.904 to 5.20241.19, we are encountering issues with all integrated tests written using Spectator.

     Flex Component Integrated Tests › should create the component
        TypeError: Cannot read properties of undefined (reading 'clientHeight')
    
          32 |     ngOnChanges(changes: SimpleChanges): void {
          33 |         if(changes.data) {
        > 34 |            this.gridData.sourceCollection = changes.data.currentValue;
             |                                          ^
          35 |         }
          36 |     }
          37 |
    
          at WjFlexGrid.FlexGrid.scrollIntoView (../../../node_modules/@mescius/wijmo.grid/index.js:14:118553)
          at WjFlexGrid.FlexGrid._syncSelection (../../../node_modules/@mescius/wijmo.grid/index.js:14:138965)
          at WjFlexGrid.FlexGrid._cvCurrentChanged (../../../node_modules/@mescius/wijmo.grid/index.js:14:138145)
          at WjFlexGrid.<anonymous> (../../../node_modules/@mescius/wijmo.grid/index.js:14:103823)
          at Event.raise (../../../node_modules/@mescius/wijmo/index.js:14:8786)
          at CollectionView.onCurrentChanged (../../../node_modules/@mescius/wijmo/index.js:14:84118)
          at CollectionView.moveCurrentToPosition (../../../node_modules/@mescius/wijmo/index.js:14:81294)
          at CollectionView.moveCurrentToFirst (../../../node_modules/@mescius/wijmo/index.js:14:80616)
          at CollectionView.set [as sourceCollection] (../../../node_modules/@mescius/wijmo/index.js:14:80126)
          at GridTestComponent.ngOnChanges (src/lib/grid/test-new-grid/grid-test.component.ts:34:42)
          at setProps (../../../node_modules/@ngneat/spectator/fesm2022/ngneat-spectator.mjs:110:9)
          at SpectatorHost.setInput (../../../node_modules/@ngneat/spectator/fesm2022/ngneat-spectator.mjs:545:9)
          at src/lib/grid/test-new-grid/grid-test.component.integrated.spec.ts:53:19
          at _ZoneDelegate.invoke (../../../node_modules/zone.js/bundles/zone.umd.js:412:32)
          at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (../../../node_modules/zone.js/bundles/zone-testing.umd.js:2164:43)
          at _ZoneDelegate.invoke (../../../node_modules/zone.js/bundles/zone.umd.js:411:38)
          at ZoneImpl.run (../../../node_modules/zone.js/bundles/zone.umd.js:147:47)
          at Object.wrappedFunc (../../../node_modules/zone.js/bundles/zone-testing.umd.js:450:38)

    Looks like the grid is triggering the scrollIntoView event, but in some objects, the clientHeight is undefined. This issue does not exist in version 5.20231.904.

  • Posted 7 August 2024, 4:20 am EST

    Test:

    import { CommonModule } from '@angular/common';
    import { WjGridModule } from '@mescius/wijmo.angular2.grid';
    import { WjGridDetailModule } from '@mescius/wijmo.angular2.grid.detail';
    import { WjGridFilterModule } from '@mescius/wijmo.angular2.grid.filter';
    import { WjInputModule } from '@mescius/wijmo.angular2.input';
    import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
    
    import { GridTestComponent } from './grid-test.component'
    
    describe('FlexGrid Component Integrated Tests', () => {
    
        let spectator: SpectatorHost<GridTestComponent>;
    
        const minimumGridTemplate =
            `<grid-test>
            </grid-test>`;
    
        const createComponent = createHostFactory({
            component: GridTestComponent,
            declarations: [
            ],
            imports: [
                CommonModule,
                WjInputModule,
                WjGridModule,
                WjGridDetailModule,
                WjGridFilterModule,
            ],
            providers: [
            ],
            template: minimumGridTemplate
        });
    
        it('should create the component', () => {
            spectator = createComponent();
    
            expect(spectator.component).toBeTruthy();
            const newData = [{
                id: 1000,
                country: 'US',
                sales: Math.random() * 10000,
                expenses: Math.random() * 5000
            }]
    
            spectator.setInput({
                data: newData
            });
            spectator.fixture.detectChanges();
    
            expect(spectator.component.data).toBe(newData);
        });
    });

    component:

    import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from "@angular/core";
    
    import { CollectionView, format, SortDescription } from "@mescius/wijmo";
    import { Column, FlexGrid } from "@mescius/wijmo.grid";
    
    @Component({
        selector: 'grid-test',
        templateUrl: './grid-test.component.html'
    })
    export class GridTestComponent implements OnInit, OnChanges {
        @Input() data: any[] = null;
    
        selectedItem: string;
        gridData: CollectionView;
        // references FlexGrid named 'flex' in the view
        @ViewChild('flex', { static: true }) flex: FlexGrid;
    
        // DataSvc will be passed by derived classes
        constructor() {
    
            this.gridData = new CollectionView();
    
        }
        ngOnInit(): void {
        }
    
        ngOnChanges(changes: SimpleChanges): void {
            if(changes.data) {
               this.gridData.sourceCollection = changes.data.currentValue;
            }
        }
    
        flexInitialized(flexgrid: FlexGrid) {
            // sort the data by country
            const sd = new SortDescription('country', true);
            flexgrid.collectionView.sortDescriptions.push(sd);
            flexgrid.collectionView.currentChanged.addHandler(this._updateCurrentInfo.bind(this));
            this._updateCurrentInfo();
    
            const columns = 'country,sales,expenses'.split(',')
            for (let i = 0; i < columns.length; i++) {
                this.flex.columns.push(this.mapColumn(columns[i]));
            }
    
        }
    
        private _getData() {
            // create some random data
            const countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','),
                data = [];
            for (let i = 0; i < countries.length; i++) {
                data.push({
                    id: i,
                    country: countries[i],
                    sales: Math.random() * 10000,
                    expenses: Math.random() * 5000
                });
            }
    
            return data;
        }
    
        private _updateCurrentInfo() {
            this.selectedItem = format(
                'Country: <b>{country}</b>, Sales: <b>{sales:c0}</b> Expenses: <b>{expenses:c0}</b>',
                this.flex.collectionView.currentItem);
        }
    
        private mapColumn(columnName: string): Column {
            return new Column({
                name: columnName,
                binding: columnName,
            });
        }
    }
  • Posted 8 August 2024, 6:14 am EST

    Hi Kamil,

    I am not able to replicate the issue on my end, could you please share a small sample, in which the issue can be replicated, so that I can investigate the issue further and assist you accordingly?

    Please find attached a sample in which I tried to replicate the issue. I am not very familiar with testing with Spectator, I have created a sample with the code you shared but am unable to replicate the issue. Please use ‘npm run test’ command to run the test in the attached sample. Please let me know if I missed something.

    You can also modify the attached sample to replicate the issue and share it with us.

    Regards

    angular-spectator-test.zip

  • Posted 9 August 2024, 6:38 am EST

    Hi Vivek,

    The issue wasn’t present in your original code, but after updating it to Angular 17 and adding some project-specific packages, the problem persists.

    Here is the code:

    grid-error.zip

  • Posted 13 August 2024, 9:23 am EST

    Hi Kamil,

    Thank you for sharing the updated sample, we are investigating the issue. It will take some time, we will update you as soon as possible.

    Regards

  • Posted 14 August 2024, 2:56 am EST

    Hi Kamil,

    After investigating the issue we found that Jest is using ‘jsdom’ for running tests. And ‘jsdom’ does not actually render elements in a real browser DOM, instead, it provides a simulated or “mock” DOM environment. Wijmo controls like FlexGrid, Flexchart, etc needs to be rendered in actual DOM for testing, as element heights are internally calculated and used for various purposes in Wijmo controls. So, we suggest using another DOM engine with Jest instead of ‘jsdom’ for testing, e.g. Puppeteer

    This issue was not observed in the old Wijmo version because there have been some updates in the ‘scrollIntoView’ method of FlexGrid after Wijmo version 5.20231.904, after which clientHeight of document.scrollingElement is considered for scrolling the cell into view in FlexGrid, due to which this error is observed in latest version while testing in jsdom environment.

    Regards

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels