Why is nivo's responsive line chart not rendered in jsdom when using Jest?

1.9k views Asked by At

I am writing Ui tests for my app using Jest/Testing Library.

I am using ResponsiveLine component from @nivo/line

However, it never renders in jsdom.

I have confirmed the conditional of tableData is met, by putting a div inside of the conditional.

It's just the Responsive Line that is not rendered.

How can I make this to work?

useEffect(() => {
    if (process.env.NEXT_PUBLIC_IS_TESING) {
      const data = [ // *** this is accurate ***
        {
          id: 'Net Income',
          lineStyle: 'dotted',
          lineColor: '#e5b122',
          data: [
            { x: 'Jan 2016', y: 88278.24 },
            { x: 'Mar 2016', y: -9110.28 },
            { x: 'May 2016', y: -12446.832 },
            { x: 'Jul 2016', y: -1979.005714 },
            { x: 'Sep 2016', y: 6513.386667 },
          ],
        },
        {
          id: 'EBITDA',
          lineStyle: 'solid',
          lineColor: '#e5b122',
          data: [
            { x: 'Jan 2016', y: 88278.24 },
            { x: 'Mar 2016', y: -9110.28 },
            { x: 'May 2016', y: -12446.832 },
            { x: 'Jul 2016', y: -1979.005714 },
            { x: 'Sep 2016', y: 6513.386667 },
          ],
        },
        {
          id: 'Total Expenses',
          lineStyle: 'solid',
          lineColor: '#E8664E',
          data: [
            { x: 'Jan 2016', y: 88278.24 },
            { x: 'Mar 2016', y: -9110.28 },
            { x: 'May 2016', y: -12446.832 },
            { x: 'Jul 2016', y: -1979.005714 },
            { x: 'Sep 2016', y: 6513.386667 },
          ],
        },
        {
          id: 'Total COGS',
          lineStyle: 'solid',
          lineColor: '#a5a5a5',
          data: [
            { x: 'Jan 2016', y: 88278.24 },
            { x: 'Mar 2016', y: -9110.28 },
            { x: 'May 2016', y: -12446.832 },
            { x: 'Jul 2016', y: -1979.005714 },
            { x: 'Sep 2016', y: 6513.386667 },
          ],
        },
        {
          id: 'Total Revenue',
          lineStyle: 'solid',
          lineColor: '#6ac5a9',
          data: [
            { x: 'Jan 2016', y: 88278.24 },
            { x: 'Mar 2016', y: -9110.28 },
            { x: 'May 2016', y: -12446.832 },
            { x: 'Jul 2016', y: -1979.005714 },
            { x: 'Sep 2016', y: 6513.386667 },
          ],
        },
      ];
      setTableData(data);
    }
  }, []);

  return (
    <Box width={1} height={600}>
      {tableData && ( // **** conditionals are met 100 % ****
        <ResponsiveLine // **** here is the component never rendered ***
          data-testid="responsive-line"
          data={tableData}
          margin={{ top: 20, right: 40, bottom: 80, left: 70 }}
          xScale={{ type: 'point' }}
          yScale={{
            type: 'linear',
            reverse: false,
            min,
            max,
          }}
          yFormat=" >-$,.0f"
          axisTop={null}
          axisRight={null}
          axisBottom={{
            tickSize: 5,
            tickPadding: 5,
            tickRotation: -50,
          }}
          axisLeft={{
            tickSize: 5,
            tickPadding: 5,
            tickRotation: 0,
            format: ' >-$,.0f',
          }}
          enablePoints={false}
          useMesh={true}
          colors={plots.map((plot) => {
            return plot.lineColor;
          })}
          layers={[
            'grid',
            'markers',
            'axes',
            'areas',
            'crosshair',
            Line,
            'points',
            'slices',
            'mesh',
            'legends',
          ]}
          enableSlices="x"
          sliceTooltip={({ slice }) => {
            return (
              <Paper
                sx={{
                  fontFamily: 'Arial',
                  padding: '20px !important',
                }}
                elevation={5}
              >
                <Box width={1} mb={1}>
                  Month: {slice.points[0].data.xFormatted}
                </Box>
                {slice.points.map((point) => (
                  <Box width={1} pb={1} key={point.id}>
                    <Grid container alignItems="center">
                      <Box
                        mr={1}
                        height={10}
                        width={10}
                        style={{ backgroundColor: point.serieColor }}
                      ></Box>{' '}
                      {point.serieId}
                      {' -'}
                      <Box ml={1}>
                        <strong>{point.data.yFormatted}</strong>
                      </Box>
                    </Grid>
                  </Box>
                ))}
              </Paper>
            );
          }}
          legends={[
            {
              anchor: 'bottom',
              direction: 'row',
              justify: false,
              translateX: 0,
              translateY: 80,
              itemsSpacing: 0,
              itemDirection: 'left-to-right',
              itemWidth: legendItemWidth,
              itemHeight: 20,
              itemOpacity: 0.75,
              symbolSize: 40,
              symbolShape: (props) => {
                const plot = plots.find((plot) => {
                  return plot.name === props.id;
                });
                if (plot) {
                  if (plot.lineStyle === 'dotted') {
                    return <SymbolDottedDash {...props} />;
                  } else if (plot.lineStyle === 'dotted-small') {
                    return <SymbolDottedSmallDash {...props} />;
                  }
                }

                return <SymbolDash {...props} />;
              },

              effects: [
                {
                  on: 'hover',
                  style: {
                    itemBackground: 'rgba(0, 0, 0, .03)',
                    itemOpacity: 1,
                  },
                },
              ],
            },
          ]}
        />
      )}
    </Box>
  );
};

export default React.memo(DataTable);
2

There are 2 answers

0
Emre A On

If i am not wrong; nivo doesnt render custom data-* props. So giving it a data-testid might not work. https://github.com/plouc/nivo/blob/master/packages/line/src/Line.js

Check how nivo tests Line graph components. https://github.com/plouc/nivo/blob/master/packages/line/tests/Line.test.js

3
Yogi Mayi On

After debugging the Nivo core library, the responsive wrapper caused the issue by consuming the ResizeObserver browser API. Because you cannot use the ResizeObserver in jest-dom since it is not supported yet.

I have found the workaround for the scenario to mock ResizeObserver and supply the contentRect values from the test.

Here's working example