What is the best way to hold off until a specific condition is met?

Seeking guidance as a newbie in the world of Protractor, I am currently attempting to implement an end-to-end test. However, facing some challenges as the page I wish to test is not entirely Angular-based. My initial spec looks like this:

describe('should open contact page', function() {
var ptor = protractor.getInstance();

beforeEach(function(){

   var Login = require('./util/Login');
   new Login(ptor);
});

In my quest to navigate to the contact page post-login, Protractor persistently attempts to find elements before the page is fully loaded.

I have tried utilizing the following code snippet:

browser.driver.wait(function() {

    expect(browser.findElement(by.xpath("//a[@href='#/contacts']")).isDisplayed());
    ptor.findElement(by.xpath("//a[@href='#/contacts']")).click();

});

Regrettably, this approach has been unsuccessful, with Protractor consistently attempting to locate elements prior to page completion. Another attempt made was:

browser.driver.wait(function() {
    expect(ptor.isElementPresent(by.xpath("//a[@href='#/contacts']")));          
    ptor.findElement(by.xpath("//a[@href='#/contacts']")).click();
});

While resorting to browser.sleep(); does get the job done, I acknowledge it may not be the most efficient solution. In my login class, the following line is present:

ptor.ignoreSynchronization = true;

Is there a way to pause and wait for @href='#/contacts' before Protractor attempts to perform a click action?

Answer β„–1

With the release of Protractor version 1.7.0, a new feature has been introduced: Expected Conditions.

This update includes various predefined conditions that can be used to explicitly wait for certain events. For example, if you need to wait for an element to appear:

var EC = protractor.ExpectedConditions;

var e = element(by.id('xyz'));
browser.wait(EC.presenceOf(e), 10000);

expect(e.isPresent()).toBeTruthy();

Additional resources:

  • Understanding expected conditions in Protractor

Answer β„–2

After some trial and error...

   var loadingElem = by.css('#loading.loader-state-hidden');

   browser.wait(function() {
       return ptor.isElementPresent(loadingElem);
   }, 8000);

   expect(ptor.isElementPresent(loadingElem)).toBeTruthy();

   var contactLink = by.xpath("//a[@href='#/contacts']");
   element(contactLink).click();

This method allowed Protractor to wait for the element until the page finished loading. Big thanks to those who offered assistance! πŸ˜„

Answer β„–3

For a while, I struggled with the same issue while using protractor in my e2e tests. My scenario involved transitioning between non-angular and angular portions, which posed some challenges. The key to overcoming this is understanding promises and how they function. Below are snippets of code from my actual e2e test that may provide insights on structuring your own tests. While there might be room for improvement, this approach has proven to be effective.

To navigate to the angular section, I utilize:

var ptor;
var events = require('events');
var eventEmitter = new events.EventEmitter();
var secondClick = require('./second-click');

beforeEach(function () {
    browser.driver.get('http://localhost:8080/', 10000);
});

it("should start the test", function () {
    describe("starting", function () {
        it("should find the link and initiate the test", function(){
            var elementToFind = by.linkText('Start');
            browser.driver.isElementPresent(elementToFind).then(function(isPresent){
                expect(isPresent).toBe(true);
                browser.driver.findElement(elementToFind).then(function(start){
                    start.click().then(function(){
                        ptor = protractor.getInstance();
                        secondClick(eventEmitter, ptor);
                    });
                });
            });
        });
    });
}, 60000);

The following code functions within the angular context:

describe("type in a message ", function(){
        it("should locate and input a random message", function(){
            var elementToFind = by.css('form textarea.limited');
            browser.driver.isElementPresent(elementToFind).then(function(isPresent){
                element(elementToFind).sendKeys(randomSentence).then(function(){
                    console.log("typed in random message");
                    continueOn();
                });
            });
        });
    }, 15000);

Upon exiting the angular part:

browser.driver.wait(function(){
   console.log("polling for a firstName to appear");
   return    browser.driver.isElementPresent(by.name('firstName')).then(function(el){
         return el === true;
       });
     }).
   then(function(){
       somefunctionToExecute()
    });

I hope these examples offer some guidance and assist you in resolving your issue!

Answer β„–5

Gratitude to the responses provided earlier, I have incorporated a simplified and revised approach:

function waitForElement(selector) {
  return browser.wait(function () {
    return browser.isElementPresent(by.css(selector));
  }, 50000);
}

Answer β„–6

Did you consider placing the ng-app attribute within the <html> tag (if possible to do so)? I found that this simple adjustment helped resolve several initialization timing issues.

Answer β„–7

Optimizing wait conditions in Protractor for displaying accurate error messages tied to specific elements upon test failure

const EC = ExpectedConditions;
const targetElement = element(by.xpath(your xpath));

return browser.wait(EC.visibilityOf(targetElement), 9000, 'Element not found').then(() => {
            targetElement.click();
         });

Answer β„–8

It's surprising that no one has mentioned this solution yet. In situations where modal dialogues are used, there may be instances where an element is visible and appears clickable but is actually not responsive due to the modal dialogue being in the foreground. This occurs because Protractor operates faster than Angular, causing it to attempt clicking on the next element before Angular has finished closing the modal.

One possible solution is to use:

public async clickElementBug(elementLocator: Locator) {
const elem = await element(elementLocator);
await browser.wait(
  async function() {
    try {
      await elem.click();
      return true;
    } catch (error) {
      return false;
    }
  },
  this.TIMEOUT_MILLIS,
  'Failed to click element: ' + elem
);

}

Answer β„–9

browser.wait is more than just your average function...

browser.wait may seem like a simple concept at first, but it holds immense power. By passing a function with a condition to wait for, you can control the flow of your automation tasks. For instance, you can wait until a loading animation disappears from the page.

let $animation = $$('.loading');

await browser.wait(
  async () => (await animation.count()) === 0, // This function determines when to stop waiting
  5000, // Timeout in milliseconds
  `Custom message displayed on timeout` 
);

Remember to always use await alongside browser.wait.

You also have access to the ExpectedConditions library, which offers a range of predefined conditions to aid your waiting operations.

The possibilities are endless...

Here are a few examples:

Waiting for the browser to have exactly two tabs open

// Wait for the browser to have exactly two tabs open
await browser.wait(
  async () => {
    let tabCount = await browser.getAllWindowHandles();
    return tabCount.length === 2;
  },
  5000,
  'New window did not open as expected'
);

Ensuring that a loading animation is absent for at least 750ms

// Ensure that the loading animation is gone for at least 750ms
await browser.wait(
  async () => (await this.$$loadAnimations.count()) === 0 && !(await browser.sleep(750)) && (await this.$$loadAnimations.count()) === 0,
  5000,
  `Timeout while waiting`
);

Waiting for any number of elements to be present

// Wait for any number of elements to be present
async waitForElements($elem, timeout = 120000, start = +new Date()) {
    let conditions = [];

    for (let i = 0; i < $elem.length; i++) {
        conditions.push(ExpectedConditions.presenceOf($elem[i]));
    }

    await browser.wait(
        ExpectedConditions.and(...conditions), 
        remainingTimeout(timeout, start), 
        `Wait for all elements to appear`
    );
}

// Usage example

await waitForElements([
  $usernameField, 
  $passwordFiend, 
  $submitButton
])

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

The Javascript code is malfunctioning

After delving into a more complex code structure for the first time, I find myself in a dilemma. My IDE claims it works fine, but jsfiddle disagrees by saying that only the two confirm functions - "confirmUserName();" and "confirmFullName();" are actually ...

Attempting to include an additional choice in a dropdown menu

I have been facing an issue with the code snippet below where it removes all the options in my edit form. However, after removing the options, I am trying to add a default option. Despite my attempts with the given code along with .add and .prepend meth ...

In search of a resolution for the error message "multipart: NextPart: bufio: buffer full" while attempting to upload an image via a fetch post request. Can anyone provide guidance

What steps can be taken to resolve the issue "multipart: NextPart: bufio: buffer full" when using a fetch post request to upload an image? I have a feature on my website that allows users to upload profile pictures. I use a fetch post request for this pur ...

What are some ways to ensure that text can adapt to the size of a

I am looking to create dynamic text that adjusts based on the size of its parent container. As the parent container's size changes, I want the text to automatically adjust accordingly. Specifically, I want the text in a widget to resize when the widg ...

Is it possible to insert a variable into a span or v-tooltip tag?

I am currently using vue 2 along with vuetify 2, and I seem to be encountering an issue when attempting to display data from a table. Whenever I insert curly braces between the v-tooltip tags, it results in a blank page. Below is an example of the code: &l ...

Converting data into a multidimensional array in AngularJS: A comprehensive guide

Struggling to convert a JSON array into a multidimensional array, looking for some guidance. I attempted using _.groupBy in underscore.js, but it's not proving successful with the nested array. If there is any way to convert from the given data [{ ...

Exploring the concept of template inheritance in Vue.js

Is there a way to implement template inheritance similar to Jade’s extends file.jade? I understand that composition can achieve the same result, but for components like the footer and header which are present on most pages except a few (e.g. login page), ...

Obtaining static images from the public directory with getStaticProps in Next.js

Next.js provides a thorough method for accessing images from the /public/ folder, where static assets are stored. This involves using Node's fs module and fetching them within the getStaticProps function. Here is an example: export async function get ...

Discovering the minimum and maximum Node.js versions that my Node.js application can support according to its dependencies

If I have 10 developer dependencies and 10 production dependencies, how can I decide on the minimum and maximum node versions required for a user to download or clone my node application and run it smoothly? How can I automate this process by analyzing all ...

Retrieving Data with AJAX: Submitting Data and Retrieving Response

I need help implementing an AJAX feature for the following process: When a visitor clicks a button, I want to display a spinning/loading image using AJAX. AJAX will then access URL 1 http://www.mywebsite.com/url1.php to retrieve a random code, such a ...

The issue of Angular JQuery Datepicker failing to set the MinDate upon initialization

In my AngularJS project, I am using JQuery UI's Datepicker for the Date From and Date To fields. I have successfully bound the value to the model using a directive, and I have also implemented logic in the OnSelect function to ensure that the Date To ...

Utilizing Node.js and Express alongside EJS, iterating through objects and displaying them in a table

Today I embarked on my journey to learn Node.js and I am currently attempting to iterate through an object and display it in a table format. Within my router file: var obj = JSON.parse(`[{ "Name": "ArrowTower", "Class" ...

Checking the list box and radio button using JavaScript based on their respective IDs

Looking to validate the selection of a listbox and radio button using their respective IDs when a submit action occurs. When testing in the browser, no alert is being displayed. The goal is to trigger the script upon clicking the submit button to verify ...

What is the most efficient way to transmit an HTML document element from a client to a server in Node JS

I am attempting to capture a snapshot of my client-side document object and send it to the Node.js server. However, when I try to convert it into a string using: JSON.stringify(document.documentElement) I encounter an issue where it becomes an empty obje ...

Is there a PostgreSQL Node.js server equivalent to the each() function in SQLite3?

Currently, I am in the process of transitioning my Node.js application's database from SQLite3 to PostgreSQL. Originally, I initialized my SQLite3 database like this: let db = new sqlite3.Database('./dbName.db', (err) => { if (err) { ...

Toggle button in React following a list iteration

Upon receiving data from an API call to Google Books, I want to hide the description paragraphs and implement a toggle button using the "hidden" CSS class from Tailwind CSS. Currently, I am just logging the elements on the "view description" button and uns ...

AngularJS showcasing data in a visually appealing layout

Successfully connected API and displaying data, but now encountering an issue with formatting the data into a table. When using ng-repeat="item in items", if used within a tr tag, only one row is shown. If used within a tbody tag, it repeats the tbody. He ...

Issue with Setting Value in JQuery Select Box

I am in the process of designing a webpage that allows users to edit listings they have created on my website. These listings fall under three main categories, each with its own set of subcategories. To streamline this process, I am implementing AJAX to dy ...

Leverage the Power of JSON Data Manipulation in WordPress with Angular JS and the WordPress JSON

After testing code in this particular post and making some adjustments, I encountered an issue with obtaining a JSON object from the API of my blog created using the WordPress JSON plugin. URL of API from BLOG (NOT FUNCTIONING): URL from W3C example (WO ...

Troubleshooting issues with table-based Bootstrap form validation

Is there a way to implement Bootstrap form validation within a table structure? I've noticed that the validation doesn't work when using the <table> tag. Removing it resolves the issue, but disrupts the table layout. Does anyone have insigh ...