Dom-testing-library: <li> is not an accessible element

Created on 19 Aug 2020  Â·  6Comments  Â·  Source: testing-library/dom-testing-library

  • @testing-library/dom version: 7.22.0
  • Testing Framework and version: jest version 24.9.0
  • DOM Environment: jsdom version 11.12.0

Relevant code or config:

// spinnerButton.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import SpinnerButton from '../spinnerButton.js';

test("renders a spinner when it's loading", () => {
    // render the button
    render(<SpinnerButton text={''} waiting={true} />);

    // expect a spinner to exist
    expect(screen.getByRole('status')).toBeInTheDocument();
});
// spinnerButton.js
import React from 'react';
import Spinner from 'react-bootstrap/Spinner';
import './styles/spinnerButton.css';

class SpinnerButton extends React.Component {
    render = () => {
        const buttonProps = { ...this.props };
        delete buttonProps.waiting;
        delete buttonProps.text;
        delete buttonProps.spinnerClassName;
        return (
            <button {...buttonProps}>
                {this.props.waiting ? (
                    <Spinner
                        as='li'
                        size='sm'
                        animation='border'
                        role='status'                     /* <= RELEVANT LINE OF CODE */
                        className={this.props.spinnerClassName}
                        aria-hidden='true'
                    >
                        <span></span>
                    </Spinner>
                ) : (
                    this.props.text
                )}
            </button>
        );
    };
}

export default SpinnerButton;

What you did:

I have a React component, SpinnerButton that shows some text before it has been clicked and a spinning wheel after it has been clicked. I gave a DOM node in that button a role called 'status'.

Then I tried to create a test that would find that element by its role, but it cannot be found.

What happened:

The test output looks like this:

 renders a spinner when it's loading

    TestingLibraryElementError: Unable to find an accessible element with the role "status"

    Here are the accessible roles:

      button:

      Name "":
      <button />

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

    <body>
      <div>
        <button>
          <li
            aria-hidden="true"
            class="spinner-border spinner-border-sm"
            role="status"
          >
            <span />
          </li>
        </button>
      </div>
    </body>

      29 |
      30 |     // expect a spinner to exist
    > 31 |     expect(screen.getByRole('status')).toBeInTheDocument();
         |                   ^
      32 | });
      33 |

So I know that the <li> element is there and that it has role="status" set.

The question is, why is "unable to find an accessible element?" The element is there and it has the role.

Problem description:

I want to find the node that I labelled, but I cannot.

Suggested solution:

It is possible (heck, probable) that I am misinterpreting what it means to be an accessible element or what getByRole is supposed to do. In that case, some more clear documentation or error message would be good.

But if I interpreted it correctly, then it should be the case that this element can be found by its role because it has a role.

Most helpful comment

@nullromo What happens when you use expect(screen.getByRole('status', { hidden: true })).toBeInTheDocument()?

By default, getByRole will not check queries that are excluded from the accessibility tree, so not specifying the hidden option is likely skipping your spinner because you have aria-hidden="true".

All 6 comments

@nullromo What happens when you use expect(screen.getByRole('status', { hidden: true })).toBeInTheDocument()?

By default, getByRole will not check queries that are excluded from the accessibility tree, so not specifying the hidden option is likely skipping your spinner because you have aria-hidden="true".

Hi @nullromo thanks for opening the issue :).

Using aria-hidden=true the element is removed from accessibility tree.

To use getByRole with hidden elements you should do in this way

getByRole('status', {hidden: true})

Let me know if this works :)

I seem to recall that we thought about adding a notice if we encountered any hidden elements with a role. Not necessarily recommending hidden: true since it's unlikely that you want to assert on excluded elements but rather to educate what excluding elements from the accessibility (a11y) tree means.

Particularly in this case you won't gain anything by adding the status role if the element is not part of the a11y tree.

@winterlamon @marcosvega91 @eps1lon Thank you all for the replies. After some further reading, I now realize that _accessible_ and _accessibility_ have special meanings that I was unaware of. When talking about _accessibility_, people (web designers, etc.) are referring specifically to website navigation hints/tools/systems that allow for easier navigation by visually impaired people, by robots, by people without mouses, or whatever it may be. As @eps1lon points out, the a11y tree.

I was reading "Unable to find an Accessible Elementâ„¢" as "Unable to access an element," which is a different thing altogether.

The machinery to handle cases like this is already in place, so great work on that. The warning message suggested here looks like a good idea.

For my case, the question remains, is it better practice to add a data-testid to the intentionally-non-accessible element that I am expecting to see and use getByTestId, or is it better to continue to use getByRole with hidden: true... Not sure if there's a right answer on that. Perhaps this isn't the place to discuss that.

It would probably be best to make use of a loading indicator that has an accessible text fallback, like an aria-label attribute, and then remove the "hidden" property. ARIA role=status is a live region meaning the text content will be read by screen readers as an alert. So you are on the right track, accessibility-wise, just need to implement the aria text representation to go with your visual spinner.

https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_status_role

For loading spinners there's quite a bit of helpful ressources out there but no concrete recommendation in the ARIA authoring practices.

I can't give you a recommendation since I didn't test any of those patterns.

Either way this issue tracker is for bug/feature tracking. For evaluating a11y patterns you should start curating a list of trustworthy resources or test it yourself. I hope that helps a bit.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kentcdodds picture kentcdodds  Â·  3Comments

ngbrown picture ngbrown  Â·  4Comments

dlbnco picture dlbnco  Â·  3Comments

nicolasschabram picture nicolasschabram  Â·  3Comments

NiGhTTraX picture NiGhTTraX  Â·  3Comments