testing-library / dom-testing-library

🐙 Simple and complete DOM testing utilities that encourage good testing practices.
https://testing-library.com/dom
MIT License
3.26k stars 467 forks source link

`getByRole` is unable to find an accessible elements in nested react components #1173

Closed shadaxv closed 1 year ago

shadaxv commented 1 year ago

Relevant code or config:

Tested component

export const InputPassword = ({ label, name }) => {
  const [passwordShown, setPasswordShown] = useState(false);
  const togglePassword = () => {
    setPasswordShown(!passwordShown);
  };

  return (
    <Input
      type={passwordShown ? "text" : "password"}
      label={label}
      name={name}
      iconRight={
        <button
          aria-label={passwordShown ? "hide password" : "show password"}
          type="button"
          data-input-icon
          onClick={togglePassword}
        >
          {passwordShown ? <EyeClose /> : <EyeOpen />}
        </button>
      }
    />
  );
};

export const Input = ({
  label,
  iconRight,
  type,
  name
}) => {
  const id = useId();
  return (
    <div>
      {label ? <label htmlFor={id}>{label}</label> : null}
      <div data-input-wrapper>
        <input
          aria-describedby={`${id}-helperText`}
          id={id}
          type={type}
          name={name}
        />
        {iconRight}
      </div>
    </div>
  );
};

Test

import "@testing-library/jest-dom/extend-expect";
import { render, screen } from "@testing-library/react";
import { InputPassword } from "../input";

test("should render password input", () => {
  render(<InputPassword label="Password" name="password" />);
  const inputPasswordElement = screen.getByRole("textbox", {
    name: /password/i
  });
  expect(inputPasswordElement).toBeInTheDocument();
});

What you did:

I want to test a component by using getByRole query, which uses another component underneath

What happened:

Query getByRole does not find an accessible element, however, any other query can find the element (e.g. getByTestId, getByText)

Error output

Input component › should render password input

    TestingLibraryElementError: Unable to find an accessible element with the role "textbox" and name `/password/i`

    Here are the accessible roles:

      button:

      Name "show password":
      <button
        aria-label="show password"
        data-input-icon="true"
        type="button"
      />

      --------------------------------------------------

    Ignored nodes: comments, script, style
    <body>
      <div>
        <div
          data-input="true"
        >
          <label
            for=":r0:"
          >
            Password
          </label>
          <div
            data-input-wrapper="true"
          >
            <input
              aria-describedby=":r0:-helperText"
              id=":r0:"
              name="password"
              type="password"
            />
            <button
              aria-label="show password"
              data-input-icon="true"
              type="button"
            >
              <svg>...</svg>
            </button>
          </div>
        </div>
      </div>
    </body>

Reproduction:

https://codesandbox.io/s/react-testing-library-demo-forked-v3dz08

Problem description:

Testing library is unable to find an accessible element in nested react components

Suggested solution:

Testing library should find an accessible element in a nested structure

MatanBobi commented 1 year ago

Hi @shadaxv, thanks for opening this one. The reason for this is that the name attribute isn't considered the component's accessible name (which is what we're querying for).. In the case of an input, the accessible name is defined by an aria-label or aria-labelledyby. To solve that issue, I'd replace the name attribute with an aria-label and then the query will work. Since this isn't an issue with testing-library, I'm closing this one :) Thanks again.

shadaxv commented 1 year ago

Hi @MatanBobi, thank you for your quick reply, I was just about to close the issue because I already found this thread - https://github.com/testing-library/dom-testing-library/issues/567

I think it is simply caused by the fact that the input with the password type, does not have its role, aria-label also will not work in this case, but thank you very much for the suggestion

For anyone who stumbles across this thread: instead of getByRole, you can use getByLabelText, which will be a good alternative

MatanBobi commented 1 year ago

Wasn't familiar with that one.. Thanks!

urbain32 commented 1 year ago

Hi @MatanBobi, thank you for your quick reply, I was just about to close the issue because I already found this thread - #567

I think it is simply caused by the fact that the input with the password type, does not have its role, aria-label also will not work in this case, but thank you very much for the suggestion

For anyone who stumbles across this thread: instead of getByRole, you can use getByLabelText, which will be a good alternative

hello i used getByLabelText but i had to remove 'toBeInTheDocument()' for it to work can you help me to understand why?

here is the code:

describe('add new sub:', () => {
    test('Should render without crash', async () => {
        render(<ItineraryDialog />  );
        const inputField = screen.getByLabelText('destinatio');
        expect(inputField);
    });
});
MatanBobi commented 1 year ago

@urbain32 - We'll need more data to try and help you with that issue.

PeymanOruji commented 1 year ago

Hello guys! I want to test a fail scenario. I know the cardHeadingElement element is not found, but I want to show result with expect function, But the result is: Unable to find an accessible element with the role "heading" and name /shazam/i

` render() const searchElement = await screen.findByPlaceholderText(/type for search/i) fireEvent.change(searchElement, {target: {value: 'marvel'}})

    const cardHeadingElement = screen.getByRole('heading', {
        name: /shazam/i
    })

    expect(cardHeadingElement).not.toBeInTheDocument()`

Please help :)

MatanBobi commented 1 year ago

@PeymanOruji You can follow the guides here: https://testing-library.com/docs/guide-disappearance#asserting-elements-are-not-present

PeymanOruji commented 1 year ago

Thank you sir. Can i ask another question? How we can test valid date ? :)

On Sun, Aug 6, 2023, 11:21 Matan Borenkraout @.***> wrote:

@PeymanOruji https://github.com/PeymanOruji You can follow the guides here:

https://testing-library.com/docs/guide-disappearance#asserting-elements-are-not-present

— Reply to this email directly, view it on GitHub https://github.com/testing-library/dom-testing-library/issues/1173#issuecomment-1666745750, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMN35H5OTCGTQZEMNSF6WALXT45HVANCNFSM6AAAAAAQVRP4OA . You are receiving this because you were mentioned.Message ID: @.***>

MatanBobi commented 1 year ago

I can't really understand what you mean with this question and this issue is aimed to provide answer for something else. If you have any questions about RTL, please feel free to open a stackoverflow question or reach out on our discord server and we'd be happy to help :)