Pooja A
Pooja A

Reputation: 73

TypeError: Cannot read property 'map' of undefined (jest.js)

I have a component that has an input and a button. When a user types a hobby in the input, it is suppose to send that string to be updated to an api. I have set up my test and I am testing whether or not the component exists and I am getting the error TypeError: Cannot read property 'map' of undefined, when I console.log(component). It says that the component is undefined.

When I comment out the {this.state.hobbies.map()} section (including the second render and everything inside of that), the component is able to render.

    EditProfile.js
    import React, { Component } from 'react';
    import { MdDelete } from 'react-icons/md';
    import { updateHobbies } from '../../services/updateHobbies';
    import './edit_profile.scss';
    import PropTypes from 'prop-types';

    class EditProfile extends Component {
      state = {
        hobbies: this.props.employeeHobbies,
        userInput: ''
      };

      handleChange = e => {
        this.setState({ userInput: e.target.value });
      };

      handleButtonClick = () => {
        const hobby = this.state.hobbies.concat(this.state.userInput);
        this.setState({ hobbies: hobby, userInput: '' }, () => 
       updateHobbies(this.state.hobbies));
      };

      handleDelete = e => {
        const array = [...this.state.hobbies];
        const index = array.indexOf(e);
        if (index !== -1) {
          array.splice(index, 1);
          this.setState({ hobbies: array }, () => 
         updateHobbies(this.state.hobbies));
        }
      };

      render() {
        return (
          <div>
            <label className='employee-label'>HOBBIES: </label>
            <span>
              <input type='text' value={this.state.userInput} onChange= 
           {this.handleChange} />
              <button className='update-details-button' onClick= 
        {this.handleButtonClick}>
                Add
              </button>

              {this.state.hobbies.map(hobbies => {
                return (
                  <li className='employee-tag-list' key={hobbies}>
                    {hobbies}
                    <span className='delete-icons' onClick={() => 
         this.handleDelete(hobbies)}>
                      <MdDelete />
                    </span>
                  </li>
                );
              })}
            </span>
          </div>
        );
      }
    }
   EditProfile.propTypes = {
  employeeHobbies: PropTypes.array
};

export default EditProfile;

EditProfile.test.js

let component;
  const chance = new Chance();
  let mockHandleChange = jest.fn();
  let mockHandleButtonClick = jest.fn();
  let mockHandleDelete = jest.fn();
  let mockUpdateHobbies;
  let mockHobbies = [chance.string(), chance.string(), chance.string()];

  function requiredProps(overrides = {}) {
    return {
      handleChange: mockHandleChange,
      handleButtonClick: mockHandleButtonClick,
      handleDelete: mockHandleDelete,
      ...overrides
    };
  }

  function renderComponent(props = requiredProps()) {
    return shallow(<Hobbies {...props} />);
  }

  beforeEach(() => {
    component = renderComponent();
  });

  it('should exist', () => {
    console.log(component.debug());
    expect(component).toHaveLength(1);
  });

I expected the test to pass but I am getting the error, TypeError: Cannot read property 'map' of undefined

Upvotes: 6

Views: 12843

Answers (1)

GregL
GregL

Reputation: 38151

There are a few things that you can do, that all aim to solve the core problem: you are not supplying a value for the employeeHobbies prop in your test.

Pick one of the following:

  1. As @Hoyen suggested, add default props to specify an empty array for employeeHobbies if it isn't supplied. EditProfile.defaultProps = { employeeHobbies: [] };.
  2. In your requiredProps() function in your test file, specify a value for employeeHobbies of an empty array along with your other properties like handleChange, handleButtonClick, etc.
  3. When initializing state.employeeHobbies, set it to this.props.employeeHobbies || [], so it has a fallback value if passed null or nothing (undefined).

I also recommend you specify the proptype for employeeHobbies as PropTypes.array.isRequired to get a helpful warning when the array isn't supplied. That will guard against misuse of the component, and violating the contract it needs to work.

Upvotes: 3

Related Questions