Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find element by property value

I'm testing a web application using Nightwatch.js, which uses Selenium WebDriver to interact with the browser. In my app I have a dynamically created list of items differentiated only by their names and the names are displayed as <input> values. I need to find an item by its name.

Example HTML representation of document structure:

<div class="item">
  <input>  <!-- current value: "first" -->
</div>
<div class="item">
  <input>  <!-- current value: "second" -->
</div>
<div class="item">
  <input>  <!-- current value: "first" -->
</div>

I need to find div.item containing an input with the value second.

Note that the value of an <input> is determined by the value of its value property, which might be different from the value of its value attribute. In my case, the DOM is manipulated by React, so the inputs might not have the value attribute at all.

Is there a way to find element by property value with Nightwatch (or Selenium WebDriver API)?

I looked over the WebDriver documentation and the only way I see is executing custom JavaScript code, which has some serious drawbacks (e.g. requires own implementation of waiting for element to appear and doesn't interact with Nightwatch page objects). As far as I can see, all of the other methods are concerned with looking at the HTML only (so attributes at best, not properties).


Just to be completely clear, using selectors like input[value=...] (CSS) or //input[@value=...] (XPath) is not a solution, as it performs lookup by attribute value, not property value.

like image 310
hon2a Avatar asked Oct 31 '22 02:10

hon2a


1 Answers

You can use .elements() to get a list of elements with class="item" and then iterate through all elements using .getValue() to get the value property of each input. If it matches the name you want, return the element.

function getElementsByValue(xpathSelector, expectedValue, callback) {
  const foundElements = [];
  browser.elements('xpath', xpathSelector, ({ value }) => value.forEach(inputEl => {
    browser.elementIdValue(inputEl.ELEMENT, result => {
      if (result.value === expectedValue) {
        foundElements.push(inputEl);
      }
    });
  });
  browser.perform(() => callback(foundElements));
}
like image 134
Raymond Avatar answered Nov 13 '22 21:11

Raymond