score:10

Accepted answer

Update

As people pointed out my original solution was wrong.

Nowadays I suggest you use userEvent for better-simulating user interactions.

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

test("radio", () => {
  const user = userEvent.setup();
  render(
    <form>
      <label>
        First <input type="radio" name="radio1" value="first" />
      </label>
      <label>
        Second <input type="radio" name="radio1" value="second" />
      </label>
    </form>
  )

  await user.click(screen.getByLabelText("Second"));
});

First, you don't have to call rerender. You use rerender only when you want the component to receive different props. See link.

Whenever you call fireEvent the component will render like it would in your normal app.

It's correct to fire a change event, but you must pass a second parameter with the event data.

This example works:

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" />
      </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')
});

score:-1

Please try this from react-testing-library docs, "render" should work fine. Agree with @Gpx

fireEvent.change(input, { target: { value: 'your_value_goes_here' } })
expect(input.value).toBe('expected_value')

score:-1

I've also had this work for me:

test('Does stuff', async () => {
// ... test prep ...

const formEl = screen.getByTestId('form_test_id')

// You can use screen.getByLabelText here instead of DOM queries 
// if you've got a nicely laid out form
const defaultInput = formEl.querySelector('input[value="default_value"]')
const newValueInput = formEl.querySelector('input[value="new_value"]')

// Confirm your baseline
expect(defaultInput.checked).toEqual(true)
expect(newValueInput.checked).toEqual(false)

// Fire the change event
await act(async () => {
fireEvent.change(newValueInput, { target: { checked: true } }) 
// To trigger any onChange listeners
fireEvent.blur(newValueInput)
})

// Confirm expected form state(s)
expect(defaultInput.checked).toEqual(false)
expect(newValueInput.checked).toEqual(true)

})

score:0

Complementing @andy's answer, this should test two radios effectly:

  it('should render successfully', async () => {
    render(
      <YourRadioGroup />
    );

    expect(screen.getByText('option 1')).toBeInTheDocument();
    expect(screen.getByText('option 2')).toBeInTheDocument();
  });

  it('should change checked option', () => {
    render(
      <YourRadioGroup />
    );

    const secondRadio = screen.getByLabelText('option 2');
    fireEvent.click(secondRadio);
    expect(secondRadio).toBeChecked();

    const firstRadio = screen.getByLabelText('option 1');
    fireEvent.click(firstRadio);
    expect(firstRadio).toBeChecked();
    expect(secondRadio).not.toBeChecked();
  });

score:0

This worked for me (working with the radio buttons, not the radio groups):

// some code here to make sure the screen has finished rendering, and I have all radio buttons in the DOM (I am expecting 5 containers):
await waitFor(() => expect(screen.getAllByTestId('some-slow-loading-container')).toHaveLength(5))

// get all "true" labeled radio buttons by test id (or by role + name or whatever):
const allTrueLabelRadioButtons = screen.getAllByTestId('true-label-radio-button');

// loop over the array of HTML elements found:
for (const trueLabelRadioButton of allTrueLabelRadioButtons) {
   // using fireEvent instead of userEvent because of some bugs with the components library I am stuck with. Usually I use userEvent:
   fireEvent.click(trueLabelRadioButton)
}

// check whatever you are expecting to happen after all radio buttons are set to "true".
//...

score:5

As of May 2020 using React 16.13 and react-testing-library 10.0, the accepted answer does not work (the test itself passes but doesn't actually do anything meaningful).

I can't find any reference to radio buttons in the documentation for react-testing-library or even React itself. However, here's an example (using Typescript) that works properly as far as I can tell.

import React from "react";
class State {
    radioValue: string = "one"
}
export default class RadioTest extends React.Component<{}, State>
{
    state: State = new State();

    radioClick = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
        this.setState({ radioValue: event.currentTarget.value });
    }

    render() {
        return (<>
            <label>
                One
                <input type="radio" name="radio" onClick={this.radioClick}
                    value="one" onChange={() => {}}
                    checked={this.state.radioValue === "one"} />
            </label>
            <label>
                Two
                <input type="radio" name="radio" onClick={this.radioClick}
                    value="two" onChange={() => {}}
                    checked={this.state.radioValue === "two"} />
            </label>
            <div>current value={this.state.radioValue}</div>
            <button onClick={() => this.setState({radioValue:"one"})}>Click</button>
        </>);
    }
}

test("radiotest", () => {
    const { getByLabelText, queryByText, getByText } = render(<RadioTest />);
    const one = getByLabelText('One') as HTMLInputElement
    const two = getByLabelText('Two') as HTMLInputElement
    expect(one).toBeChecked();
    expect(two).not.toBeChecked();
    expect(queryByText("current value=one")).toBeTruthy();
    fireEvent.click(two);
    expect(one).not.toBeChecked();
    expect(two).toBeChecked();
    expect(queryByText("current value=two")).toBeTruthy();
    fireEvent.click(getByText("Click"))
    expect(one).toBeChecked();
    expect(two).not.toBeChecked();
    expect(queryByText("current value=one")).toBeTruthy();
});

React onChange handlers will work in the browser but not with react-testing-library because they don't fire when you call fireEvent.change()

The dummy onChange handlers are required to avoid a React warning: "If the field should be mutable use defaultChecked". You can't use defaultChecked though, because it stops you setting the state in code (i.e. clicking the button at the bottom doesn't update the radio)

So on the whole, it looks like React wants you to use onChange but react-testing-library only works with onClick, so this is a bit of a fudge.

score:23

if you have a label like with Radio Component of Material-ui, you could use:

const labelRadio: HTMLInputElement = getByLabelText('Label of Radio');
expect(labelRadio.checked).toEqual(false);
fireEvent.click(labelRadio);
expect(androidRadio.checked).toEqual(true);

or you can add https://github.com/testing-library/jest-dom matchers and check it in this way:

expect(getByLabelText('Label of Radio')).not.toBeChecked();
fireEvent.click(labelRadio);
expect(getByLabelText('Label of Radio')).toBeChecked();

Related Query

More Query from same tag