When using React-Virtualized AutoSizer, children not being rendered in test
Asked Answered
B

2

12

I have a component which uses react-virtualized AutoSizer, and inside this component there is a react-virtualized List. The way it is rendered is:

<AutoSizer>
  {({width, height}) => (
    <List ref={(ref) => (this.refVirtualizedList = ref)}
      width={width}
      height={height}
      playlistLoading={playlistLoading}
      playlistPlayingTrackId={playlistPlayingTrackId}
      rowCount={rowCount}
      deferredMeasurementCache={this.cellMeasurerCache}
      overscanRowCount={12}
      scrollToIndex={trackGroupToGo - 1}
      scrollToAlignment="center"
      rowHeight={this.cellMeasurerCache.rowHeight}
      updateTrackListFlag={updateTrackListFlag}
      noRowsRenderer={this.renderNoRowsResult}
      rowRenderer={this.renderTrackGroupRow}
      onRowsRendered={this.handleOnRowsRendered} />
  )}
</AutoSizer>

It works perfectly, but it is not working on tests. I cannot see anything inside the list, and the function rowRenderer is never being called. I'm using Jest and React Testing Library. When checking what's inside the component with the logDOM method, all I see is this:

<div
  aria-label="grid"
  aria-readonly="true"
  class="ReactVirtualized__Grid ReactVirtualized__List"
  role="grid"
  style="box-sizing: border-box; direction: ltr; height: 0px; position: relative; width: 0px; will-change: transform; overflow-x: hidden; overflow-y: auto;"
  tabindex="0"
/>

The List component is never rendered. Any ideas?

Borrego answered 5/6, 2020 at 11:56 Comment(0)
B
34

Thanks to this issue on GitHub: https://github.com/bvaughn/react-virtualized/issues/493

All I needed to do is set up the tests to "mock" some behavior for AutoSizer:

Copying the same solution that you can find in the issue:

describe("My Test", () => {
  const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight');
  const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth');

  beforeAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { configurable: true, value: 50 });
    Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { configurable: true, value: 50 });
  });

  afterAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'offsetHeight', originalOffsetHeight);
    Object.defineProperty(HTMLElement.prototype, 'offsetWidth', originalOffsetWidth);
  });
  // Your tests
})

The List component is now being rendered!

Borrego answered 5/6, 2020 at 11:56 Comment(0)
P
2

Alternatively, in your global setup, you can define the jsDom properties like so:

// jsDom does not implement offset* methods.  This will break tests 
// for components that use react-virtualized-auto-sizer 
// (https://github.com/jsdom/jsdom/issues/135#issuecomment-68191941)
Object.defineProperties(window.HTMLElement.prototype, {
    offsetLeft: {
        get: function () {
            return parseFloat(window.getComputedStyle(this).marginLeft) || 0;
        }
    },
    offsetTop: {
        get: function () {
            return parseFloat(window.getComputedStyle(this).marginTop) || 0;
        }
    },
    offsetHeight: {
        get: function () {
            return parseFloat(window.getComputedStyle(this).height) || 0;
        }
    },
    offsetWidth: {
        get: function () {
            return parseFloat(window.getComputedStyle(this).width) || 0;
        }
    }
});
Palfrey answered 29/10, 2021 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.