47

I have a React component that generates a button, which content contains <span> element like this one:

function Click(props) {
    return (
        <button disable={props.disable}>
            <span>Click me</span>
        </button>
    );
}

I want to test the logic of this component with the use of react-testing-library and mocha + chai.

The problem which I stuck at the moment is that getByText("Click me") selector return the <span> DOM node, but for the tests, I need to check disable attribute of the <button> node. What is the best practice handling such test cases? I see a couple of solutions, but all of them sounds a little bit off:

  1. Use data-test-id for <button> element
  2. Select one of the ancestors of the <Click /> component and then select the button within(...) this scope
  3. Click on the selected element with fireEvent and check that nothing is happened

Can you suggest a better approach?

Nikita Sivukhin
  • 1,568
  • 2
  • 11
  • 29

5 Answers5

84

Assert if button is disabled

You can use the toHaveAttribute and closest to test it.

import { render } from '@testing-library/react';

const { getByText } = render(Click);
expect(getByText(/Click me/i).closest('button')).toHaveAttribute('disabled');

or toBeDisabled

expect(getByText(/Click me/i).closest('button')).toBeDisabled();

Assert if button is enabled

To check if the button is enabled, use not as follows

expect(getByText(/Click me/i).closest('button')).not.toBeDisabled();
johnny peter
  • 3,155
  • 21
  • 35
  • 2
    Just a note: there must be a relatevily fresh version of the `jsdom` library to be able to use `closest(...)` function in your example (v 11.12.0 or higher) – Nikita Sivukhin Jun 14 '19 at 08:16
  • 6
    Note that `toHaveAttribute` requires that https://github.com/testing-library/jest-dom be installed. – Sam Dec 09 '19 at 12:45
  • Thanks! that helps to test Material-ui buttons – misolo Sep 10 '20 at 14:17
  • For everyone using a different framework than jest, e.g. Jasmine, something like this should do the job: `expect(getByText(/Click me/i).closest('button').hasAttribute('disabled')).toBeTrue();` – René Schubert Feb 17 '21 at 10:57
28

You can use toBeDisabled() from @testing-library/jest-dom, it is a custom jest matcher to test the state of the DOM:

https://github.com/testing-library/jest-dom

Example:

<button>Submit</button>
expect(getByText(/submit/i)).toBeDisabled()
Towko
  • 33
  • 7
Meysam Izadmehr
  • 2,600
  • 14
  • 24
9

For someone who looking for the test which is the button is not disabled.

import { render } from '@testing-library/react';

const { getByText } = render(Click);
expect(getByText(/Click me/i).getAttribute("disabled")).toBe(null)
Tony Nguyen
  • 2,598
  • 5
  • 14
3

You can test the disable prop of the button just by using @testing-library/react as follows.

example:

   import { render } from '@testing-library/react';

   const {getByText} = render(<Click/>)

   expect(getByText('Click me').closest('button').disabled).toBeTruthy()
Satish
  • 31
  • 1
1

Another way to fix this would be to grab by the role and check the innerHTML like,

const { getByRole } = render(<Click />)
const button = getByRole('button')

// will make sure the 'Click me' text is in there somewhere
expect(button.innerHTML).toMatch(/Click me/))

This isn't the best solution for your specific case, but it's one to keep in your back pocket if you have to deal with a button component that's not an actual button, e.g.,

<div role="button"><span>Click Me</span></div>

Yatrix
  • 12,038
  • 13
  • 39
  • 73