Nightwatch experiences out-of-sequence execution of commands in a for loop

I've recently started exploring unit testing and am currently working on a Nightwatch script that navigates through the body content of a webpage, clicks on each link, and checks if it's broken.

My goal is to create a for loop that goes through every tag in the body content, counts the number of 'a' tags within them, and then clicks on each link. However, I'm facing an issue where the browser.execute command inside the for loop seems to be executing out of order.

Below is my code snippet with some console.log statements added to track what's happening:

'Click Links' : function(browser) {
browser
  //Count all non-link tags (p/div) in the content
  .useCss()
  .execute(function() {
    return document.querySelectorAll("div.field-item.even *:not(a)").length;
  },
  function(tags){
    tag_total = tags.value;

    //Loop through every tag in content and check each contained a tag
    for (var x = 1; x < tag_total+1; x++) {
      console.log("x val before execute: " + x);
      browser.execute(function() {
        return document.querySelectorAll("div.field-item.even *:not(a):nth-child(" + x + ") a").length;
      },
      function(links){
        console.log("x val at start of execute: " + x);
        a_total = links.value;

        for (var y = 1; y < a_total+1; y++) {
          browser.click("div.field-item.even *:not(a):nth-child(" + x + ") a:nth-child(" + y + ")");
          browser.pause(1000);

          //Check for on-site broken links
          browser.execute(function() {
            return document.querySelector("meta[content='Error Document']");
          }, 
          //Notify about broken link
          function(result){
            if (result.value != null) {
              browser.url(function(result) {
                console.log("BROKEN LINK: " + result.value);
              });
            }
          });

          //Navigate back to previous page
          browser.url(process.argv[2]);
          browser.pause(1000);
        }
        console.log("x val at end of execute: " + x);
      });
    console.log("x val at end of for loop: " + x);
    }
  })

.end()
}

The output shows a discrepancy in the execution sequence:

 x val before execute: 1
 x val at end of for loop: 1
 x val before execute: 2
 x val at end of for loop: 2
 x val at start of execute: 3
 x val at end of execute: 3
 ERROR: Unable to locate element: "div.field-item.even *:not(a):nth-child(3) a:nth-child(1)" using: css selector

It appears that the for loop is processing ahead and skipping the entire browser.execute section. Once the loop completes, the browser.execute part runs with an incorrect value of x. This leads to the question of why the browser.execute command disrupts the order of execution and whether there's a fix to maintain the intended order.

Answer №1

Although this topic is not related to Nightwatch, it pertains to Javascript.

When a function is called within a loop, the variable used in that function is saved by reference. This means that the variable retains its value across all function calls.

Let's illustrate this with a simple example:

var myFuncs = [];
for (var i = 0; i < 3; i += 1) {
  myFuncs.push(function () {
    console.log('i is', i);
  });
}

myFuncs[0](); // i is 3
myFuncs[1](); // i is 3
myFuncs[2](); // i is 3

The reason for this behavior is that i is stored as a reference in the function. Therefore, when i increments in the next iteration, the reference remains the same while the value changes.

A solution to this issue would be to move the function outside of the loop:

function log (i) {
  return function () {
    console.log(i);
  }
}

var myFuncs = [];
for (var i = 0; i < 3; i += 1) {
  myFuncs.push(log(i));
}

myFuncs[0](); // i is 0
myFuncs[1](); // i is 1
myFuncs[2](); // i is 2

For further exploration of this concept, you can refer to this similar SO answer (which presents a similar example - ironically).

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

Moving the Promise.all feature from AngularJs to VueJs

I'm currently facing a challenge with moving a function from AngularJs to VueJs. I would really appreciate any help or suggestions you may have! items = { one: {...details here...}, two: {}, } In AngularJs: var promises = []; var deferred = $ ...

Check if a user is currently on the identical URL using PHP and JavaScript

In my Laravel and AngularJS project, I have a functionality where users can view and edit a report. I'm looking to add a feature that will prevent multiple users from editing the report at the same time - essentially locking it while one user is makin ...

What are the steps for including and excluding components in Parallax JS?

When working with Parallax JS: I am trying to modify the components within the <li> tags of my menu, but I am unsure how to do so without restarting the plugin. I cannot seem to find the destroy command. Currently, I am using the JQuery version of ...

Verifying the status following a promise execution in the initial promise function

Below is the function I am currently working with: startGame = () => { this.buildDeck() .then(this.shuffleDeck) .then(this.dealToPlayer) .then(setTimeout(this.dealToPlayer, 2000)) .then(setTimeout(this.dealToDealer, 4000)) } In ...

How can I change an array from OData into JSON format?

I've been working on finding a solution to properly handle an OData response in JavaScript. The issue I am facing is that the response comes back formatted as an array rather than JSON, preventing me from using JSON.parse(mydata) with the current data ...

Turn off specific default features within Sails.js

Currently, I am working on a backend REST API application using Sails.js framework version 0.10. The main focus of this application will be strictly on REST functionality, with authentication utilizing oAuth bearer tokens. All responses will be formatted i ...

What is the best way to render geoJSON as a mesh instead of a line in three.js, and apply a color fill to it?

Currently working on a three.js globe project that involves adding data layers using geoJSON. The initial layer, representing countries, is displayed as lines thanks to ThreeGeoJSON. https://i.sstatic.net/nuBkR.png However, I am aiming to go beyond just ...

Error message from BitBucket pipeline indicates that the npm command was not found

Upon deploying code to my server via the Bit Bucket scp pipeline, I encountered an issue with another pipeline meant to install node modules and start the node server. The pipeline returned a failed status and displayed the following error: ./server-run.s ...

Creating dynamic email content with Node.js using SendGrid templating

How can I properly format SendGrid's content using Node.js? I'm currently working on sending emails from a contact form within an application using SendGrid. I have a Google Cloud Function set up that I call via an HTTP post request. Although I ...

Search MongoDB to find, update, and validate any empty fields in the body

I'm currently working on updating a user's profile information, but I'm facing a problem with checking for empty values before proceeding with the update. The code I've written so far is not displaying error messages and is preventing m ...

Creating an animated time-based scrollable bar chart in javascript

As someone who is new to JavaScript and charting, I am seeking assistance with a specific task. Despite browsing various JavaScript charting libraries and examples, none seem to address my issue: My goal is to generate dynamic stacked bar charts, as depic ...

Learn the process of retrieving a file from server.js and showcasing it on an HTML page

I am currently developing a YouTube video downloader using express, HTML, and JavaScript, with plans to transition to Vue.js in the future. Here is a snippet of my code: Index.html <!DOCTYPE html> <html lang="en"> <head> & ...

The functionality of ng-click and ng-submit seems to be malfunctioning

I am currently facing an issue with my Angular application and PhoneGap. I have a login form along with a login controller set up, but for some reason, the ng-submit function is not working as expected. When the submit button calls the formConnexion() func ...

Using jQuery to create a flawless animation

I am currently working on an animation project, and I have shared my progress on jsfiddle. Below is the code snippet I have utilized: /* JavaScript: */ var app = function () { var self = this; var allBoxes = $('.box&apos ...

Ways to leverage the power of Reactivity APIs in Vue.js

In my Vue application, I am trying to create a Drop Down Menu by using a variable called "showDropDown". The idea is to use a v-if directive to check if the value of showDropDown is true, and then display the menu accordingly. Additionally, I want to imp ...

Issues encountered while scraping Instagram's web content using Selenium with Python

I am facing an issue with scraping images from an Instagram profile. Even after scrolling to the bottom of the page and extracting all "a" tags, I only end up getting the last 30 image links. It seems like the driver is unable to view the full content of ...

Struggling to get Angular to properly sanitize inputs using ng-bind-html

I've been struggling to figure out the issue in my code for an entire day with no success. At this point, I'm reaching out for help. My problem arises when trying to utilize ng-bind-html-unsafe within a template. As a newcomer to Angular, it&apos ...

Determining if a value is an Object Literal in JavaScript: Tips for judging

As someone with limited experience in object type judgment, I find myself unsure of how to determine if a value is an Object Literal in JavaScript. Despite my efforts to search online for answers, I have not been successful. Any guidance or ideas on how to ...

Efficient Method for Parameterizing Data in TestNG

While working on developing a framework with Selenium and TestNG, I am currently focusing on implementing Data Parameterization. However, I am facing confusion regarding the most effective way to implement this feature. So far, I have considered the follow ...

Discover the location by determining the distance from established points

Before I get redirected to this particular question, let me clarify that while I've come across it, I am unable to comprehend its content (I wish I could). What I'm really seeking is a straightforward method (bearing in mind my limited math skill ...