21

here is my code example

<div class="dropdown" data-testid="dropdown">
  <div class="option" data-testid="option">
   <b>[AF]</b> Afghanistan
  </div>
  <div class="option" data-testid="option">
   <b>[AL]</b> Albania
  </div>
  <div class="option" data-testid="option">
   <b>[DZ]</b> Algeria
  </div>
 </div>

What I need to do is to access the first element by its text to trigger the userEvent.selectOptions

const dropdown = getByTestId('dropdown');
userEvent.selectOptions(dropdown, screen.getByText('[AF] Afghanistan'))

What I get is :

TestingLibraryElementError: Unable to find an element with the text: [AF] Afghanistan. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

It's obviously because the text I'm trying to query is broken by elements.

Please note, that this is not a select/option dropdown and it doesn't have any accessible roles so I can only query it by screen.getByText

1

1 Answer 1

26

getBy* queries accept a TextMatch as an argument, which means the argument can be either a string, a regex, or a function. In this case, we can use a function (rather than a string) and target the specific element we want to select.

Here's a helper function that applies this logic and makes it reusable.

const getByTextContent = (text) => {
    // Passing function to `getByText`
    return screen.getByText((content, element) => {
        const hasText = element => element.textContent === text
        const elementHasText = hasText(element)
        const childrenDontHaveText = Array.from(element?.children || []).every(child => !hasText(child))
        return elementHasText && childrenDontHaveText
  })
}

To quickly explain what's going on: The query will traverse all elements in the DOM, but we want to avoid returning more elements than needed. We make sure that none of the children has the same text as its parent. This ensures that the element we return is the one that actually contains the target text.

The getByTextContent helper function can then be used in your tests as follows.

const dropdown = getByTestId('dropdown');
userEvent.selectOptions(dropdown, getByTextContent('[AF] Afghanistan'))
Sign up to request clarification or add additional context in comments.

2 Comments

I'm using this and getting the following error TestingLibraryElementError: Unable to find an element with the text: (content, node) => { /* istanbul ignore next */ cov_21pldi4...
I removed the await method within expect method and it fixed it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.