Home > Software engineering >  TypeError: Cannot read properties of undefined (reading 'property')
TypeError: Cannot read properties of undefined (reading 'property')

Time:05-12

The error is the next.

    TypeError: Cannot read properties of undefined (reading 'name')

      32 |           type="text"
      33 |           placeholder="Full Name"
    > 34 |           value={employee.name}
         |                           ^
      35 |           onChange={(e) => setEmployee({ ...employee, name: e.target.value })}
      36 |         />
      37 |       </div>

Here is the code where I'm trying to see why is not reading correctly the property name.

import React, { useContext, useState } from "react";
import unid from "uniqid";
import { EmployeesContext } from "../context/EmployeesContext";
import { useNavigate, useParams } from "react-router-dom";

export const EditEmployee = ({ id }) => {
  const navigate = useNavigate();
  const params = useParams();

  id = params?.id;

  const { employees, setEmployees } = useContext(EmployeesContext);

  const [employee, setEmployee] = useState(
    employees.find(({ dni }) => dni === id)
  );

  const saveEmployee = (id, emp) => {
    setEmployees(
      employees.map((employee) =>
        employee.dni === id ? (employee = emp) : employee
      )
    );
    navigate("/");
  };

  return (
    <div className="add-employee">
      <div className="field">
        <label>Name</label>
        <input
          type="text"
          placeholder="Full Name"
          value={employee.name}
          onChange={(e) => setEmployee({ ...employee, name: e.target.value })}
        />
      </div>
      <div className="field">
        <label>DNI</label>
        <input
          type="text"
          placeholder="DNI"
          value={employee.dni}
          onChange={(e) => setEmployee({ ...employee, dni: e.target.value })}
        />
        <button
          onClick={() => {
            setEmployee({ ...employee, dni: "" });
            setEmployee({ ...employee, dni: unid().toUpperCase() });
          }}
        >
          Generate
        </button>
      </div>
      <div className="field">
        <label>Birth date</label>
        <input
          type="text"
          placeholder="DD/MM/YYYY"
          value={employee.birth}
          onChange={(e) => setEmployee({ ...employee, birth: e.target.value })}
        />
      </div>
      <div className="field">
        <label>Address</label>
        <input
          type="text"
          placeholder="Address"
          value={employee.address}
          onChange={(e) =>
            setEmployee({ ...employee, address: e.target.value })
          }
        />
      </div>
      <div className="field">
        <label>Phone</label>
        <input
          type="text"
          placeholder="Phone"
          value={employee.phone}
          onChange={(e) => setEmployee({ ...employee, phone: e.target.value })}
        />
      </div>
      <div className="field">
        <label>Email</label>
        <input
          type="text"
          placeholder="Email"
          value={employee.email}
          onChange={(e) => setEmployee({ ...employee, email: e.target.value })}
        />
      </div>
      <div className="field">
        <label>Position</label>
        <input
          type="text"
          placeholder="Position"
          value={employee.position}
          onChange={(e) =>
            setEmployee({ ...employee, position: e.target.value })
          }
        />
      </div>

      <div className="actions">
        <button onClick={() => saveEmployee(id, employee)}>Confirm</button>
        <button onClick={() => navigate("/")}>Cancel</button>
      </div>
    </div>
  );
};

And the test that I'm trying to execute is the next. I don't know how to pass a new employee if my code I suppose that with the id that I'm providing in test it is searching for the correct employee so I hope you could help me to clarify my fail here.

  // should render and save input position
  it("should render and save input position", () => {
    const wrapper = mount(
      <EmployeesContext.Provider value={{ employees, setEmployees }}>
        <EditEmployee id="MBJ34368V12P5" />
      </EmployeesContext.Provider>
    );
    const input = wrapper.find("#position");
    expect(input.props().value).toBe("Front-end Developer");
  });

Here is the data that I'm providing in the test case.

const empData = [
  {
    name: "Jaime Armando Straus",
    address: "Los Angeles, CA",
    dni: "MBJ34368V12P5",
    birth: "19/03/1998",
    phone: "5628903455",
    email: "[email protected]",
    position: "Front-end Developer",
  },
  {
    name: "Jose Armando Straus",
    address: "Washington, DC",
    dni: "NFIN3543543NKBN",
    birth: "19/03/1980",
    phone: "5628903455",
    email: "[email protected]",
    position: "Back-end Developer",
  },
];

export const employees = [...empData];
export const setEmployees = jest.fn();

CodePudding user response:

useState argument is the initial value. On your first render, you are using useParams from react-router-dom to extract the id and find the employee from your array provided by the context.

So when id is not supplied, your employee value will be undefined and hence you will get the error.

You can simply add a console.log to check the value present in employee object.

 const [employee, setEmployee] = useState(
    employees.find(({ dni }) => dni === id)
  );
 console.log({employee})

CodePudding user response:

Try to add default value also.

const [employee, setEmployee] = useState(
    employees.find(({ dni }) => dni === id) || {}
  );
  • Related