WhiteMountain
WhiteMountain

Reputation: 43

"TypeError: cannot read property 'prototype' of undefined" when Jest testing react component that includes c3 chart

I have a react component that imports c3 and builds a c3 chart. Works fine, I can see the c3 chart.

I'm trying to test my react code with Jest, so I started a simple test for my react component, just an import for the component and test that verifies the component is 'truthy' (not null/not undefined), but I'm getting the following error when trying to run the test:

● Test suite failed to run

  TypeError: Cannot read property 'prototype' of undefined


  at node_modules/c3/c3.js:3578:29
  at node_modules/c3/c3.js:4266:5
  at node_modules/c3/c3.js:3:83
  at Object.<anonymous> (node_modules/c3/c3.js:6:2)
  at Object.<anonymous> (src/ChartPanel.tsx:2075:49)
  at Object.<anonymous> (src/module.ts:131:25)
  at Object.<anonymous> (src/module.test.ts:1:1)

Any idea? What am I missing here?

Example: Here is code using a react sample app, just modified it to include a custom component with simple c3 chart:

App.js

import React from 'react';
import './App.css';
import { Chart } from './Chart';

function App() {
  return (
    <div className="App">
      <div className="App-link-container">
        <a className="App-link"
           href="https://reactjs.org"
           target="_blank"
           rel="noopener noreferrer">
           Learn React
        </a>
      </div>
      <Chart />
    </div>
  );
}
export default App;

Chart.js (component with very simple c3 chart)

import React, { PureComponent } from 'react';
import c3 from 'c3';

export class Chart extends PureComponent {
  _chart;

  componentDidMount() {
    this._renderChart();
  }

  componentDidUpdate() {
    this._renderChart();
  }

  _renderChart() {
    this._chart = c3.generate({
      bindto: '#chart',

        data: {
            columns: [
                ['data1', 30, 200, 100, 400, 150, 250],
                ['data2', 50, 20, 10, 40, 15, 25]
            ]
        }
    });
  }

  render() {
    return <div id="chart">hi</div>;
  }
}

Test (just verifying the 'Learn React' link is on the document. Seems the error is already fired in the import of the Chart component at the App.js)

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  const { getByText } = render(<App />);
  const linkElement = getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

Jest configured in package.json as following

  "jest": {
    "roots": [
      "<rootDir>/src"
    ],
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,ts,tsx}",
      "!src/**/*.d.ts"
    ],
    "setupFiles": [
      "react-app-polyfill/jsdom"
    ],
    "setupFilesAfterEnv": [
      "<rootDir>/src/setupTests.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
      "<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
    ],
    "testEnvironment": "jest-environment-jsdom-fourteen",
    "transform": {
      "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
      "^.+\\.module\\.(css|sass|scss)$"
    ],
    "modulePaths": [],
    "moduleNameMapper": {
      "^react-native$": "react-native-web",
      "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
    },
    "moduleFileExtensions": [
      "web.js",
      "js",
      "web.ts",
      "ts",
      "web.tsx",
      "tsx",
      "json",
      "web.jsx",
      "jsx",
      "node"
    ],
    "watchPlugins": [
      "jest-watch-typeahead/filename",
      "jest-watch-typeahead/testname"
    ]
  }

While setupTests.js has nothing special but the following line

import '@testing-library/jest-dom/extend-expect';

Upvotes: 4

Views: 3560

Answers (1)

seanplwong
seanplwong

Reputation: 1091

There is a similar issue: https://github.com/thymikee/jest-preset-angular/issues/113

This is because jsdom doesn't provide an implementation for svg related api. If you follow the stacktrace to c3.js, you will find it is pointing right to

c3 adding prototype

you just need to provide the stub c3 need in setupTests.js:

window.SVGPathElement = jest.fn();

A side note: it is better to put setupTests.js somewhere else so that it will not get compiled or published.

Upvotes: 8

Related Questions