Home > Mobile >  Cannot trigger callback function from react component in jest
Cannot trigger callback function from react component in jest

Time:10-17

I'm trying to write some jest tests for a simple weather web app I made with React. When I run my test, it creates a snapshot of the component and it looks ok, but when I try to trigger a click event I get a type error:

TypeError: tree.props.handleClick is not a function

I used the jest docs to write this test and I thought this was how you triggered a click event. Am I not referencing the click function correctly? I'm new to writing tests so any info on writing tests for React with jest are welcome!

React code

import React from "react"
import { useEffect, useState } from 'react'
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

const CityEntry = ({ weatherDatum, deleteLocation }) => {
  const capitalizeFirstLetter = (string) => {
    return string.charAt(0).toUpperCase()   string.slice(1);
  }

  const handleClick= () => {
    deleteLocation(weatherDatum.id)
  }

  return (
    <div className="city">
      <p className="location flex-item">{capitalizeFirstLetter(weatherDatum.location)} </p>
      <p className="temp flex-item">{weatherDatum.temperature}  &#x2109;</p>
      <p className="feels-like flex-item">Feels like: {weatherDatum.feelsLike}</p>
      <p className="description flex-item">{capitalizeFirstLetter(weatherDatum.description)}</p>
      <p><img className="icon flex-item" src={`https://openweathermap.org/img/w/${weatherDatum.icon}.png`}></img></p>
      <button className="delete" onClick={handleClick}>Delete</button>
    </div>
  )
}

export default CityEntry;

Jest test code

import renderer from 'react-test-renderer';
import CityEntry from '../src/Components/CityEntry.js'

it('deletes a city entry when clicked', () => {
  const component = renderer.create(
    <CityEntry weatherDatum={{ id: '', lat: '', lon: '', location: '', temperature: '', feelsLike: '', description: '', icon: '' }} />
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot()

  renderer.act(() => {
    tree.props.handleClick()
  });

  tree = component.toJSON();
  expect(tree).toMatchSnapshot()
})

jest snapshot that was created

exports[`deletes a city entry when clicked 1`] = `
<div
  className="city"
>
  <p
    className="location flex-item"
  >
     
  </p>
  <p
    className="temp flex-item"
  >
      ℉
  </p>
  <p
    className="feels-like flex-item"
  >
    Feels like: 
  </p>
  <p
    className="description flex-item"
  />
  <p>
    <img
      className="icon flex-item"
      src="https://openweathermap.org/img/w/.png"
    />
  </p>
  <button
    className="delete"
    onClick={[Function]}
  >
    Delete
  </button>
</div>
`;

CodePudding user response:

The JSON representation of the component is only for assertions. You can't use it to manipulate the state of the component. JSON can't contain functions, it's just static data.

To simulate a button click you need to instead use the methods available on TestInstance.

It's probably also best to trigger the actual click handler on the button so that the other deleteLocation function is called.

import renderer from 'react-test-renderer';
import CityEntry from '../src/Components/CityEntry.js'

it('deletes a city entry when clicked', () => {
  const component = renderer.create(
    <CityEntry weatherDatum={{ id: '', lat: '', lon: '', location: '', temperature: '', feelsLike: '', description: '', icon: '' }} />
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot()

  renderer.act(() => {
    component.root.findByType('button').props.onClick();
  });

  tree = component.toJSON();
  expect(tree).toMatchSnapshot()
})

By the way, you might consider using React Testing Library. The react-test-renderer API is really quite low level and most people find this more ergonomic. Most React test suites I see that are created recently go down this road.

Philosophically it also prevents what you were about to do, which is to grab hold of the props and manipulate them directly. That's because good tests only ever interact with the elements as a real user would.

  • Related