testing-library/dom-testing-library

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

brookjordan opened this issue · 3 comments

  • @testing-library/dom version: 9.3.1
  • Testing Framework and version: vitest 0.33.0 (in the linked repo I’ve used jest-dom 5.16.5)
  • DOM Environment: jsdom 22.1.0

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:
const { getByRole } = render(
  <dl> <dt>Hello</dt> <dd>There</dd> </dl>
);

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?

TestingLibraryElementError: Unable to find an element with the role "term" and name "Hello"

Here are the available roles:

  term:

  Name "":
  <dt />

  --------------------------------------------------
  definition:

  Name "":
  <dd />

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

Ignored nodes: comments, script, style
<body>
  <div>
    <dl>
      <dt>
        Hello
      </dt>
      <dd>
        There
      </dd>
    </dl>
  </div>
</body>

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.

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.

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:

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 :)