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 466 forks source link

{ name } is always empty when getByRole is used with 'term' or 'description' #1247

Closed brookjordan closed 1 year ago

brookjordan commented 1 year ago

What you did:

Trying to test that <dl> children exist and have the right text using:

<dl> <dt>Hello</dt> <dd>There</dd> </dl>
expect(getByRole('term', { name: 'term' })).toBeVisible();
expect(getByRole('definition', { name: 'definition' })).toBeVisible();

What happened:

The test finds the <dl> children, but doesn’t recognise the inner text:

term:
  Name "":
  <dt />

definition:
  Name "":
  <dd />

Reproduction:

https://codesandbox.io/s/react-testing-library-demo-forked-sytg8p?file=/src/__tests__/hello.js

Click to see the code here without opening the repo: ```js const { getByRole } = render(
Hello
There
); expect(getByRole('term', { name: 'Hello' })).toBeVisible(); expect(getByRole('definition', { name: 'There' })).toBeVisible(); ``` The test output shows that it knows about the inner text, but I guess isn’t considering it as the name? ```shell TestingLibraryElementError: Unable to find an element with the role "term" and name "Hello" Here are the available roles: term: Name "":
-------------------------------------------------- definition: Name "":
-------------------------------------------------- Ignored nodes: comments, script, style
Hello
There
```

Problem description:

Other element types accept the name parameter to describe the inner text. It would be great to have this ability within this test, too.

cmorten commented 1 year ago

The name option here means accessible name, which doesn’t necessarily always mean text content.

The accessible name for an element is calculated per the accname specification (https://www.w3.org/TR/accname-1.2/#mapping_additional_nd_te) using the dom-accessibility-api package (https://github.com/eps1lon/dom-accessibility-api).

For text content the part of interest is step F of the algorithm regarding deriving the accessible name from content - in the case of dt and dd they don’t meet the requirements as in your case they are not labelling another element, nor do they have implicit roles that allow naming from content (see https://www.w3.org/TR/wai-aria-1.2/#namefromcontent for the list).

Thus in this case I believe it is expected behaviour that your matchers aren’t working.

cmorten commented 1 year ago

The *ByRole queries don’t have an explicit option for match on role and text content, for that would consider either:

  1. Matching on just the role and asserting on the text content
  2. Use a *ByText matcher (in addition to or instead of *ByRole)
  3. Use the TextMatch capability to pass a function that matches based on the role content and the element.innerText

REF:

MatanBobi commented 1 year ago

Thanks @cmorten for the detailed explanation! I would just add that both dt and dd support only name from author, meaning you can add aria-label or aria-labelledby in order to set their accessible name. Since this is not an issue with testing-library, I'm closing it. Thanks again @cmorten for your help :)