Discovering a particular element involves iterating through the results returned by the findElements method in JavaScript

I am attempting to locate and interact with a specific item by comparing text from a list of items. The element distinguished by .list_of_items is a ul that consists of a list of li>a elements.

I am uncertain about how to transfer the determined element to the next function. There are no available identifiers, such as id or class, for pinpointing the element.

driver.isElementPresent(By.css(".list_of_items")).then(function(trueFalse){
  if (trueFalse){
    return driver.findElements(By.css(".list_of_items a"));                         
  }else{
    console.log('err');
  }
}).then(function(eleArray){
  for (var i=0; i < eleArray.length; i++){
    eleArray[i].getInnerHtml().then(function(html){
      if (html.trim().toLowerCase() == item_to_search.toLowerCase()){
        //
        // How can I pass the matched element to the subsequent function??
        //
        return true;
      }
    }).then(function(element){
        console.log(element);
      }
    });
  }
});

Answer №1

If you're looking to filter elements, consider using the filter method:

driver.isElementPresent(By.css(".list_of_items")).then(function(trueFalse){
  if (trueFalse){
    return driver.findElements(By.css(".list_of_items a"));                         
  }else{
    console.log('error');
    throw new Error('Element not found.'); // Updated error message for clearer handling.
  }
}).then(function(eleArray){
  return webdriver.promise.filter(eleArray, function(element){
    return element.getInnerHtml().then(function(innerText){
      return innerText.trim().toLowerCase() == item_to_search.toLowerCase();
    });    
  });
}).then(function(reducedElements){
  console.log('filtered elements: ', reducedElements.length);
});

Answer №2

It's worth noting that your current code is performing a case-insensitive search. If you have the capability to conduct a case-sensitive search, consider using the following method to locate your element:

browser.findElement(By.linkText(item_to_search)).then(...);

In my experience developing numerous application tests with Selenium, I've consistently been able to search by link text without requiring case sensitivity. I highly recommend organizing your code in a way that enables this functionality.

If conducting a case-sensitive search is not an option, you may need to scan through each element to identify the desired one. While it is possible to create an XPath expression that matches text regardless of case, I tend to avoid using XPath for matching CSS classes like in your scenario. Consequently, scanning through elements as you were previously doing might be preferable. Note that when comparing text values against HTML content, it is advisable to use getText() rather than getInnerHtml(), as testing against HTML can be fragile: there could be additional elements within the HTML that do not affect the actual text of the link. For example,

<a><b>This</b> is a test</a>
would display "This is a test" but checking the inner HTML of the <a> tag would yield
<b>This</b> is a test
, which is not ideal for matching purposes.

Below is an implementation showcasing the By.linkText method mentioned earlier and including an illustrative example:

var webdriver = require('selenium-webdriver');
var By = webdriver.By;
var chrome = require('selenium-webdriver/chrome');
var browser = new chrome.Driver();

browser.get("http://www.example.com");

// Modifying the example.com page to add test data.
browser.executeScript(function () {
    document.body.innerHTML = '\
<ul class="list_of_items">\
  <li><a>One</a></li>\
  <li><a>  Two  </a></li>\
  <li><a>Three</a></li>\
</ul>';
});

// Example of utilizing By.linkText for a case-sensitive search.
browser.findElement(By.linkText("Two")).getOuterHtml().then(function (html) {
    console.log("case-sensitive: " + html);
});

var item_to_search = "TwO"; // Intentionally mixed case for illustration.

browser.findElements(By.css(".list_of_items a")).then(function (els){
    if (els.length === 0)
        throw new Error("abort!");

    var item_to_search_normalized = item_to_search.toLowerCase();

    function check(i) {
        if (i >= els.length)
            throw new Error("element not found!");

        var el = els[i];

        return el.getText().then(function (text) {

            if (text.trim().toLowerCase() === item_to_search_normalized)
                return el;

            return check(i + 1);
        });
    }

    return check(0);
}).then(function (el) {
    el.getOuterHtml().then(function (html) {
        console.log("case-insensitive: " + html);
    });
});


browser.quit();

Additional tips:

  1. Your initial code checked if .list_of_items existed before proceeding. Instead of this, my approach assumes the page is correctly structured, reducing unnecessary operations. If troubleshooting why no elements are being retrieved, modify the throw new Error("abort!") statement for diagnosis purposes.

  2. Your original code halted the search upon finding a match, which I preserved. Using webdriver.promise.filter scans every element even after locating a target, unlike my recursive method which terminates early upon success. This reduces round-trip interactions between the script and the browser, especially significant for remote server setups where each test adds latency. The recursion mirrors the behavior of webdriver.promise.filter while optimizing efficiency.

In my code snippet, I utilize executeScript to minimize exchanges between the Selenium script and the browser:

browser.executeScript(function () {
    var item_to_search = arguments[0].toLowerCase();
    var els = document.querySelectorAll(".list_of_items a");
    for (var i = 0; i < els.length; ++i) {
        var el = els[i];
        if (el.textContent.trim().toLowerCase() == item_to_search)
            return el;
    }
    return null;
}, item_to_search).then(function (el) {
    if (!el)
        throw new Error("can't find the element!");

    el.getOuterHtml().then(function (html) {
        console.log("case-insensitive, using a script: " + html);
    });
});

The script passed to executeScript runs within the browser context, necessitating the use of arguments for parameters and .then for result retrieval. Any console.log calls within executeScript output to the browser console.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The issue with the jQuery click event arises when utilizing the "Module Pattern"

Exploring the Module Pattern as described by Chris Coyyer here, I, an intermediate front-end JS developer, have encountered a problem. Specifically, when attempting to utilize a jQuery selector stored in the settings object, I am unable to trigger a click ...

retrieving the element's height results in a value of 'undefined'

I am attempting to get the height of a specific element, but unfortunately I keep getting undefined. Here is what I have tried: var dl; $(window).load(function(){ dl = $("#dashboard_left").height(); }); $(document).ready(function(){ alert(dl); } ...

Transferring information from offspring to parent

Greetings! I'm currently getting my feet wet with React and finding myself stuck on an issue regarding passing states. Is it possible for me to pass a child state to a parent component in order to selectively render other child components? ...

Issue with Firebase V9 addDoc: No indication of success or failure, and data is not being written to the

I am encountering an issue where the authentication related functions are working fine, but I am unable to make any progress with Firestore. Despite no errors or successes being returned by the try-catch block, nothing seems to happen in the Firestore data ...

Initial position of jQuery slider

A while back, I came across some slider code on a website and copied it. Unfortunately, I can't seem to locate the source now. Here is the code snippet: slides.min.jquery.js $(function(){ $('#slides').slides({ preload: true, ...

Accessing getUserMedia within Internet Explorer 11 or utilizing MediaStream on IE 11

I am attempting to utilize the getUserMedia function in IE 11 with the help of the temasys plugin. However, IE does not support the MediaStream instance returned by getUserMedia. Below is a snippet of my code: import React from 'react' import { ...

Persistent error function arises from Ajax request in Laravel

Greetings everyone. I'm currently working on my Laravel application and trying to verify the attendance for a specific date, subject, grade in my database table. If the data exists, I have implemented an if statement to display the desired results bas ...

The animation in an AngularJS directive only functions properly when utilizing $timeout

I can't seem to figure out why the animation is not working as intended in the code below: app.directive('openMenu', ['$animate', '$timeout', function($animate, $timeout) { return { link: function(scope, elem ...

What is the best way to extract the body content from a Markdown file that includes Frontmatter

How can I retrieve the content of the body from my markdown file using front matter? Currently, it is displaying as undefined. What steps should I take to fix this issue? {latest.map(({ url, frontmatter }) => ( <PostCard url={url} content={frontmat ...

What is the best way to implement nested iterations in Jade?

ul li a(href='') menu1 li a(href='') menu2 ul li a(href='') sub-menu2 li a(href='') menu3 ul li a(href=&apos ...

npm is unable to install a forked git repository in its current state

Attempting to install a customized version of ng2-smart-table on my application, but npm seems to be struggling with the process. I've experimented with various commands such as npm install git+http://github.com/myusername/ng2-smart-table.git npm i ...

Increase the size of the textarea when it is clicked on and revert back to its original size when it

My question revolves around a text area that I am trying to manipulate through jQuery. The desired functionality is to increase the height of the text area whenever someone clicks on it, and decrease the height when clicking anywhere else on the screen. & ...

Using JavaScript to ensure that a div is not hidden on page load if a checkbox is unchecked

Upon inspecting a page, I am implementing a script to check if a checkbox is selected. If not selected, the goal is to hide a specific div element. While troubleshooting this issue, I suspect the problem may be due to the lack of an inline element within t ...

Standardize API data for utilization in Redux

I have an API that provides the following data: const data = { id: 1, name: 'myboard', columns: [ { id: 1, name: 'col1', cards: [ { id: 1, name: 'card1' }, { id: 2, name: 'card ...

Trouble with Ruby and Selenium: Struggling to identify visible elements in a list

Trying to figure out how to identify which elements in a list are visible has been quite the challenge for me. The application I'm working with features variable menu dropdowns where each row shows different options based on specific parameters, even ...

How can I apply an underline effect when hovering over navigation links in a responsive menu?

I've successfully added an underline effect on hover for the navigation menu. However, I encountered an issue with the responsiveness of the menu. When viewed on screens smaller than 600px, the underline effect covers the entire width of the block ins ...

Encountered a SyntaxError on JSON Web Tokens Node JS Server: Unexpected token } found in JSON at position 24

Me, along with others, have encountered this issue: SyntaxError: Unexpected token } in JSON at position 24 at JSON.parse (<anonymous>) while following a tutorial on JSON Web Tokens (TUTORIAL LINK: https://www.youtube.com/watch?v=mbsmsi7l3r4&t=34s ...

Adding input values to a jQuery Ajax POST request

I am currently attempting to send form values to a remote API using AJAX. The necessary information I require from the HTML form element includes the author, string, false, and true. At the moment, I have hard-coded some values but... function sendData ...

Developing an easily optimized library using rollup to remove unnecessary code branches

I'm currently in the process of developing a component library using rollup and Vue with the goal of making it tree shakable for others who import it. The configuration setup is outlined below: Here's a snippet from package.json { "name": "re ...

Capturing Data from Tables and Saving it with Protractor

Imagine having a table structured like this <h2>HTML Table</h2> <table> <tr> <th>Company</th> <th>Contact</th> <th>Code</th> </tr> <tr> <td>Alfreds Fu ...