There seems to be an issue with the loop - nightwatch is behaving unexpectedly

I am facing a challenge with this code where I need to iterate through all the links located at the bottom of a webpage. Once clicked, I want to verify that the opened URL is correct. I suspect that the recursive calls are being made too early and I am also struggling to identify which link belongs to a specific URL.

function navigateLinks(browser, total_links) {
    if (total_links <= 0) {
        browser.end();
        return;
    }

    console.log("Number of links: " + total_links);
    console.log('Flag1');

         browser
            .waitForElementVisible('.bottom .socal>span:nth-child(' + total_links + ')', 1000, function () {

            console.log('Flag2');
            browser.execute('scrollIntoView(alignToBottom)')

            .moveToElement('.bottom .socal>span:nth-child(' + total_links + ')', 3, 3)
                .pause(3000)
                .click('.bottom .socal>span:nth-child(' + total_links + ') a', function () {
                    console.log('Flag3');
                    browser.keys(['\uE006'])
                    //  .assert.urlContains('facebook')
                    //.assert.urlEquals('https://www.facebook.com/unitel.ao/?fref=ts')
                            .window_handles(function (result) {
                            console.log('Flag4');
                            browser.assert.equal(result.value.length, 2, 'There should be two windows open.');
                            var handle_1 = result.value[0];
                            var handle_2 = result.value[1];
                            browser.switchWindow(handle_2, function () {
                                browser.closeWindow()
                                    .switchWindow(handle_1, function () {
                                        total_links = total_links - 1;
                                        navigateLinks(browser, total_links);
                                    });
                            });
                         });

                    console.log('Flag5');
                });
            console.log('Flag6');   
        });
}

module.exports = {
    'Social links': function (browser) {
        var total_links;

        browser
            .url('http://m.unitel.ao/fit/')
            .execute(function () {
                    return document.querySelectorAll("ul.navbar-nav>li").length;
                },
                function (tags) {
                    total_links = tags.value;
                    navigateLinks(browser, total_links);

                });

        //  .end();
    }
};

Answer №1

It appears that you've been facing this issue for quite some time now. To make your code more flexible and avoid hardcoding, I suggest using page objects. This will simplify changing CSS in the future.

For instance, a homepage object (home.js) could look like this:

module.exports = {
  url: function() {
    return 'http://m.unitel.ao/fit/';
  },
  commands: [{
    getUrl: function(n) {
      if (n === 3) {
        return 'youtube.com/user/tvUNITEL';
      }
      if (n === 1) {
        return 'facebook.com/unitel.ao/?fref=ts';
      }
      if (n === 2) {
        return 'instagram.com/unitelangola/';
      }
      if (n === 4) {
        return 'plus.google.com/110849312028181626033/posts';
      }
    }
  }],
  elements: {
    facebook: {
      selector: '.bottom .socal>span:nth-child(1)',
    },
    instagram: {
      selector: '.bottom .socal>span:nth-child(2)'
    },
    youtube: {
      selector: '.bottom .socal>span:nth-child(3)'
    },
    googleplus: {
      selector: '.bottom .socal>span:nth-child(4)'
    }
  }
};

You can structure your test like this:

module.exports = {
  'Social links': function(browser) {
    const homePage = browser.page.home();
    var j = 0;
    for (var i in homePage.elements) {
      homePage
        .navigate()
        .waitForElementVisible(homePage.elements[i].selector, 5000, false,
          function() {
            browser.pause(3000);
          })
        .click(homePage.elements[i].selector, function() {
          browser
            .pause(2000)
            .window_handles(function(result) {
              url = homePage.getUrl(j + 1);
              var home = result.value[0];
              var handle = result.value[1];
              browser
                .switchWindow(handle)
                .verify.urlContains(url)
                .closeWindow()
                .switchWindow(home);
              j += 1;
            });
        })
    }
  }
};

If you're unsure how to create a page-object, refer to the documentation here.

In the Nightwatch.js config file:
Nightwatch.js:

  "src_folders" : ["tests"],
  "output_folder" : "reports",
  "custom_commands_path" : "",
  "custom_assertions_path" : "",
  "page_objects_path" : "./lib/pages", /* don't forget to add the path,e.g: './lib/pages', */
  "globals_path" : "",

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

Is it possible to consolidate a Next.js Application into a singular JavaScript file for seamless incorporation into an external HTML webpage?

Currently, I'm in the process of integrating a Next.js application into an existing HTML page. My goal is to display Next.js components on this HTML page by linking a JavaScript file (created from the Next.js application) within a <script tag. Howe ...

Upgrade to the latest version of MaterialUI - V4

After attempting to upgrade materialUI/core from version 3.9.3 to 4.4.1 and materialUI/icons from version 3.0.2 to 4.4.1, I encountered the following error: Error: TypeError: styles_1.createGenerateClassName is not a function I am currently importing crea ...

What is the best way to iterate through a multi-dimensional array and only load a single section at a time? - Using JavaScript

I have a massive multidimensional JavaScript array object that stores coordinates of numerous earthquakes. Here is an example: var earthquakeArray = [ [ 0 : { "place": "home", "lat": "30", ...

What is the best way to handle a promise passed as parameters to a Subject in RxJS?

When passing a Promise to Subject as a parameter: const work = new Subject<{ id: number; dialogRef: Promise<typeof Dialog> }>(); I aim to utilize the instance inside the promise at a later stage: ... exhaustMap(({ id, dialogRef }) => http ...

Having an issue with my application crashing and showing the message "[nodemon] app crashed - waiting for file changes before starting...". Does anyone know how to

mainapp.js const PORT = 3000 const express = require('express') const axios = require('axios') const cheerio = require('cheerio') const app = express() app.listen(PORT, ()=>console.log('Server running on port ${PORT} ...

Python Selenium No Identification Needed

How can I input the postcode, e.g. "3000", and click submit using Selenium (Python) when searching by name or ID is not an option? Below is the HTML code: <div class="container-fluid" id="basicpage"> <div class="con ...

Tips on using CSS to hide elements on a webpage with display:none

<div class="span9"> <span class="disabled">&lt;&lt; previous</span><span class="current numbers">1</span> <span class="numbers"><a href="/index/page:2">2</a></span> <span class="num ...

A step-by-step guide on masking (proxying) a WebSocket port

Within my server-side rendering React app, I have set up a proxy for all HTTP calls to a different port. Take a look at the code snippet below for the HTTP proxy configuration. import proxy from "express-http-proxy"; const app = express(); const bodyParse ...

Using jQuery to retrieve the TD value

I'm attempting to retrieve the TD value using the Value attribute.... Let's say I have the following HTML markup: <td nowrap="nowrap" value="FO2180TL" class="colPadding" id="salesOrderNumber1">bla bla </td> So, I tried this- v ...

Whenever I try to launch Appium on my Android device, I keep encountering an error

While launching Appium on Android, an error is encountered: Failed to establish a new remote session. Please refer to the server log for more information. The original error states that an unknown server-side error occurred while executing the command. ...

Trouble arises when adding HTML elements to a Content Editable Div. Any text inputted after programmatically inserting HTML content will merge with the last HTML tag instead

https://i.sstatic.net/bKIVm.pngI am currently working on a project that involves creating message templates within an app. Users have the ability to add placeholders for fields like names to these templates by clicking a button. They can also remove these ...

How do I extract text from BeautifulSoup without using class identifiers?

When trying to scrape the website, I encountered a situation where the text I need does not have a specific class name or id that distinguishes it within the HTML structure. The selector path used with soup.select is not effective for extracting this data ...

Unable to get the onchange event to trigger for a span element

Is there a way to trigger the onchange event on a span element that doesn't seem to be working? Here is the code I am using: Attempt 1 document.getElementById(seconds).addEventListener('change', (event: MutationEvent & { path: any }) =& ...

Importing a substantial number of records from an XML file into an HTML table

Currently, I am working on a project where I am reading records from an XML file and dynamically displaying them in an HTML table using JavaScript's push method. Everything works smoothly when the number of records is below 1000. However, when the num ...

What is the process for navigating to the next page using Selenium?

Currently, I am delving into Selenium with Python, attempting to extract data from multiple pages. However, I've hit a roadblock in the process. Here is the specific element I need to interact with: https://i.sstatic.net/iGGgv.png The code snippet I ...

The JavaScript function's argument is determined by the value submitted in EJS

I am currently in the process of developing an express application. One of the key features involves a drop-down menu where the selected value is sent to users.js to trigger a MongoDB query. The results of this query are then returned to the EJS template a ...

Executing an external Python script within a Vue application's terminal locally

Hello, I am new to using Vue.js and Firebase. Currently, I am working on creating a user interface for a network intrusion detection system with Vue.js. I have developed a Python script that allows me to send the terminal output to Firebase. Right now, I a ...

Utilizing a React hook to render and map elements in a function

Can the hook return function be assigned to a render map in React? In this example, we have the socialAuthMethodsMap map with the onClick parameter. I tried to assign the signInWithApple function from the useFirebaseAuth hook, but it violates React's ...

Ways to extract all elements with multiple classes in selenium

Here is how I access the website: from selenium import webdriver url = '...' driver = webdriver.Firefox() driver.get(url) Now, my objective is to extract all elements that have specific classes and store them in a list. <li class=foo foo-defa ...

Verify if a request attribute has been established using jQuery

How can I determine if an attribute is present in a request object? I have specific error scenarios where an error message needs to be sent to the client side: Here is the servlet code snippet: request.setAttribute("error", "The following term was not fo ...