Selenium and AngularJS patiently wait before carrying out specific actions

I have been using selenium to test an AngularJS application and I am encountering an issue where I am unable to perform any actions on the page until it is fully loaded. Although I have considered using Thread.sleep(), I am aware that this is not the most efficient solution. I have researched and tried multiple methods to wait for the page to load, but none have been successful so far. Once I navigate to a webpage in my application, it appears visually loaded, yet I still cannot interact with it until it has fully loaded (which takes about 1 second).

If anyone could share their implementation of how they successfully solved this issue, I would greatly appreciate it.

Here is a snippet of my code:

public By ngWait(final By by) {
    return new FluentBy() {
        @Override
        public void beforeFindElement(WebDriver driver) {
            driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
            ((JavascriptExecutor) driver).executeAsyncScript("var callback = arguments[arguments.length - 1];" +
                    "angular.element(document.body).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);");
            super.beforeFindElement(driver);
        }

        @Override
        public List<WebElement> findElements(SearchContext context) {
            return by.findElements(context);
        }

        @Override
        public WebElement findElement(SearchContext context) {
            return by.findElement(context);
        }

        @Override
        public String toString() {
            return "ngWait(" + by.toString() + ")";
        }
    };
}

Answer №1

During my experience with writing tests for an Angular app using Selenium, I encountered a similar challenge. The page skeleton loads instantly in the Angular app, but it continuously makes background $http requests to fetch data. The view is only rendered once these calls are completed, making traditional Selenium waits like waitUntilPageToBeLoad or waitUntilElementToBeClickable ineffective.

One workaround is using Thread.Sleep(), but that is not considered a smart wait strategy. A more efficient approach is to implement a custom wait method to ensure that all $http calls have finished in the background. Here is a sample wait method that worked well for me:

public void untilAngularFinishHttpCalls() {
    final String javaScriptToLoadAngular =
        "var injector = window.angular.element('body').injector();" + 
        "var $http = injector.get('$http');" + 
        "return ($http.pendingRequests.length === 0)";

    ExpectedCondition<Boolean> pendingHttpCallsCondition = new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver driver) {
            return ((JavascriptExecutor) driver).executeScript(javaScriptToLoadAngular).equals(true);
        }
    };
    WebDriverWait wait = new WebDriverWait(driver, 20); // timeout = 20 secs
    wait.until(pendingHttpCallsCondition);
}

Answer №2

Unfortunately, I am unable to leave a comment at the moment, so I will provide my assistance in the form of an answer.

Regarding the issue with the comments on Priyanshu Shekhar's response, it appears that jqLite (Angular's simplified version of jQuery) may not have the necessary functionality for the task attempted by the code.

To rectify this issue, consider integrating the complete jQuery library into your webpage.

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

How to update data in AngularJS grid component using ng-bind directive

As a newcomer to AngularJS, I'm facing an issue that I need help with. Here's my problem: I have an ng-grid connected to a table. Inside the grid, there are values along with an ID (which is a foreign key from another table). Instead of display ...

Dealing with Array Splicing Issues in Angular

Being fairly new to the world of AngularJS, I suspect that I am just making a simple mistake. My goal is to splice the cardTypes array at the var newCard = cardTypes.shift(); line rather than using .shift() so that I can consider my ng-repeat index. Whil ...

The React.js component search test encounters errors in locating components

I have been working on a React app that utilizes Redux and React-router. I am currently writing tests using React TestUtils, and I encountered an issue with the following test results: The first expect statement is successful: expect(nav).to.have.length(1) ...

Koa and Stripe are patiently holding off on displaying the page

My current setup involves using koa and stripe for processing a one-time payment. Although the functionality is there, I'm facing an issue where the page renders before the 'data' assignment takes place. This results in the 'id' sh ...

The object does not contain a 'navigation' property within the 'Readonly<{}> & Readonly<{ children?: ReactNode; }>' type

As a beginner in react native, I am facing some challenges with the components I have created. Let me share them: List of Playlists: export default class Playlists extends Component { playlists = [ ... ]; render() { const {navigation} = th ...

Is there a way to create a list of languages spoken using Angular?

I am in search of a solution to create a <select> that contains all the language names from around the world. The challenge is, I need this list to be available in multiple languages as well. Currently, I am working with Angular 8 and ngx-translate, ...

Leveraging environmental variables in a Vue.js web application

The article I recently came across discussed how to effectively utilize environment variables in vuejs. Following the instructions, I set up my local .env.local file and also installed dotenv. VUE_APP_AUTH_AUTHORITY = 'http://localhost/auth' I ...

React throwing an error when attempting to include a Link component from react-router-dom

Currently working on a React app and encountering an issue while trying to add the Link component from the react-router-dom package. The main routes are defined in the App.js file structured as follows: https://i.stack.imgur.com/BF8M8.png The <Header ...

Are there any effective methods to improve coding efficiency in BeautifulSoup4?

def extract_data_from_table(self) -> typing.Union[dict, None]: page_source = self.driver.page_source soup = BeautifulSoup(page_source, "html.parser") data_container = soup.find_all("div", {"class":"scaledRo ...

Displaying random characters in place of Angular 6 font awesome icons

Recently, I started a new project with the angular cli and incorporated font-awesome 4.7.0. After that, I included it as a dependency in my angular.json file. "styles": [ "./node_modules/font-awesome/css/font-awesome.min.css", "./node ...

An issue occurred while deploying Docker on Railway services: Build Error

After successfully deploying my Django project on Railway, I decided to add SendGrid mail functionality using the django-sendgrid-v5 package. Everything worked fine in the development environment, including sending emails like user signups. However, when ...

What is the best way to show the current date and time?

To filter out and display only the date from the array that is the largest compared to the current date, all dates are displayed. const states = States.select().exec() var curr = new Date(); for (var i = 0; i < states.length; i++) { var maxDate = ...

What is the best way to dismiss the additional modal popup?

Here is an example that I need help with: http://jsfiddle.net/zidski/Mz9QU/1/ When clicking on Link2 followed by Link1, I would like the Link2 box to close automatically. Is there anyone who can assist me with this issue? ...

The getServerSideProps function in Next.js is only executed once, meaning it won't retrieve fresh data when accessed via next/router

I'm working on a Next.js application with Server-Side Rendering (SSR) where I have an async function called getServerSideProps that is exported like this: export const getServerSideProps = getGenericServerSideProps([""]); The getGenericServerSideProp ...

What is the process for running .js files on my browser from my local machine?

Hi there! I'm trying to figure out how I can create a JavaScript game in TextMate on my Mac. I want to have a regular .js file, then open it and run it in Chrome so that whatever I have coded - for example, "Hello World!" - will display in the browser ...

Setting up WebPack for TypeScript with import functionality

A tutorial on webpack configuration for typescript typically demonstrates the following: const path = require('path'); module.exports = { ... } Is it more advantageous to utilize ES modules and configure it with import statements instead? Or is ...

Steps to activate a single button within a deactivated fieldset

Is there a way to deactivate all elements within a Fieldset, while keeping certain buttons active? Check out this demo. <fieldset ng-disabled="true"> <legend>Personalia:</legend> Name: <input type="text"><br> Em ...

Assigning a click event to an element within CKEditor

Looking to add a click event to an element in ckeditor4-angular for custom functionality <div class="fractional-block" id="fractional-block"><span>5</span><svg height="5" width="100%"><line ...

Ways to eliminate space within a list?

I am currently engaged in a project where I am extracting data from Indeed search results. At the moment, when I print the data I find, it appears with a space before the semicolon. Currently, my data prints like this: "Item 1 ; Item 2" I wan ...

Error: The strategy for authentication is not recognized as "login" - Express and Passport

I am currently experimenting with a basic MEAN stack tutorial I found online. The technologies involved are: Node.js Express.js Passport.js Below is the code snippet for the application file: app.js var express = require("express"); var mongoose = req ...