Nightwatch.js - Techniques for waiting until an AJAX request is finished

Currently, I am relying on nightwatchJS for browser automation. A common issue I encounter is that much of the content on my webpage gets updated via ajax calls. To ensure accurate testing, I need a way to pause my testing until the ajax call returns results. Unfortunately, I have not been able to find any built-in API in nightwatch or selenium to achieve this.

I experimented with waitForElementVisible, but I am concerned that it may not be sufficient. What happens if the ajax call fails to return any data?

Has anyone else faced and resolved this challenge before?

Answer №1

If you are familiar with ajax paths, here is a solution that can be implemented by attaching an 'ajaxComplete' event to the client and matching the executed request path:

client
    .timeoutsAsyncScript(15000) // set async exec timeout
    .click('.btn-submit') // initiate ajax form submit
    .executeAsync(
        function(targetUrl, done){
            var nightwatchAjaxCallback = function(ajaxUrl) {
                if(ajaxUrl.indexOf(targetUrl) === 0) { // notify script when URL matches
                    done(true);
                }
            };

            if(!window.nightwatchAjaxInited) { // ensure ajaxComplete is attached only once

                window.nightwatchAjaxInited = true;

                $(document).ajaxComplete(function(e, res, req) {
                    nightwatchAjaxCallback(req.url);
                });
            }
        },
        ['/ajaxpath'], // expected xhr request path
        function(status){
            // code to execute once ajax is completed
            client.verify.containsText('.entry', 'lorem ipsup...') // verify post creation
        }
    );

A command called 'ajaxWait' has been created based on the above code:

exports.command = function(targetUrl, action, callback) {

    this.timeoutsAsyncScript(15000);

    action();

    this.executeAsync(function(targetUrl, done){

        var nightwatchAjaxCallback = function(ajaxUrl) {
            if(ajaxUrl.indexOf(targetUrl) === 0) {
                done(true);
            }
        };

        if(!window.nightwatchAjaxInited) {

            window.nightwatchAjaxInited = true;

            $(document).ajaxComplete(function(e, res, req) {
                nightwatchAjaxCallback(req.url);
            });
        }

    }, [targetUrl], function(status){

        callback();
    });
};

And the usage of this command should resemble the following:

client.ajaxWait('/ajaxpath', function(){
    // initiate ajax form submission
    client.click('.btn-submit')
}, function(){
    // code to execute once ajax is completed
    client.verify.containsText('.entry', 'lorem ipsup...') // verify post creation
})

Answer №2

Looking for a unique custom command solution? Check out our special commands at https://github.com/mobify/nightwatch-commands

We have put in the effort to make our commands adaptable to any project, removing the need for adaptive.js specific requirements.

To integrate these commands into your project, simply include nightwatch-commands: 1.6.0 in your package.json and add references to the custom commands in your settings.json file:

"custom_commands_path": "./node_modules/nightwatch-commands/commands",
"custom_assertions_path": "./node_modules/nightwatch-commands/assertions",

Answer №3

I am encountering some similar issues and have identified two potential solutions:

1) Consider inserting a pause statement before interacting with elements following an ajax request. Oftentimes, test failures occur because the ajax request has not finished loading completely.

client.pause(5000); could resolve this issue.

2) It appears that adaptive.js offers a waitForAjax feature for nightwatchJS. While it is a closed source code, I am unable to provide further details on its functionality.

3) Utilize the --verbose option to gain insight into the operations taking place. The verbose mode can reveal any unhandled error messages, aiding in pinpointing and resolving minor but tricky problems.

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 can I utilize a service for monitoring user data and ensuring that $watch() functions properly?

I'm a beginner when it comes to AngularJS and currently working on building a website that has a navigation bar dependent on the user's login status. My approach involves using a state model design with the Nav controller as the parent state for ...

Transform the date format from yyyy-MM-dd'T'HH:mm:ss.SSS'Z' to dd-mmm-yyyy with the help of JavaScript

I am looking to convert date format from yyyy-MM-dd'T'HH:mm:ss.SSS'Z' to dd-mmm-yyyy when the dates are retrieved from a JSON object. Currently, I am utilizing the ng-csv plugin to download this JSON data, which is working properly. How ...

Issues with the functioning of the HTTP POST method in Ionic on the server

For the past 2 days, I have been facing a major issue with my app. Previously, the app worked fine everywhere using the same code. However, now when I run the ionic serve command and make a POST request, I encounter the following error: OPTIONS https://w ...

$q.all - successfully resolving some HTTP requests while encountering errors on others

I encountered a coding scenario like this angular.forEach(config.tvshows.shows, function(show) { promises.push($http.get('http://epguides.frecar.no/show/' + show.replace(/\s|\./g, '') + '/next/')); }); re ...

Error: Trying to access properties of an undefined object (specifically 'promise.data.map')

Currently, I am in the process of writing unit tests for a project built with Angular version 1.2. For my controller tests, I have set up a mockService that returns a deferred promise. One of the service methods looks like this: function getItems() { ...

A guide on updating object values within an array using map in React

Is there a method to calculate the total sum of specific values from an array of objects? Example array: const exampleArray = [ {item_id: 1, quantity: "3"}, {item_id: 2, quantity: "5"}, {item_id: 3, quantity: "2"} ] In this case, I want to add up the qua ...

Running Selenium UI tests in Azure pipelines for C# can be a breeze. However, be prepared for any challenges that may come your way, such as the dreaded OpenQA.Selenium

I have been attempting to run Selenium UI tests through a VSTS release pipeline using Visual Studio Test tasks from VSTS release. While my tests are being recognized, they are not executing and the same error is persisting across all tests. Despite tryin ...

"The interplay of Vue components: exploring the relationships, lifecycle hooks

Brand new to utilizing Vue.js. I am exploring the concept of having a single parent component and two child components that need to communicate asynchronously through Vue's event bus system. This involves using a dummy Vue object as a shared container ...

What is the method for rotating a map using JavaScript?

My map built with Leaflet displays a route and a moving car marker. Now, I am looking to implement a feature where the map rotates based on the direction of the car. I have access to both the current coordinates of the car and the target coordinates. ...

Line of cubes - tap on a single cube and the others gracefully slide away from view

I am working on a project where I need to create a row of blocks. The goal is for the blocks to slide off the screen when one is clicked, leaving the clicked block in the first position. For instance: https://i.sstatic.net/IB5LI.jpg I attempted using jQ ...

Issue with GTM: The use of this language feature is restricted to ECMASCRIPT_2015 mode or higher: constant declaration

I'm having trouble extracting UTMs and transferring them to specific fields through my script, but it seems like the script isn't functioning properly on GTM. (Interestingly, the script does work when directly added to webflow custom code) var ...

Adding an HTML tag attribute to a Bootstrap 5 popover using the setAttribute() method: A Step-by

Trying to include HTML tags in a popover setAttribute() function within Bootstrap 5, but the tags are displayed as content rather than being applied as attributes. <button type="button" class="btn btn-secondary mx-2" data-bs-containe ...

Is the Material UI Checkbox toggled on or off?

How can I determine the status of a Metrial UI Checkbox (React Material UI Checkbox component) using Webdriver or a similar browser controller? What is the recommended approach for this specific task? Adding an event listener and an on/off attribute migh ...

Output of ngResource compilation

Is there a way to retrieve a single result from my array $scope.trailers? I am encountering an issue where accessing the first index using $scope.trailers[0] returns undefined. The API call is made using ngResource. function getTrailers(pageNo){ ...

Is there a way for me to identify a click within a region where a jQuery plugin is already actively monitoring clicks?

I have successfully implemented the jQuery Bar Rating Plugin on my website. The plugin works perfectly, allowing users to turn a select list into clickable images. However, I am facing a challenge in revealing a hidden field on the page when a user selects ...

saving information from a GET call into an array

In my current project, I am facing an issue with storing tweet IDs for later use. Here is the code snippet I am using: let twit = require('twit'); let config = require('./config.js'); const T = new twit(config); let retweetIDs = []; ...

Filter and return only specific sections of the matched object

How can I selectively return only a specific part of the matched object while using the filter method on a list? For example: let comments = [{ "postId": 6, "status": "ACTIVE", "id": 28, "name": "quo voluptates voluptas nisi veritatis d ...

Improprove jQuery code to eliminate redundancy

Is there a better way to improve the appearance of this code? Here is a condensed snippet of the HTML: <div id="template" style="display:none;"> <div style="position:relative;"> <fieldset> <img class="sm_kont" ...

Using Vue and vue-multiselect to create interactive options based on the selected language

I'm currently developing a Vue website with multilingual support. The chosen language is stored in a Vuex store and accessed through the computed property lang, like so: lang(){ return this.$store.state.lang } I use this lang property in v-if cond ...

Is there a way to replicate numerous random clicks on a react web application using selenium?

I am currently working on creating a Selenium script that can simulate random clicks within a web application, similar to the clicker function used by gremlinsjs. Is it possible to achieve this using JavaScript? ...