1

I've got project made by create-react-app, using styled components and I'm trying to test some DOM elements of this component in many other ways and always got the same issue. For example here I just want to log whats shallow return.

Here is my BattleGround.js component:

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;

Here is my 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)
})

And here is my testSetup.js if it;s need:

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;

Console Error:

 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)

Obvious is that props cards is undefinded when the tests gone through the component but I don't know why. This components should have props from App component when render.

2 Answers 2

1

You are not supplying with props in simple test. Since you are not defining default values, cards is undefined.

it('Simple test', () => {
  const wrapper = shallow(<BattleGround />)
  console.log(wrapper)
})
Sign up to request clarification or add additional context in comments.

Comments

0

Have you tried adding a condition to the renderCards, as below, which will ensure the map function only runs when the cards are loaded from props?

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.