Using a while loop to chain promises in webdriver.io

I am trying to capture a full webpage screenshot by taking tiles of the viewport size. I have almost completed this task, but I am relatively new to promises and need guidance on the correct approach.

Below is my code. The issue I am facing is that the call to client.execute(...) doesn't wait for itself between loop iterations. Additionally, the final 'end' statement does not wait for the previous 'then', which is why it's currently commented out.

...
var client = webdriverio.remote(options);
...
client    
  ...
  .then(function() {

    var yTile = 0;
    var heightCaptured = 0;

    while(heightCaptured < documentSize.height) {
      var tileFile  = 'screenshot-' + yTile + '.png';

      client
      .execute(function(heightCaptured) {
        window.scrollTo(0, heightCaptured);
      }, heightCaptured)
      .then(function() {
        console.log('captured: ' + tileFile);
        client.saveScreenshot('./' + tileFile);

        return client;
      });

      heightCaptured += viewportSize.height;
      yTile++;
    }

  })
  //.client.end()
  ;

Could someone provide me with the correct way to utilize promises in this scenario?

Thank you.

Answer №1

To efficiently chain an indeterminate number of async operations, avoid using a while loop as it will run to completion immediately. Instead, create an internal function called next() that returns a promise. Call this function repeatedly, chaining each call to the previous one until all async operations are complete. Decide within the loop whether to continue chaining by returning next() inside a prior .then() handler or end the chain by returning a regular value.

...
var client = webdriverio.remote(options);
...
client
    ...
    .then(function () {
        var yTile = 0;
        var heightCaptured = 0;

        function next() {
            if (heightCaptured < documentSize.height) {
                var tileFile = 'screenshot-' + yTile + '.png';

                // return promise to chain automatically
                return client.execute(function (heightCaptured) {
                    window.scrollTo(0, heightCaptured);
                }, heightCaptured).then(function () {
                    console.log('captured: ' + tileFile);

                    heightCaptured += viewportSize.height;
                    yTile++;

                    // chain promises properly
                    return client.saveScreenshot('./' + tileFile).then(next);
                });

            } else {
                // End the promise chain
                return client;
            }
        }

        return next();
    }).then(function () {
        // done here
    }, function (err) {
        // error here
    });

When inside a .then() handler, returning a promise chains it to the previous promise. Returning a value ends the chain there. In this example, returning a promise from next() allows for sequential chaining until a regular value is returned to end the chain.

Hence, calling return next(); repeatedly from within the .then() handler links all screenshots in a sequential order until reaching the final value that signals the end of the chain.

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

Can Redis be used with Promises in Node.js?

It appears that unlike other data repositories I work with, I am unable to utilize the following approach in Redis: export class CollectPromises { private cachePromises: Array<Promise<any>> = []; public addPromise(promise: Pr ...

Calculating the number of rows in a dynamic jQuery table

I have a table structured like this: <div class="row"> <input type="button" id="btnAddGatePass" value="Add Gate Pass Requester" /> <div class="table-responsive"> <table id="gatePass" class="table table-striped table-ho ...

Facing difficulties in initiating Selenium with PhantomJS/GhostDriver as child processes

I am currently working on a Node script that involves using the child_process module in order to run a Selenium server with PhantomJS's GhostDriver. I have imported the module: Child = require "child_process" This is how I am attempting to start the ...

What is the method for a Greasemonkey script to divide a link into three interconnected links?

My goal is to use Greasemonkey to link Redmine issue numbers found in cgit commit messages to their respective issues or projects. The cgit commit message HTML source looks like this: <a href='/editingmodule/commit/?id=49e4a33e0f8b306ded5'&g ...

Optimizing CSS for printing by eliminating unnecessary white space with media queries

Appreciate your assistance! I'm currently working on a solution to print a specific div using CSS Media queries. When the user clicks on print, I want to hide all other elements except for the body div they chose. However, I'm facing an issue whe ...

hitting the value of the text input

Is there a way to strike through only the first word in an input box of type text, without editing the html? I've tried using css text-decoration: line-through; but it's striking both words. Any suggestions on how to achieve this using javascript ...

Issue with Click event not working on dynamically added button in Angular 8

My goal is to dynamically add and remove product images when a user clicks the add or delete button on the screen. However, I am encountering an issue where the function is not being called when dynamically injecting HTML and binding the click event. Below ...

Errors in Selenium Webdriver - troubleshooting the issues

As I delve into the world of test automation, I decided to try my hand at writing a script using Selenium Webdriver. To my dismay, upon running the script, I encountered a barrage of errors that have left me scratching my head in confusion. Despite metic ...

When Glue is not executed from the Stepdef in Cucumber, but the @Before setup() method is executed

Working on a cucumber maven project, the setup includes: Feature: Smoke Test for Home Scenario: positive scenario Given Open "JTMS_PORTAL" StepDef File : package jtms.stepdef; import cucumber.api.java.Before; import cucumber.api.j ...

Tips for repeatedly clicking a button over 50 times using Protractor

Is it possible to click the same button more than 50 times using a loop statement in Protractor? And will Protractor allow this action? Below is my locator : var nudge= element(by.xpath("//a[@class='isd-flat-icons fi-down']")); nudge.click(); ...

Track the loading time of a webpage and the time it takes to render all subelements of

For my project, I need to track page load times for each individual visitor. My idea is to embed a JavaScript snippet into the page in order to achieve this goal. However, the task is more complex than I anticipated because I also need to measure the respo ...

How can we have a div stay at the top of the screen when scrolling down, but return to its original position when scrolling back up?

By utilizing this code, a div with position: absolute (top: 46px) on a page will become fixed to the top of the page (top: 0px) once the user scrolls to a certain point (the distance from the div to the top of the page). $(window).scroll(function (e) { ...

Transform JavaScript into Native Code using V8 Compiler

Can the amazing capabilities of Google's V8 Engine truly transform JavaScript into Native Code, store it as a binary file, and run it seamlessly within my software environment, across all machines? ...

Retrieve data from each URL listed in a JSON array using React

My json file structure was as follows: [ { "name": "google", "route": "/google", "url": "www.google.com" }, { "name": "bing", "route": " ...

Establish the Selenium property specifically tailored for the Selenium application

As a newcomer to Selenium and its frameworks, I require assistance with the following: In Program 1, I utilized set property to resolve slow key sending issues. The keys were being sent very slowly until I used setProperty. However, in Program 2, even af ...

Printing keys of objects in an array in AngularJS through iteration

Here is an array of objects that I am attempting to iterate in ng-repeat and print keys, but I am facing some challenges. $scope.directivesInfo = [ {"ngRepeat": {"enter": true, "leave": true, "move": true, "add": false, "remove": false}}, {"ngView ...

Using Node.js to Insert Data into MySQL

I recently started experimenting with node.js and decided to use node-mysql for managing connections. Even though I am following the basic instructions from the github page, I am unable to establish a simple connection successfully. var mysql = require(& ...

Is there a way to convert this JSON object into HTML table code?

I've been working on tweaking a code snippet I came across, but I'm struggling to get it to function the way I desire. Here is the current Javascript code: function JsonUtil() { /** * Given an object, * return its type as a string. ...

What are the steps to execute PhantomJS on a client machine?

I have implemented an HTML to PDF converter that utilizes phantomjs, following this method: npm install -g html-pdf var fs = require('fs'); var pdf = require('html-pdf'); var html = fs.readFileSync('./test/businesscard.html' ...

Scalable Vector Graphics Form Field

I'm looking to enable user input in one of my SVG text fields when they click on it. Any ideas on how to achieve this? const wrapper = document.getElementById('wrapper'); const text = document.getEl ...