Exploring AngularJS testing using Protractor's browser.wait() method

In the process of developing an automated test suite for an AngularJS application using Protractor, I have reached a point where I no longer need to manually pause the script at each step with browser.pause(). Now, I want to let the script run through to completion on its own.

To achieve this, I am exploring the use of browser.wait() to ensure the browser has loaded before executing the next step. I am passing the last line of each test as a parameter to browser.wait() along with a timeout value. For example:

it('should log the user in to the application', function() {
    browser.wait(loginAsUser(username, password), 10000);
});

instead of the previous:

browser.pause();

it('should log the user in to the application', function() {
    loginAsUser(username, password);
});

However, I encountered a failure with the message: "Failed: Wait condition must be a promise-like object, function, or a Condition object". This error puzzled me as the wait condition is a function, specifically the loginAsUser() function previously defined.

Further edits to my test revealed issues with subsequent tests failing due to elements not being found after the login step. It seems that the page was not given enough time to load following the login when browser.pause() was removed.

Attempts to use browser.wait() within the failing test did not resolve the issue, leading to the same "Failed: No element found using locator" error. It became clear that the application required more time to load after the login before proceeding to the next test.

Finally, I optimized the test script with a new approach utilizing EC.visibilityOf() and browser.wait() to wait for elements to be displayed before interacting with them. However, the test still failed with unexpected results, indicating a need for further debugging and understanding of the implementation.

Answer №1

Typically, waiting for a hardcoded period of time is not recommended.

It is advisable to pair the waiting process with an expected condition to break free as soon as the condition is met.

Here's an example of a helper method:

public static async waitForPresenceOf(element: ElementFinder, waitMs?: number): Promise<boolean> {
    return browser.wait(EC.presenceOf(element), waitMs || 5000).then(() => true, () => false);
}

You can also apply the same concept to wait for the visibility of elements and similar scenarios.

Below is a collection of helper methods, written in TypeScript, that you might find useful:

// Collection of helper methods
import * as webdriver from 'selenium-webdriver';
import By = webdriver.By;

// Other imports
import {browser, element, protractor, by, WebElement, ElementFinder, ElementArrayFinder} from "protractor";

// Main class definition
import * as _ from 'lodash';
import {expect} from "./asserts.config";

let EC = protractor.ExpectedConditions;

export default class BrowserHelper {
    // Methods definition here...
}

When writing test cases, it's important to incorporate waiting periods. Here's an example:

it('should log the user in to the application', function(done) {
      BrowserHelper.sendKeys(usernameInputField, username)
        .then(function() { 
            return BrowserHelper.sendKeys(passwordInputField, password) 
        })
        .then(function() {
            return BrowserHelper.click(loginBtn)
        }).then(done)
});

Make sure to include the done parameter in the test case to indicate when the test is completed.

Alternatively, you can achieve the same result by returning a promise:

it('should log the user in to the application', function() {
      return BrowserHelper.sendKeys(usernameInputField, username)
        .then(function() { 
            return BrowserHelper.sendKeys(passwordInputField, password) 
        })
        .then(function() {
            return BrowserHelper.click(loginBtn)
        })
});

Answer №2

The error you're encountering is due to the fact that the wait method requires a condition to be met or a promise to be resolved.

For instance, if you're waiting for an element with the id abc to become visible after loginBtn.click();, you would write something like the following. Refer to ExpectedConditions for more details.

var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to become visible in the DOM.
browser.wait(EC.visibilityOf($('#abc')), 5000);

Alternatively, if you need to wait for a specific custom condition (e.g., the visibility of an element), you can use the following approach:

browser.wait(function(){
    element.isDisplayed().then(function(isDisplayed){
       if(!isDisplayed) {
          return false; // continue looking until it's visible;
       }
       return true; // exit unless the timeout has been reached
    });
}, 5000);

Additional information provided in their documentation:

For example, suppose you have a function called startTestServer that returns a promise indicating when the server is ready for requests. You can sync a WebDriver client to this promise as follows:

Sample Code:

var started = startTestServer();
browser.wait(started, 5 * 1000, 'Server should start within 5 seconds');
browser.get(getServerUrl());

Modifications based on new details

pageTagBrowserBtn.isDisplayed() returns a promise rather than a boolean value. Therefore, if you're using chai expect, you should follow the example below:

it('should display the Pages menu', function() {
    browser.waitForAngularEnabled(false);
    browser.wait(EC.visibilityOf(pagesMenuBtn), 5000).then(
        browser.actions().mouseMove(pagesMenuBtn).perform().then(function(){
           pageTagBrowserBtn.isDisplayed().then(function(isDisplayed) {
                  // verify isDisplayed is true at this point
           });
        })).then(
        browser.actions().mouseMove(userCircle).perform().then(function(){
            expect(pageTagBrowserBtn.isDisplayed()).toBeFalsy();
        }));
});

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

Did I accidentally overlook a tag for this stylish stripe mesh Gradient design?

I've been attempting to replicate the striped animated Gradient mesh using whatamesh.vercel.app. I've set up the JS file, inserted all the gist code into it, and placed everything in the correct locations, but unfortunately, it's not functio ...

Is it possible to export informative test titles in Selenium / Gherkin / Cucumber?

Within my feature files, I have implemented tests using the Scenario Template method to input multiple parameters. For instance: @MaskSelection Scenario Template: The Mask Guide Is Available Given the patient is using "<browser>" And A patie ...

Retrieving JSON information stored in a JavaScript variable

I'm feeling a bit embarrassed to admit it, but I am still learning the ropes when it comes to Javascript development. I've hit a roadblock and could really use some help from the experts here. Thank you in advance for all the assistance this comm ...

Changing the user object stored in the database within the next authentication process following registration

In my next.js application, I have implemented Next Auth for authentication and used a database strategy. Once a user logs in, is there a way to update their data? ...

What is the process for retrieving randomized data using mongoose?

I recently came across the mongoose-random package which allows for retrieving a JSON array of random records using mongoose. My goal is to retrieve three random records with a specific field. Despite reviewing the documentation, I have yet to find a work ...

How to dynamically disable options in a Vuetify v-select based on the type of object value

When utilizing the Vuetify v-select component and setting the prop multiple, we can select multiple values at once. In this scenario, I have a variety of recipes categorized under Breakfast or Dinner using the parameter type. The goal is to deactivate al ...

Why isn't my script responding to mouse events like mouseenter, mouseover, or any other mouse event?

const element = document.getElementById("box"); element.addEventListener("mouseenter", handleMouse); function handleMouse(event) { console.log("Event type: " + event.type); } ...

Is it possible to stack one Canvas on top of another?

Right now, I am engaged in a process that involves: creating a canvas and attaching it to a division applying a background image through CSS to that canvas. drawing a hex grid on the canvas placing PNGs on the canvas. animating those PNGs to show "movem ...

Is there a way to dynamically incorporate line numbers into Google Code Prettify?

Having some trouble with formatting code and inserting/removing line numbers dynamically. The line numbers appear on the first page load, but disappear after clicking run. They don't show at all on my website. I want to allow users to click a button a ...

The challenge with Three.js CTM loader: Developing a separate .js file to reference the .ctm file

When using the CTM loader function, I was able to successfully create a .ctm file for the object, but I am having difficulty creating a .js reference file for it in the same way that the three.js example file does. If anyone can provide guidance on this ...

Easy way to eliminate empty elements following a class using jQuery

I'm encountering a situation where I have a group of elements following a specific class that are either empty or contain only white space. <div class="post-content"> <div class="slider-1-smart"> --- slider contents --- < ...

Can JavaScript bypass the need for an html page and go directly to the printing process?

Is it possible for a user to click a "print" button and have the printer start printing? Please note that there is already a server process in place (via AJAX) that can respond with success for printing or return HTML content for display, so that is not a ...

AngularJS: Transforming form field inputs into JSON format

I am curious about how I could create a function (either a directive or controller) that can convert all of my form inputs into JSON, including their current values. The JSON format I have in mind is something like this: { fields: [ {fi ...

Interacting with APIs in Svelte applications

I'm fairly new to utilizing Svelte and JavaScript. I've been attempting to construct a page that incorporates numerous API components from external websites, but I'm facing some challenges. I'm uncertain about where exactly to place the ...

What to do when encountering a problem with HTML, CSS, and JS while loading a webpage from an SD card to a WebView

I am facing an issue while loading an HTML file from the SD card to a webview. The problem is that the CSS, images, and videos are not loading properly in the webview. Compatible with Android 4.4 KitKat and Chrome version Not compatible with versions belo ...

Use Ajax to dynamically update the href attribute of an ID

I have a page with songs playing in a small audio player, and the songs change every 1-2 minutes or when I choose to (like a radio). Users can vote on each song using the following format: <span class='up'><a href="" class="vote" id="&l ...

The click() function in jQuery executing only once inside a "for" loop

This is an example of my HTML code: <!DOCTYPE html> <head> <title>Chemist</title> <link href="stylesheet.css" rel="stylesheet"> </head> <body> <h2 id="money"></h2> <table border="1px ...

Encountering issues with parsing JSON data following its transmission through an Ajax request

Client Side Once an object has been processed with JSON.stringy, it is sent in this format to a node-server via a POST request: {"id":"topFolder","parentPath":null,"name":"newProject","is":"root","children":[]} The request is sent from the client side u ...

Navigate down to the bottom of the element located on the webpage

I'm trying to create a feature where clicking an anchor tag will smoothly scroll to a specific element on the page. Currently, I am using jquery scrollTo for this purpose. Here's the code snippet: $.scrollTo( this.hash, 1500, { easing:&apos ...

What is the reason why calling setState does not update the local state?

Hello everyone, I came across an intriguing React task and I'm struggling a bit with finding the solution. Task: Can you figure out why this code isn't working and fix it? Code: class BugFixer extends React.Component { constructor(props) { ...