How do you check a checkbox in react-testing-library?
Asked Answered
P

4

71

I cant seem to find much/any docs on this really simple thing I'm trying to achieve

I have a dropdown that is display: none. when I click a checkbox it becomes display: block all I'm trying to assert is when I click the checkbox, it shows the dropdown

 expect(getByLabelText('Locale')).toHaveStyle(`
  display: none;
`)

getByLabelText('Locale').checked = true

expect(getByLabelText('Locale')).toHaveStyle(`
  display: block;
`)

the code works as expected but the test is failing on the second expect block saying: it should still be display: none

is the correct way to assert this?

when I click the checkbox it updates 2 attributes in my object to true which is how it renders in the code. when I manually pass these attributes the test still fails but it fails in the first expectation.

I feel like I need to do something like setProps

I have now tried to use renderWithRedux but it doesn't seem to be firing my action creator correctly?

is fireEvent.click(queryByTestId('LocaleCheckbox')) the best thing to try and update a checkbox?

Piliferous answered 15/3, 2019 at 7:54 Comment(2)
According to your test code, the checkbox is invisible before attempting to change the "checked" value. How would a user be able to click the checkbox if it were display: none;?Spume
nah the dropdown was display none, although was so long ago now ha. cant' really rememberPiliferous
R
85

To check or uncheck the checkbox using react-testing-library, you simply want to fireEvent.click the checkbox. There was a discussion about this on react-testing-library Issue #175. In particular, kentcdodds said:

this should probably be documented better, but with checkboxes you don't actually fire change events, you should fire click events instead.

But, based on the code you wrote above, what is the node with label text 'Locale'? Because if it has style display: none, how would your user click to check it? Is that a typo? You should be asserting style on your dropdown but clicking on your checkbox. Maybe I'm seeing it wrong, but it looks from your code like you're doing all your assertions and operations on the same node. That doesn't seem right.

I've written up a CodeSandbox sample which has a basic div with a style that is set to display: none or display:block based on whether a checkbox is checked or not. It uses react-hooks to maintain the state.

There is also a react-testing-library test that demonstrates asserting on the style, checking the checkbox, and then asserting the changed style.

The test code looks like this:

it('changes style of div as checkbox is checked/unchecked', () => {
  const { getByTestId } = render(<MyCheckbox />)
  const checkbox = getByTestId(CHECKBOX_ID)
  const div = getByTestId(DIV_ID)
  expect(checkbox.checked).toEqual(false)
  expect(div.style['display']).toEqual('none')
  fireEvent.click(checkbox)
  expect(checkbox.checked).toEqual(true)
  expect(div.style['display']).toEqual('block')
  fireEvent.click(checkbox)
  expect(checkbox.checked).toEqual(false)
  expect(div.style['display']).toEqual('none')
})

Hope this helps to point you in the right direction.

Edit checkbox alters style

Redraft answered 15/3, 2019 at 8:40 Comment(5)
sorry, let me explain better. I have a checkbox that is always is visible, checking and unchecking it, causes the dropdown next to it to be shown or hidden. i.e. checked == display block, unchekced == display: none. when I click the checkbox it fires an action to the redux store which changes the parameter to be either false or true. the component code then uses the redux state to display or not display that component, .does that make sense? I'm trying to test that when I click the checkbox the dropdown is either displayed or notPiliferous
and it does not look like my action is being fired in the test code?Piliferous
When you do getByLabelText('Locale'), are you talking about the dropdown or the checkbox? Because your test code is referencing it both for the style assertions and for checking/unchecking. That doesn't seem right. Any chance you have a CodeSandbox or other place where your code can be reviewed more fully?Redraft
I'm arriving late @RedBaron, but I think that if you are using Redux for this, you have to use async waitFor, findBy... and await statements since that process is asynchronous, it might be helpfull. PDT sorry for my poor EnglishBellina
Property 'checked' does not exist on type 'HTMLElement'.ts(2339)Trying
G
6

Using userEvent and jest-dom libraries would be a better approach.

import React from "react";
import userEvent from "@testing-library/user-event";
import { act, render, screen } from "@testing-library/react";
    
it("changes style of div as checkbox is checked/unchecked", async () => {
  render(<MyCheckbox />);
  const checkboxLabel = screen.getByText(/checkbox/i, { selector: "label" });

  expect(screen.queryByRole("checkbox")).not.toBeChecked();
  expect(checkboxLabel).toHaveStyle("display: none");

  await act(async () => {
    await userEvent.click(screen.getByRole("checkbox"));
  });

  expect(screen.getByRole("checkbox")).toBeChecked();
  expect(checkboxLabel).toHaveStyle("display: block");
});

test checkbox toggle

Gammadion answered 22/10, 2022 at 0:8 Comment(0)
H
4

@samehanwar, thanks for your clear answer. I want to add something.

You don't need to use act() actually. The reason why you don't need to do is the most of cases like userEvent, render are wrapped in act already. eventWrapper() in testing-library/dom is called when event functions like userEvent.

The answer should be like this

import React from "react";
import userEvent from "@testing-library/user-event";
import { render, screen } from "@testing-library/react";
    
it("changes style of div as checkbox is checked/unchecked", async () => {
  render(<MyCheckbox />);
  const checkboxLabel = screen.getByText(/checkbox/i, { selector: "label" });

  expect(screen.queryByRole("checkbox")).not.toBeChecked();
  expect(checkboxLabel).toHaveStyle("display: none");

  await userEvent.click(screen.getByRole("checkbox"));

  expect(screen.getByRole("checkbox")).toBeChecked();
  expect(checkboxLabel).toHaveStyle("display: block");
});
Harsh answered 22/10, 2022 at 0:49 Comment(0)
J
1

I'm using "react-test-renderer": "^17.0.2". I've manage to do the same with a simple:

getByTestId("data-testid").click()

this is the code to get the getByTestId:

const {getByTestId} = render(<Checkbox
        onClose={jest.fn()}
        onSave={onSave}
    />)
Jennijennica answered 2/6, 2021 at 12:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.