The versatility of Protractor's variable scope when working with promises

Insight into Angular App Testing

As I delved into testing my Angular app using ng-repeat to create a table, a user brought to my attention the presence of duplicate entries. Eager to address this issue, I visually confirmed it and proceeded to craft a Protractor test.

The Inquiry

Dilemma with Variable Scoping

During the test creation process, I stumbled upon peculiar behavior in the scope that seemed unfamiliar to me.

It seemed logical that the for-loop on line 61 would have access to linkStorage (line 38) as it resides in a higher scope. The console indicated successful addition of objects via the for-loop within the promise at line 47.

However, when attempting to perform the confirmation loop outside the promise, such as before the expect statement...

...linkStorage appeared as an empty object.

No nested key-value pairs could be identified upon iterating over the object; it was undeniably void of any data.

Pondering the Question (in short)

What is causing the linkStorage object to populate inside the then statement, but not before the expectation?

Answer №1

The Power of Asynchronous Programming

Asynchronousity plays a crucial role in the success of the first example. The non-blocking nature of the .getAttribute method allows the code to keep executing while it fetches data, leading to the console loop being reached before the object is fully populated.

If you allow some time for the asynchronous code to do its job, say one second:

You'll see that linkStorage now contains the necessary information.

A Comprehensive Approach

To ensure precise timing and execution of code, chain multiple promises together as demonstrated below:

it('should not have duplicates within the match grid', function() {
    // Already on job A, with match grid shown.
    var duplicate = false;
    var linkStorage = {};

    // Save unique links
    var uniqueUserLinks = element.all(by.css('div.row table tbody tr td a'));
    
    // get an array of href attributes
    uniqueUserLinks.getAttribute('href')
      .then(function(hrefs) {
        // add the links to the linkStorage object
        for (var i = 0; i < hrefs.length; i++) {
          // if the link is already there
          if( linkStorage[ hrefs[i] ] ) {
            // update its counter
            linkStorage[hrefs[i]] += 1
            duplicate = true;
            // there's already one duplicate, which will fail the test
            break;
          } else {
            // create a link and start a counter
            linkStorage[hrefs[i]] = 1;
          }
        };
      }).then(function() {
        // confirm links have been added to storage
        for(var link in linkStorage) {
          console.log('link:', link );
          console.log('number:', linkStorage[link] );
        }
      }).then(function() {
         expect(duplicate).toBe(false);
     });
  });

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

Selenium in C#: Timeout issue with SendKeys and Error thrown by JS Executor

Attempting to insert the large amount of data into the "Textarea1" control, I have tried two different methods. The first method successfully inserts the data but occasionally throws a timeout error, while the second method results in a JavaScript error. A ...

The DOM assigned a new source to an image

Currently, I am working on a project that involves both jquery and PHP. In this project, users are able to upload images which are then displayed in blocks. The uploading functionality is already working, but I am facing an issue with setting the image sou ...

AngularJS - the element of surprise in execution sequence

Encountering a puzzling issue that exclusively affects Internet Explorer (any version) and not Chrome. An "items" array is stored within the "doc" object. Users have the capability to edit items, which essentially deletes the item but retains its content ...

I'm having trouble getting my CSS opacity to smoothly transition back to its original state of .5 using setTimeout(). What could be

I recently started learning JS, Jquery, and CSS. My goal is to create a Simon Says style game. However, when I attempt to animate the computer to automatically light up the correct square, I faced some challenges. To address this issue, I decided to star ...

Using JavaScript in Internet Explorer 11, you can open multiple tabs without the UrlReferrer being null

I have tried numerous solutions to open multiple tabs in IE 11, but none of them seem to work for me. In Chrome, everything works smoothly with a simple window.open(url) command. When I try to open tabs using an iterative JavaScript code snippet, only one ...

JavaScript callback closure and the mysterious undefined variable

Today, I encountered something new. I was trying to use phantomjs in node and was setting up the phantom npm module npm link. The issue that arose was regarding how to access "document.title". Please refer to the provided example code on their website for ...

How can I access the marker's on-screen location in react-native-maps?

Looking to create a unique custom tooltip with a semi-transparent background that can overlay a map. The process involves drawing the MapView first, then upon pressing a marker on top of the MapView, an overlay with a background color of "#00000033" is dra ...

The functionality of the `next-auth` signOut button click does not seem to accept a variable as input, although

The Nav.jsx component code provided is working as intended. In this implementation, clicking the 'Sign Out' button will redirect the application to http://localhost:3000. 'use client' import { signOut } from 'next-auth/react&apos ...

Issue: The `libsass` component could not be located

When attempting to run an Express app using node-sass-middleware on Ubuntu, I encountered this error: 0 info it worked if it ends with ok 1 verbose cli [ '/home/mohamed/.nvm/versions/node/v0.12.7/bin/node', 1 verbose cli '/home/mohamed/.n ...

How can I improve my skills in creating efficient Angular routers?

In my Ionic project, I am dealing with an AngularJS routes file that contains a large number of routes, approximately a hundred. The structure is similar to the one provided below. (function() { 'use strict'; angular.module('applicatio ...

End-to-end testing with Protractor using multiple capabilities: Running Internet Explorer at the same time

Currently, I have Protractor 5 set up in the configuration file with multiCapabilities for testing my AngularJS 1.6 application. The idea is to have two instances of the same browser running simultaneously, simulating interactions between two users. While ...

Issue with collapsed navbar button functionality in Bootstrap version 5.1.3

Issue with Bootstrap 5 Navbar Collapse Functionality The navbar collapse button is not working on my PC. The button appears but when clicked, the navbar does not show up. Surprisingly, when I test the code on Codeply (without linking to Bootstrap 5 and ot ...

Keep the final item in an array that shares the same attribute

I am working with an array const obj=[{fullCart: 5, halfCart: 4, smu: 3, stowage: 5, index: "FC-093"}, {fullCart: 5, halfCart: 4, smu: 8, stowage: 5, index: "FC-093"}, {fullCart: 5, halfCart: 4, smu: 0, stowage: 5, index: "FC-093 ...

The function applyMiddleware in React Redux is not working correctly

After thoroughly reviewing my code, I couldn't find any flaws, yet I received this error message: Uncaught TypeError: (0 , _reactRedux.applyMiddleware) is not a function import { applyMiddleware, createStore } from 'react-redux' impor ...

Empty req.params in nested ExpressJS routers

I have a unique routing system that relies on the directory structure of my 'api' folder to automatically configure routes. However, I encountered an issue where the req.params object is undefined in the controller when using a folder name as a r ...

Checking to see if an object is null using Javascript/AngularJS

Below is the code snippet: function getBestBlock(size){ var bestBlock = {}; var blockEnteredTest = true; for(var i = 0; i < $scope.blocks.length; i++) { if($scope.blocks[i].state == "Free") { i ...

Issue with nodes/JavaScript: Array objects not being properly updated

Being new to Javascript and Node.js, I attempted to code a simple program that generates an array of planes with varying index values. I started by defining a plane object with default values and tried to update the index value in a for loop. However, whe ...

When attempting to download a file in AngularJS from an API REST, the file ends up becoming corrupted

I have created an Excel report using the REST API and sent it to the front-end (AngularJS). When I directly access the URL from the browser, everything works fine. However, when I try to download it from AngularJS, the file is downloaded but then cannot be ...

Having trouble figuring out how to update a list using ajax in Yii

I need to modify a JavaScript function that filters the content of a list. The current code looks like this: var id = $(this).data('id'); $.fn.yiiListView.update('contests-list', { data: {category: 2} }); I couldn't find any ...

Executing ForceAtlas2 algorithm from a predetermined starting point within Sigma.js

I need assistance with rendering a complex network using the React-Sigma wrapper. The base structure of this network consists of numerous nodes of degree one and some nodes with high degrees. I have prepared my graph data with x and y coordinates that repr ...