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

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

我有一个导入 c3 并构建 c3 图表的 React 组件。效果很好,我可以看到c3图表。

我正在尝试用 Jest 测试我的 React 代码,所以我开始对我的 React 组件进行简单测试,只是导入组件并测试验证组件是 'truthy'(不是 null/not undefined), 但在尝试 运行 测试时出现以下错误:

● 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)

有什么想法吗?我在这里错过了什么?

示例: 这是使用 React 示例应用程序的代码,只是对其进行了修改以包含带有简单 c3 图表的自定义组件:

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(带有非常简单的 c3 图表的组件)

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>;
  }
}

测试(只是验证 'Learn React' link 在文档上。似乎错误已经在 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 在package.json 中配置如下

  "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"
    ]
  }

虽然 setupTests.js 除了下面这行没有什么特别之处

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

有一个类似的问题:https://github.com/thymikee/jest-preset-angular/issues/113

这是因为jsdom没有提供svg相关的实现api。如果您跟随堆栈跟踪到 c3.js,您会发现它正指向

你只需要在 setupTests.js:

中提供存根 c3 需要
window.SVGPathElement = jest.fn();

旁注:最好将 setupTests.js 放在其他地方,这样它就不会被编译或发布。