Support complex aria-labelledby queries
jossmac opened this issue · 3 comments
Describe the feature you'd like:
I'd like getByLabelText
to resolve the associated elements of aria-labelledby
. As I'm writing this it occurs to me that this might be too costly and perhaps better suited to something like axe.
Describe alternatives you've considered:
I've resorted to a combination of getByRole + getByText
and checking IDs.
Teachability, Documentation, Adoption, Migration Strategy:
The summarised/pseudo code looks something like:
let contentId = 'content-id';
let spinnerId = 'spinner-id';
return (
<button
aria-disabled={props.pending ? true : undefined}
aria-labelledby={props.pending ? `${contentId} ${spinnerId}` : undefined}
>
<span id={contentId}>{props.children}</span>
{props.pending && (
<span id={spinnerId} aria-label="pending" aria-hidden>
...
</span>
)}
</button>
);
The desired test would look something like:
it('supports "pending" prop', () => {
let { getByLabelText } = render(<Button pending>Submit</Button>);
expect(getByLabelText(`Submit ${PENDING_LABEL}`)).toHaveAttribute('aria-disabled', 'true');
});
Hi @jossmac, thanks for opening this.
I'm not sure I'm entirely understanding your request, but since you already have a solution that works, you can build a custom query in your own codebase.
Do you believe this use case is worth adding to the core library?
I wasn't aware of custom queries, thanks for the heads up!
Looking at this with fresh eyes, I think there's a sensible way to write the expectation with existing APIs e.g.
it('supports "pending" prop', () => {
let { getByRole } = render(<Button pending>Submit</Button>);
expect(
getByRole("button", { name: `Submit ${PENDING_LABEL}` })
).toHaveAttribute("aria-disabled", "true");
});
Do you believe this use case is worth adding to the core library?
No, I think my mental model was at odds with the library's design decisions.
However, I think it should be documented somewhere* that getByLabelText()
will only resolve the first ID when "aria-labelledby" is provided. In addition to improved docs, it could be helpful to warn consumers when the query encounters an "aria-labelledby" value that contains spaces.
Single ID, works as expected:
const { getByLabelText } = render(
<>
<div id="label-1">first</div>
<button aria-labelledby="label-1" />
</>
);
expect(getByLabelText("first")).toBeVisible(); // passes
Multiple IDs, does not work as expected:
const { getByLabelText } = render(
<>
<div id="label-1">first</div>
<div id="label-2">second</div>
<button aria-labelledby="label-1 label-2" />
</>
);
expect(getByLabelText("first second")).toBeVisible(); // fails. shouldn't really, but understandable knowing what i do now
Which could lead to tests passing that really shouldn't e.g.
const { getByLabelText } = render(
<>
<div id="label-1">first</div>
<div id="label-2">second</div>
<button aria-labelledby="label-1 label-2" />
</>
);
expect(getByLabelText("first")).toBeVisible(); // passes, incorrectly
*Found this documentation under a somewhat confusing heading:
The example above does NOT find the input node for label text broken up by elements.