Tips for choosing a visible element in Protractor while using AngularJS

I am working on a Single Page Application that contains multiple divs with the same class. My goal is to have protractor identify the visible div and then click on it. However, I keep encountering the error Failed: element not visible, which leads me to believe that the locator is finding an element that may not be on the current page. Additionally, I receive a

WARNING - more than one element found for locator By.cssSelector('.myDiv') - the first result will be used
message, indicating that the click operation might be targeting an invisible element instead of the visible one.

Below is my test specification:

describe('User actions', function () {
    it("should be able to click a my div.", function () {
        var myDiv = element(by.css('.myDiv'));
        myDiv.click();

        // some expect... haven't gotten this far yet.
    });
});

How can I ensure that protractor selects the visible .myDiv element and clicks on it?

Answer №1

To eliminate unwanted elements, you can utilize the filter() method:

var specificDiv = element.all(by.css('.specificDiv')).filter(function (element) {
    return element.isDisplayed().then(function (isDisplayed) {
        return isDisplayed;
    });
}).first();

Answer №2

The approach and method utilized in my response are essentially identical, however, I have discovered that my solution offers greater reusability.

To achieve this, define a function as follows:

getFirstDisplayed(locator: Locator) {
  return element.all(locator).filter(x => x.isDisplayed()).first();
}

Then simply transform your commands from:

element(by.css('img[title="Delete query rule"]')).click();

to:

getFirstDisplayed(by.css('img[title="Delete query rule"]')).click();

By following this method, you will be able to click on the first displayed item each time.

Answer №3

When working with Angular, it is common to have multiple layers of hidden HTML elements within the overall structure of the page. Sometimes, you may need to access a specific visible element that is buried under these layers.

For debugging purposes, one approach is to open your site and inspect the HTML to locate the element that your Protractor test is targeting. You can determine if it is visible and its position within the DOM hierarchy.

If needed, consider adding unique tags to different areas where the element might appear and use parent-child selectors to pinpoint the desired element.

You can also implement a function to select only the first visible element:

// Function to retrieve the first displayed element
// Example:
// var coolBox = $('.coolBox');
// var visibleCoolBox = getFirstVisibleProtractorElement(coolBox);
this.getFirstVisibleProtractorElement = function(selector){
    var allElementsOfSelector = element.all(by.css(selector.locator().value));
    return allElementsOfSelector.filter(function(elem) {
        return elem.isDisplayed().then(function(displayedElement){
             return displayedElement;
        });
    }).first();
};

Simply pass in any element for the function to extract the first visible version of it. If necessary, you can remove the .first() method to obtain an array of visible elements to work with.

NOTE: Please note that the following example assumes there are multiple elements on the page, with at least one being visible. It uses Protractor with Jasmine for demonstration.

example_spec.js

var examplePage = require('./example_page.js');

describe('Extracting visible elements', function(){
    it('Should extract a visible element successfully', function(){
        expect(examplePage.isACoolBoxVisible()).toBeTruthy('Error: No visible CoolBoxes');
    });
});

example_page.js

var protractorUtils = require('./protractor_utils.js');

module.exports = new function(){
    var elements = {
        coolBox: $('.coolBox')
    };

    this.getVisibleCoolBox = function(){
        return protractorUtils.getFirstVisibleProtractorElement(elements.coolBox);
    };

    this.isACoolBoxVisible = function(){
        return getVisibleCoolBox.isDisplayed();
    };
};

protractor_utils.js

module.exports = new  function(){
    this.getFirstVisibleProtractorElement = function(selector){
        var allElementsOfSelector = element.all(by.css(selector.locator().value));
        return allElementsOfSelector.filter(function(elem) {
            return elem.isDisplayed().then(function(displayedElement){
                 return displayedElement;
            });
        }).first();
    };
};

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

Tips for validating a dynamically created form with Bootstrap tabs using jQuery

For my project, I am dynamically creating an HTML form using jQuery. The page consists of five tabs, each with separate previous and next buttons. These tabs are designed using Bootstrap. Can someone please suggest the easiest way to validate this page? Fo ...

How can I create a textbox in vue.js that only allows numeric input?

methods: { acceptNumber() { var x = this.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/); this.value = !x[2] ? x[1] : '(' + x[1] + ')' + x[2] + (x[3] ? '-' + x[3] : & ...

Having trouble getting a constructor to function properly when passing a parameter in

Here's the code snippet I'm working with: import {Component, OnInit} from '@angular/core'; import {FirebaseListObservable, FirebaseObjectObservable, AngularFireDatabase} from 'angularfire2/database-deprecated'; import {Item} ...

Display a single item from nested objects using ng-repeat

Imagine having an object where the keys represent different products and the values consist of objects with keys representing price points at which those products were sold, along with corresponding amounts sold. For instance, if you sold 10 widgets at $1 ...

In JavaScript, a "switch statement" retrieves a test value from a "input type text" by accessing the value using getElementByName.value

Attempting to test 7 possible values for the variable 'a' by passing it to a function from user input in seven 'input type text' boxes, then checking each value individually with clicks on 7 'input type image' elements. Howeve ...

Send a file using ajax with the help of JavaScript and PHP

Currently, I am looking to implement a method for uploading files using Ajax and JavaScript/PHP without having the page refresh. My initial thought is to use Ajax to send the file using xmlhttp.send(file) and then retrieve it in the PHP script, but I' ...

A singular Vuejs Pinia store utilizing namespaced actions

Is it possible to separate pinia actions into two distinct namespaces, allowing access through properties n1 and n2 like this: // current store.n1a('hi') store.n2b() // wanted store.n1.a('hi') store.n2.b() // cumbersome workaround: sto ...

What is the best way to determine if an AJAX response is of the JavaScript content type?

There are multiple forms in my system, each returning different types of data. I need to be able to distinguish between a simple string (to display in the error/status area) and JavaScript code that needs to be executed. Currently, this is how I'm ha ...

Facing issues with Express, http-proxy-middleware, and encountering the error net::ERR_CONNECTION_REFUSED

For some time now, I've been troubleshooting an issue with my Express App that utilizes http-proxy-middleware to forward requests to another backend service. The problem arises when a third-party application makes a request to my server using an IP ad ...

Struggling to import MUI components from node modules in your React JavaScript project using Vite? Discover why autosuggestion isn't getting the

Encountering a dilemma with autosuggestion in Visual Studio Code (VSCode) while attempting to import MUI (Material-UI) components from node modules in my React JavaScript project built with Vite. The autosuggestion feature is not working as intended, causi ...

Utilizing numerous Nuxt vuetify textfield components as properties

Trying to create a dynamic form component that can utilize different v-models for requesting data. Component: <v-form> <v-container> <v-row> <v-col cols="12" md="4"> <v ...

Utilizing the js-yaml library to parse a YAML document

Currently, I'm utilizing js-yaml to analyze and extract the data from a yaml file in node js. The yaml file consists of key-value pairs, with some keys having values formatted like this: key : {{ val1 }} {{ val2 }} However, the parsing process enco ...

Other Components take turns submitting the form in one Component

Two components, CreateCandidate and Technologies are being used. CreateCandidate requires technologies from the Technologies Component. When passing the technologies to CreateCandidate, the form within CreateCandidate is submitted. Below is the code: Crea ...

Challenges arising with the express search feature

Currently, I am in the process of developing an API for a to-do application. I have successfully implemented the four basic functions required, but I am facing some challenges with integrating a search function. Initially, the search function worked as exp ...

Is there a way to activate the width styling from one class to another?

I have these 2 elements in my webpage: //1st object <span class="ui-slider-handle" tabindex="0" style="left: 15.3153%;"></span> //2nd object <div id="waveform"> <wave style="display: block; position: relative; user-select: none; he ...

Tips for saving and accessing Shopping Cart items using localstorage

As I develop a shopping cart for an e-commerce site, I aim to utilize browser localstorage to store the products. The functions that have been added to my code include: - addToCart(): triggered when the "Add to Cart" button is clicked. - addProduct(): ...

Storing an HTML page in a PHP variable, parsing it, and displaying it correctly

I am currently using the simple_html_dom parser to extract information from an HTML page. After making some modifications, I would like to display this content on my own page. $page = file_get_html($url); foreach($page->find('div#someDIv') as ...

Tips for swapping images as a webpage is scrolled [using HTML and JavaScript]

Hi there, I am looking to make some changes to a JavaScript code that will switch out a fixed image depending on the user's scrolling behavior. For example, when the page loads, the image should be displayed on the right side. As the user scrolls down ...

Merge objects based on specific property within an array of objects

Is there a way to merge objects based on one property and also add missing Days names in the output? Consider this example: var array = [ { "heure1": "14:00", "heure2": "17:00", "day&q ...

Easy task tracker in Vue.js

I’m currently delving into the world of VueJS and working on a simple to-do list application. The issue I’m facing is that I can't seem to successfully pass an array to the child component responsible for displaying the list: Parent Component < ...