在Jest.js中反应测试组件并得到TypeError:无法读取未定义的属性“ map”

时间:2019-09-25 16:13:21

标签: reactjs jestjs enzyme

我有一个由create-react-app创建的项目,使用了样式化的组件,并且我试图以许多其他方式测试该组件的某些DOM元素,并且总是遇到相同的问题。例如,在这里我只想记录什么是浅收益。

这是我的BattleGround.js组件:

import React, { PureComponent, Fragment } from "react";

import { Title } from "../Common/TitleStyled/TitleStyled";
import { BattleWrapper } from "./BattleWrapperStyled/BattleWrapperStyled";
import { Table } from "./TableStyled/TableStyled";
import { Header } from "../Common/HeaderStyled/HeaderStyled";
import { Result } from "./ResultStyled/ResultStyled";
import { Button } from "../Common/ButtonStyled/ButtonStyled";
import { Loading } from "../Common/LoadingStyled/LoadingStyled";
import { ErrorPage } from "../Common/ErrorPageStyled/ErrorPageStyled";
import CardItem from "../CardItem/CardItem";

class BattleGround extends PureComponent {
  state = {
    atributes: [],
    category: null,
    loading: false
  };

  componentDidMount() {
    this.setAtributes();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.cards !== this.props.cards) {
      this.setState({
        atributes: []
      });
      this.setAtributes();
    }
  }

  renderCard = () => {
    const { cards } = this.props;

    return cards.map((card, key) => {
      return <CardItem card={card} key={key} id={key + 1} />;
    });
  };

  setAtributes = () => {
    const { cards } = this.props;

    cards.forEach(atr => {
      this.setState(state => ({
        atributes: [...state.atributes, atr.mass || atr.crew],
        category: atr.mass ? "people" : "starships"
      }));
    });
  };

  checkWhoWins = () => {
    const { atributes } = this.state;

    if (atributes[0] === "unknown" || atributes[1] === "unknown") {
      return <h2>Atribute unknown. Play again</h2>;
    } else if (parseInt(atributes[0]) > parseInt(atributes[1])) {
      return <h2>Player 1 Wins!</h2>;
    } else if (parseInt(atributes[0]) < parseInt(atributes[1])) {
      return <h2>Player 2 Wins!</h2>;
    } else {
      return <h2>Draw!</h2>;
    }
  };

  playAgain() {
    const { clearCards, fetchCards } = this.props;
    const { category } = this.state;

    this.setState({
      loading: true
    });
    clearCards();
    fetchCards(category);
    fetchCards(category).then(() => this.closeLoading());
  }

  closeLoading() {
    this.setState({
      loading: false
    });
  }

  render() {
    const { errorFetch, resetGame } = this.props;
    const { atributes, loading } = this.state;

    return (
      <Fragment>
        <Header>
          <Title>Moon Wars</Title>
          {errorFetch && <ErrorPage>{errorFetch}</ErrorPage>}
        </Header>
        <BattleWrapper>
          <Table>{this.renderCard()}</Table>
          <Result>{atributes.length === 2 && this.checkWhoWins()}</Result>
          <Button onClick={() => this.playAgain()}>PLAY AGAIN</Button>
          <Button onClick={() => resetGame()}>Go Back</Button>
        </BattleWrapper>
        {loading && <Loading />}
      </Fragment>
    );
  }
}

export default BattleGround;

这是我的BattleGround.test.js:

import BattleGround from "./BattleGround";

it("renders correctly", () => {
  const wrapper = shallow(
    <BattleGround
      cards={ [{name: "Luke", mass: 10}] }
      clearCards={() => {}}
      fetchCards={() => {}}
      errorFetch={() => {}}
      resetGames={() => {}}
    />
  );

  expect(wrapper).toMatchSnapshot();
});

it("renders correctly detailed", () => {
  const wrapper = render(
    <BattleGround
      cards={[{ name: "Luke", mass: 10 }]}
      clearCards={() => {}}
      fetchCards={() => {}}
      errorFetch={() => {}}
      resetGames={() => {}}
    />
  );

  expect(wrapper).toMatchSnapshot();
});

it('Simple test', () => {
  const wrapper = shallow(<BattleGround />)
  console.log(wrapper)
})

如果需要,这是我的testSetup.js:

import React from "react";
import Enzyme, { shallow, render, mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { createSerializer } from "enzyme-to-json";
import sinon from "sinon";
import expectExport from "expect";

expectExport.addSnapshotSerializer(createSerializer({ mode: "deep" }));

Enzyme.configure({ adapter: new Adapter() });

global.React = React;
global.shallow = shallow;
global.render = render;
global.mount = mount;
global.sinon = sinon;

控制台错误:

 FAIL  src/components/BattleGround/BattleGround.test.js
  ✕ Simple test (36ms)
  Renders check
    ✓ renders correctly (9ms)
    ✓ renders correctly detailed (60ms)

  ● Simple test

    TypeError: Cannot read property 'map' of undefined

      34 |     const { cards } = this.props;
      35 | 
    > 36 |     return cards.map((card, key) => {
         |                  ^
      37 |       return <CardItem card={card} key={key} id={key + 1} />;
      38 |     });
      39 |   };

      at BattleGround.map [as renderCard] (src/components/BattleGround/BattleGround.js:36:18)
      at BattleGround.renderCard [as render] (src/components/BattleGround/BattleGround.js:95:24)
      at ReactShallowRenderer._mountClassComponent (node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:845:37)
      at ReactShallowRenderer.render (node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:768:14)
      at render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:666:53)
      at fn (node_modules/enzyme-adapter-utils/src/Utils.js:99:18)
      at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:666:18)
      at new render (node_modules/enzyme/src/ShallowWrapper.js:397:22)
      at shallow (node_modules/enzyme/src/shallow.js:10:10)
      at Object.shallow (src/components/BattleGround/BattleGround.test.js:33:19)

很明显,当测试通过组件时,道具卡是未定义的,但我不知道为什么。渲染时,这些组件应具有来自App组件的道具。

2 个答案:

答案 0 :(得分:1)

您没有在简单测试中提供道具。 由于您未定义默认值,因此未定义卡。

it('Simple test', () => {
  const wrapper = shallow(<BattleGround />)
  console.log(wrapper)
})

答案 1 :(得分:0)

您是否尝试过如下所示的条件向renderCards添加条件,以确保map功能仅在从道具加载卡片时才运行?

renderCard = () => {
    const { cards } = this.props;

    return cards ? cards.map((card, key) => {
      return <CardItem card={card} key={key} id={key + 1} />;
    }: null);
  };