user2387766
user2387766

Reputation:

xPath - Why is this exact text selector not working with the data test id?

I have a block of code like so:

<ul class="open-menu">
  <span>
    <li data-testid="menu-item" class="menu-item option">
      <svg>...</svg>
      <div>
        <strong>Text Here</strong>
        <small>...</small>
      </div>
    </li>

    <li data-testid="menu-item" class="menu-item option">
      <svg>...</svg>
      <div>
        <strong>Text</strong>
        <small>...</small>
      </div>
    </li>
  </span>
</ul>

I'm trying to select a menu item based on exact text like so in the dev tools:

$x('.//*[contains(@data-testid, "menu-item") and normalize-space() = "Text"]');

But this doesn't seem to be selecting the element. However, when I do:

$x('.//*[contains(@data-testid, "menu-item")]');

I can see both of the menu items.

UPDATE:

It seems that this works:

$x('.//*[contains(@class, "menu-item") and normalize-space() = "Text"]');

Not sure why using a class in this context works and not a data-testid. How can I get my xpath selector to work with my data-testid?

Upvotes: 1

Views: 1103

Answers (2)

Prophet
Prophet

Reputation: 33361

data-testid="menu-item" is matching both the outer li elements while text content you are looking for is inside the inner strong element.
So, to locate the outer li element based on it's data-testid attribute value and it's inner strong element text value you can use XPath expression like this:

//*[contains(@data-testid, "menu-item") and .//normalize-space() = "Text"]

Or

.//*[contains(@data-testid, "menu-item") and .//*[normalize-space() = "Text"]]

I have tested, both expressions are working correctly

Upvotes: 0

urznow
urznow

Reputation: 1811

Why is this exact text selector not working

The fact that both li elements are matched by the XPath expression if omitting the condition normalize-space() = "Text" is a clue. normalize-space() returns ... Text Here ... for the first li in the posted XML and ... Text ... for the second (or some other content in place of ... from div/svg or div/small) causing normalize-space() = "Text" to fail.

In an update you say the same condition succeeds. This has nothing to do with using @class instead of @data-testid; it must be triggered by some content change.

How can I get my xpath selector to work with my data-testid?

By testing for an exact text match in the li's descendant strong element,

.//*[@data-testid = "menu-item" and div/strong = "Text"]

which matches the second li. Making the test more robust is usually in order, e.g.

.//*[contains(@data-testid,"menu-item") and normalize-space(div/strong) = "Text"]

Append /div/small or /descendant::small, for example, to the XPath expression to extract just the small text.

Upvotes: 2

Related Questions