首页 > 解决方案 > Jest & react-router-dom: React.createElement: type is invalid - 期望一个字符串(用于内置组件)......但得到:未定义

问题描述

我正在为一个组件编写测试,该组件Link来自react-router-dom.

组件本身可以正常工作而不会给出任何错误或警告。

但是,当使用shallowfrom呈现组件时enzyme,它会在控制台中显示以下错误消息。

警告:React.createElement:类型无效——需要一个字符串(对于内置组件)或一个类/函数(对于复合组件),但得到:未定义。

您可能忘记从定义组件的文件中导出组件,或者您可能混淆了默认导入和命名导入。

据我研究,当您错误地导入 React 模块(或组件)时,显然会发生此错误。

例如

import Link from 'react-router-dom'; // Wrong!
import { Link } from 'react-router-dom'; // Correct!

但是,在我的情况下,Link它是正确导入的,但它仍然给出上面的警告消息。

这是该组件的一个片段。

import React from 'react';
import { Link, useHistory } from 'react-router-dom';
// other modules here

const ListItem = (props) => {
  const history = useHistory();
  const queryParameter = _.get(history, 'location.search', '');
  const pathName = `/blah/${props.id}${queryParameter}`;

  return (
    <li>
      <Link to={pathName}>
        <div>blah blah...</div>
      </Link>
    </li>
  );
};

(当我注释掉时<Link>,警告消息将从控制台消失。所以,使用useHistory()应该与警告无关)

jest.mock('react-router-dom', () => ({
  useHistory: jest.fn()
}));

describe('ListItem', () => {
  const baseProps = { /* initial props here*/ };

  it("renders the name", () => {
    const wrapper = shallow(<ListItem {...baseProps} />);
    // the line above shows the warning message in the console
  });
});

我完全一无所知。任何建议将被认真考虑。

标签: reactjsreact-routerjestjsenzymereact-router-dom

解决方案


听起来您没有导入正确的文件(如果您有一个.(s)csstest.js文件与组件共享相同的名称并位于同一根目录中,那么 webpack 可能会将错误的文件导入到测试文件中——因此,我建议指定组件名称和扩展名:index.jsListItem.js)。否则,您可能会忘记导出ListItem组件。

工作示例(此示例使用mountRouter-- 单击Test选项卡以运行测试):

编辑测试 RRD


组件/ListItem/index.js

import React from "react";
import get from "lodash/get";
import { Link, useHistory } from "react-router-dom";

function ListItem({ children, id, destination }) {
  const history = useHistory();
  const query = get(history, ["location", "search"]);

  return (
    <li style={{ margin: 0, padding: 0 }}>
      <Link to={`${destination}/${id}${query}`}>
        <div>{children}</div>
      </Link>
    </li>
  );
}

export default ListItem;

组件/ListItem/__tests__/ListItem.test.js

import React from "react";
import { mount } from "enzyme";
import { Router } from "react-router-dom";
import { createMemoryHistory } from "history";
import ListItem from "../index.js";

const children = "Test";
const id = 1;
const destination = "/home";
const query = "?id=1";
const initialPath = `${destination}/${id}${query}`;

const history = createMemoryHistory({
  initialEntries: [initialPath]
});

const initProps = {
  children,
  id,
  destination
};

const wrapper = mount(
  <Router history={history}>
    <ListItem {...initProps} />
  </Router>
);

describe("ListItem", () => {
  afterAll(() => {
    wrapper.unmount();
  });

  it("renders the children", () => {
    expect(wrapper.find("div").text()).toEqual(children);
  });

  it("renders a Link that contains destination, params.id and query", () => {
    expect(wrapper.find("Link").props().to).toEqual(
      `${destination}/${id}${query}`
    );
  });
});

推荐阅读