Search code examples
react-testing-library

Testing a radio button click event resulting in "checked"


I've read this post where the following example is given:

import React from "react";
import { render, fireEvent } from "react-testing-library";
test("radio", () => {
  const { getByLabelText } = render(
    <form>
      <label>
         First <input type="radio" name="radio1" value="first" id="firstRadioId" />
      </label>
      <label>
        Second <input type="radio" name="radio1" value="second" />
      </label>
    </form>
  );
  const radio = getByLabelText('First')
  fireEvent.change(radio, { target: { value: "second" } });
  expect(radio.value).toBe('second')
});

But that feels kind of odd since it's not the result of a click that's being tested. But rather it's directly setting the value to a certain string. However, the click event does not work:

  // ...
  const radio = getByLabelText('First')
  const radioSecond = getByLabelText('Second')
  fireEvent.click(radioSecond);
  expect(radio.value).toBe('second');
  // ...

The thing that I don't get is why document.getElementById('firstRadioId').checked is returning false. In the browser it does, as can be seen in the example here:

https://codesandbox.io/s/silly-saha-xt0j7

On the index page you see that radio.checked returns true. But in the test it does not.


Solution

  • In your codesandbox, you have the following:

      it("changes the value based on the radio buttons", () => {
        const { getByText } = render(tree);
        const radio = getByText(/My label/i);
    
        fireEvent.click(radio);
        // why is this false?
        expect(radio).toHaveProperty("checked", true);
      });
    

    If you debug radio, you'll find that your query returned a label, which won't have the attribute checked:

    
    <label
      for="myRadioButton1"
    >
      <input
        id="myRadioButton1"
        name="myRadioButtonGroup"
        type="radio"
      />
      My label
    </label> 
    

    If you want to check something's checked attribute, you should get the radio button using getByRole:

      it("changes the value based on the radio buttons", () => {
        const { getByRole } = render(tree);
        const radio = getByRole("radio", { name: /My label/i });
        fireEvent.click(radio);
        expect(radio).toHaveProperty("checked", true);
      });
    

    To anyone reading this, consider using debug (preferrably using screen.debug()) when you are unsure why something isn't working.