What is the best way to access the text content of a nested HTML element for automation tasks with Selenium or Protractor?

Can anyone help me with this HTML code snippet? I want to extract and display only the text within the desc class - "Print this", ignoring the text in the spell class. This needs to be done using either Protractor or Selenium.

<span class="desc">
Print this
    <a class="new-link" href="#">
        <span class="spell">And not this</span>
    </a>
</span>

I attempted using the getText() method, but it printed both parts of the statement as shown below:

Print this And not this

In Protractor with Javascript:

element(by.css('.desc')).getText().then(function(text){
    console.log(text);
});

In Selenium with Java:

System.out.println(driver.findElement(by.xpath('//*[@class=".desc"]')).getText());

Any suggestions on how to only print the first part of the text ("Print this")?

Your assistance is greatly appreciated! Thank you.

Answer №1

ElementFinder.getText() retrieves the text content of an element by calling innerHTML and then removing any leading and trailing whitespaces. However, innerHTML includes all child elements within the element at any level of nesting. While there isn't a built-in property in the DOM to specifically retrieve only first-level text, it can be implemented manually. Text within the DOM is treated as a node and stored in the DOM tree similarly to tag elements, just with different characteristics. By accessing the property Element.childNodes, we can obtain the first-level children elements of the main element, iterate through them to extract only text nodes, concatenate their content, and return the result.

To streamline this process in Protractor, I have created a custom method that extends the prototype of ElementFinder. This enhancement allows for simple usage across all Protractor elements. You may choose where to include this additional code, but I recommend placing it before your tests, perhaps in protractor.conf.js.

protractor.ElementFinder.prototype.getTextContent = function () {
    // Inject script onto the page
    return this.ptor_.executeScript(function () {
        // Note: this scope is not specific to Protractor

        // Current element
        var el = arguments[0];
        var text = '';

        for (var i = 0, l = el.childNodes.length; i < l; i++) {
            // Extract text from text nodes exclusively
            if (el.childNodes[i].nodeType === Node.TEXT_NODE) {
                text += el.childNodes[i].nodeValue;
            }
        }

        // Optionally trim leading and trailing whitespace
        text = text.trim();

        return text; // The final outcome - Promise resolves with this value

    }, this.getWebElement()); // Pass the current element to the script
};

This method returns a Promise that resolves with the value stored in the text variable. To apply it:

var el = $('.desc');

expect(el.getTextContent()).toContain('Print this');

// or 

el.getTextContent().then(function (textContent) {
    console.log(textContent); // 'Print this'
});

Answer №2

I recently implemented a solution proposed by Michael directly into my test case, skipping the function call. While this approach works fine, I would still recommend using it as a standalone function if you anticipate needing to reuse it. However, for those looking for an inline solution, here is a way to achieve it -

it("Extracting First part of text", function(){
    browser.executeScript(function () {
        var element = arguments[0], extractedText = '';
        for (var j = 0, len = element.childNodes.length; j < len; j++)
            if (element.childNodes[j].nodeType === Element.TEXT_NODE)
                extractedText += element.childNodes[j].nodeValue;
        return extractedText.trim();
    },$('.desc').getWebElement()).then(function(extractedText){
        //include expect statements with "extractedText" as necessary
    });
});

Wishing you success with your implementation.

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

Analyzing the string's worth against the user's input

I need help figuring out how to save user input on a form (email and password) as variables when they click "Register", so that the data can be used later if they choose to click "Login" without using default information. I am working on this project for s ...

Change the className of an element in React upon clicking it

I just finished developing a menu bar using ReactJS with some basic routing features. Here is the JSX code for the component: class TopBar extends Component { state = { menus: [{id:0,menu:"Home"}, {id:1,menu:"Contact"}, {id:2,menu:"About"}] } a ...

Exploring the intricacies of parsing nested JSON data

Could someone assist me with understanding the following json data? { "Message":"The request is invalid.", "ModelState":{ "model.ConfirmPassword":["The password and confirmation password do not match.","The password and confirmation passwo ...

Consolidate and then transfer to a different database

How can I insert the data returned from my aggregate (controller function) into another collection called User? Here is the schema for the User: const userSchema = new mongoose.Schema({ firstName: { type: String, required: [true, &ap ...

Designing a user interface that consists of numerous distinct components

Challenge I'm faced with a dilemma regarding site A, which is built using React. Specifically, I need to find a way to integrate smaller React components into site A whenever a user navigates to a specific page within the site. Each of these smalle ...

Interactive JQuery plugin for scrolling through thumbnails with customizable buttons

I am attempting to create a jQuery thumbnail scroller with buttons that respond to mousedown and mouseup events. I have successfully implemented the scrolling functionality, but I am facing issues when trying to refactor it into a reusable function. Below ...

How can I utilize the pick parameter in nuxtjs3 useFetch for selecting arrays or performing a deep pick?

Currently working on my nuxtjs3 project, where I am extracting data from an API. Specifically using jsonPlaceholder for this task. Extracting data from a single object is not a problem: const { data: useFetchOnly } = await useFetch('https://jsonplace ...

What could be causing my state not to change in Nextjs even though I followed the quick start guide for Easy Peasy?

I recently encountered an issue while trying to implement easy peasy for global state management in my nextjs app. The problem I faced was that the state would only update when I changed pages, which seemed odd. To better understand what was going on, I de ...

Identifying when a user closes a tab or browser to trigger a logout in JavaScript with Vue.js using the Quasar framework

Is there a way to trigger the logout function only when the tab or browser is closed, and not when the page is refreshed? I attempted the following code example, which successfully triggers the logout on tab close but also logs out when the page is ref ...

Is there a method in JavaScript and Vue.js to detect when a drag event exits the boundaries of a container?

Currently, I am in the process of incorporating a drag and drop feature in my todo app built with Vue.js. This functionality allows users to freely move todo items within the list by dragging them either before or after other elements. The challenge is to ...

Ways to deactivate a button using CSS

I need to use Javascript to disable a link based on its id. By default, the link is invisible. I will only enable the link when the specific id value comes from the backend. HTML <li id="viewroleId" style="display: none;"> <a href="viewrole" ...

Display complete information of the selected list in a modal window by clicking on it in PHP Yii

I recently started working with the Yii framework and encountered a challenge when trying to pass data from a list to a modal using AJAX. The modal is located within the same view as the list. Here's a snippet of my code: This is my view: <div id ...

"Modifying Code Aesthetics in WebStorm/IDEA: A Step-by-

Here is the code style I am currently using in my JavaScript project: var obj = { a: 1 , b: 2 , c: 3 } var arr = [ 'a1' , 'a2' , 'a3' ] const w = 1 , w2 = 2 , w3 = 3 The team claims they are following npm's co ...

Locate the XPath for a recurring AngularJS element

Is it possible to determine the xpath for an angularJs element? I noticed that all links on my page share the same xpath due to repeated items in angularJS. .//*[@id='div_1_1_1_2']/div/div[1]/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/a I have ...

To enable communication between methods, you can easily add a property to a JavaScript class component

Is there a better way to communicate between methods in a class? class T extends React.Component { constructor(props) { super(props) this.a = false; } methodA { //will set 'a' in this method, maybe async. } ...

What steps can be taken to ensure that all object properties become reactive?

Let's dive into this simplified scenario: interface Pup { name: string; age: number; } const puppy: Pup = { name: 'Rex', age: 3, }; The goal here is to establish a reactive link for each attribute within the puppy object. The usua ...

Grab the webpage's URL by collecting the link from the src attribute of the script tag using XSLT

Can XSLT be used to extract a URL link specified within the src attribute of a script tag in an HTML file? Here is an example of the HTML file: <HTML> <BODY> <SCRIPT language="javascript" src="http://myspace.com" type="text/javascript"> ...

Automated task scheduled to execute every minute between the hours of 8am and 4.30pm using Cloudwatch Events

I am facing an issue with my working CRON schedule. It currently runs from 8am to 5pm and I need to change it to end at 4:30pm. Is it possible to set a specific half-hour time interval in CRON? Below is the current setting for my CRON: 0/1 8-17 ? * MON- ...

Utilize React to Effectively Control Multiple Audio Files on a Single Page, Ensuring Only One Plays at a Time with Function

I am currently working on a new React app that includes multiple music cards on the same page. I am looking to modify the state of the previous card before updating the state of the new card. Essentially, I aim to pause the audio playing in the previous ca ...

Converting hexadecimal string to a double value in Java

Currently, I am working on decoding the value of the "Well-known Binary" format using Java. The Node script below accomplishes this task: Buffer.from('A4C0A7DEBFC657C0', 'hex').readDoubleLE() // returns -95.1054608 I am struggling to f ...