testing-library / dom-testing-library

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

Button's inner text is ignored when label exists, even though aria-hidden is set to true #1233

Open alex1701c opened 1 year ago

alex1701c commented 1 year ago

Heyho, I have the problem that a button component has a label which has aria-hidden="true" causes findByRole to not look at the button's inner text. In case I remove the for attribute from the label, it works as expected. But according to the accessibility tab in the browser, the label is ignored even with the for attribute set.

Relevant code or config:

[
    'button1', // The correct for attribute pointing to the button, this causes the last finyByRole to fail
    undefined, // Don't set this attribute
].forEach((labelFor) =>
    it('should find button', () => {
        cy.mount(
            <div className="SCFormControl">
                {/* The label is needed due to some internal layout, other controls always have a label containing the user-visible text */}
                <label id="button1_label" htmlFor={labelFor} aria-hidden="true"></label>
                <button type="button" id="button1">
                    <span className="somestylingclasses">Button 1</span>
                </button>
            </div>,
        );
        cy.findByText('Button 1').should('exist');
        cy.findByRole('button').should('exist');
        cy.findByRole('button', { name: 'Button 1' }).should('exist');
    }),
);

What happened:

image

Reproduction:

See attached code snippet

lausuarez02 commented 11 months ago

I've been looking at the error and the only thing that i see that could generate an error is the fact that instead of using a string to get the name of it you should probably try using this syntax name: /Button 1/i . Apart from that i don't see another error, check that out, i hope that helps. ;)

alex1701c commented 11 months ago

I've been looking at the error and the only thing that i see that could generate an error is the fact that instead of using a string to get the name of it you should probably try using this syntax name: /Button 1/i .

That does not help. Did you try it with the attached cypress snippet?

timdeschryver commented 11 months ago

It seems like this needs to be resolved in dom-accessibility-api, specifically within computeAccessibleName. However, I'm not sure if this is a bug, or the desired outcome. From my tests my screen reader (windows narrator) finds the button with name Button 1, but the accessibility tree of my browser also finds the button but with the content of the label which is invisible.

alex1701c commented 11 months ago

From my tests my screen reader (windows narrator) finds the button with name Button 1

Yep, same with NVDA.

but the accessibility tree of my browser also finds the button but with the content of the label which is invisible.

Hmm, that is a good point, but even a non-empty aria-hidden label will result in an empty text.

Consider the following example:

<div class="SCFormControl">
    <label id="button1_label" for="button1" aria-hidden="true">Screenreader ignores me :(</label>
    <button name="bla" type="button" id="button1">
        Button 1
    </button>
    <label>But not me!</label>
</div>

As you can see with the label texts, the button1_label is completely ignored, even with a non-empty text. In the accessibility tab, the label is ignored, but I am not sure why the computed content is considered invalid.

image
MatanBobi commented 11 months ago

This is a tricky one. The accessible name computation algorithm doesn't state that one specifically if I understand correctly here: https://www.w3.org/TR/accname-1.2/#terminology

What happens in dom-accessibility-api is that the label is linked to the button and since the label is hidden, the result of it is an empty string.

@eps1lon do you maybe have an idea about this specific use case? I'm not sure if the screen reader behaves as it should or the browsers.

cmorten commented 9 months ago

To complicate matters, ACCNAME isn’t the only algorithm in play for accessible name computation of HTML elements, we also have HTML-AAM section 4 to contend with.

Some relevant issues:

Depending on the spec you use as your starting point I’m not convinced you can potentially land with different results 😅 that may simply be me lacking ability to follow!

In this specific case of a hidden <label> naming a form control, there are some relevant issues:

These hint at a future intention to treat a hidden <label> with for as equivalent to aria-labelledby such that it’s accessible name is used regardless of whether it is hidden, and not to ignore it in preference of proceeding with the algorithm to deriving name from contents etc.

alex1701c commented 9 months ago

Thanks for all the investigation on this!