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

Discover the best methods for accessing all pages on a Facebook account

I attempted to retrieve a list of all Facebook pages, but encountered an error. The error message states: 'request is not defined.' Here is the code snippet: var url = 'https://graph.facebook.com/me/accounts'; var accessToken = req.u ...

Changing the bootstrap popover location

I'm looking to customize the position of a Bootstrap popover that appears outside of a panel. Here's my setup: HTML: <div class="panel"> <div class="panel-body"> <input type="text" id="text_input" data-toggle="popover ...

What are some React component libraries compatible with Next.js 13.1?

I'm exploring Next.js and experimenting with version 13.1 and the new app directory. Is it feasible to accomplish this without sacrificing the advantages of server controls? An error message I encountered states: You're attempting to import a c ...

Encountering a problem with the JavaScript promise syntax

Using pdfjs to extract pages as images from a PDF file and then making an AJAX call to send and receive data from the server is proving to be challenging. The implementation for iterating through the pages in the PDF was sourced from: The issue lies in pr ...

Updating a component from a different source

As a newcomer to React, I'm curious about the ability to update one component's content based on events from another component. I have two React components set up. The first component loads data when the page initializes, while the second compon ...

Calendars malfunctioning following the execution of npm run build

While utilizing the vue2-datepicker for a calendar, I encountered an issue during development. When clicking on the input box in my form, the calendar appeared as expected above the input. However, after running npm run build and loading up the resulting p ...

Implementing a dynamic update of an HTML element's content with JSON data - Learn how!

My task involves creating a quiz application where I need to show the answers along with images of the choices stored in my JSON data. However, I encounter an error: Uncaught TypeError: Cannot set properties of null (setting 'src') when I attempt ...

Adjust the HTML 5 range slider to update according to the selected value

Is it possible to create a custom marker on an HTML5 range input element? I'm looking for a way to change the design of the circle marker as it moves along the scale from 1 to 10. Specifically, I want to change the color of the marker based on its po ...

Unusual output from the new Date() function: it displays the upcoming month

Your assistance and explanation are greatly appreciated. I have created a method that is supposed to return all the days of a given month by using two parameters- the year and the month: private _getDaysOfMonth(year: number, month: number): Array<Date& ...

Consecutive pair of JavaScript date picker functions

My issue involves setting up a java script calendar date picker. Here are my input fields and related java scripts: <input type="text" class="text date" maxlength="12" name="customerServiceAccountForm:fromDateInput" id="customerServiceAccountForm:from ...

Unable to successfully download npm packages - encountered an error running `[email protected] install: `node-pre-gyp install --fallback-to-build` on Ubuntu 18.04 system

I am facing an issue while trying to npm install (using lerna bootstrap) a project on Ubuntu 18.04. The error I encounter is related to node-pre-gyp install --fallback-to-build. I have attempted installing node-gyp, node-pre-gyp, and apt-get build-essenti ...

Positioning a Material UI Menu item underneath its parent element using CSS styling

I have created a Material UI dialog that features some text and an Icon with a dropdown menu option. You can check out the demo here: https://codesandbox.io/s/prod-rain-1rwhf?file=/src/App.js My goal is to properly position the Menu component so that it a ...

Adding ui-router states to an existing ui-view element

Application structure $stateProvider. state('azured', { url: "/azured/", }). state('azured.ref', { url: "/ref", }). state('azured.ref.table', { url: "/table/:tableId", }). s ...

Ways to transfer a value from ng-Init to the following controller

Upon loading the Index page, a userName is retrieved. Controller Action in MVC public ActionResult Index() { string userName = "Current User" return View((object)userName); } Subsequently, an attempt is made to store this value using ng-init. Ind ...

The mapStateToProps function is returning an undefined value

import React, { Component, Fragment } from "react"; import { connect } from "react-redux"; import { login, logout } from "./redux/actions/accounts"; import Home from "./Home"; import Login from "./Login"; class ToggleButton extends Component { render() ...

Ways to track all requests completed in Nuxt 3

I am looking to create a unique loading page that conceals itself once all requests and static data have been loaded, including static images and libraries. How can I determine when all requests and static data have finished loading? I have attempted the ...

Why does Angular require a $broadcast when updating a list?

Currently, I am utilizing a Service that includes a list and various methods to manipulate that list. The Service gets initialized in the app.run() function and is shared among multiple controllers. The NavCtrl controller has a method for updating the ent ...

The resetFields() function fails to execute

While utilizing Vue3 with Element Plus to create a form, I encountered an issue with the resetFields() method not working as expected. The form is unable to automatically refresh itself. In the child component (Edit.vue): <template> <el-dialo ...

ConfirmUsername is immutable | TypeScript paired with Jest and Enzyme

Currently, I am experimenting with Jest and Enzyme on my React-TS project to test a small utility function. While working on a JS file within the project, I encountered the following error: "validateUsername" is read-only. Here is the code for the utilit ...

Unable to activate focus() on a specific text field

It's quite peculiar. I'm working with a Sammy.js application, and my goal is to set the focus on a text field as soon as the HTML loads. Here's the CoffeeScript code snippet I've written: this.partial('templates/my-template.jqt&ap ...