V
V
valentine112016-11-27 16:30:04
JavaScript
valentine11, 2016-11-27 16:30:04

Promise doesn't work right, huh?

There is a task: to get some data from the page, generate urls with this data, then send requests to the urls and check it in the response.
The following code was made:

function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return search.forEach(function(val, i) {
                    console.log(search.length); //debug printing
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        console.log(body);
                        assert.include(body, 'class="someClass"');
                    });
                });
            });

        }

        return checkSpec();

But it doesn't work correctly. First, the array is iterated over, the test step allegedly passes successfully, other steps begin, and somewhere in the middle answers begin to come (output body to the console).
What needs to be corrected in the promise so that it works fine? Those. for each element of the array - request - check, and only then for the next element of the array - request - check, etc.
UPD.
After changing the code as recommended, I got this:
function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return Promise.all(search.map(function(val, i) {
                    /*console.log(search.length);*/
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        var $ = cheerio.load(body);
                        var txt = $('locator1').text().replace(/\s+/g," ").trim();
                        var doc = $(locator2').text().trim();
                        /*console.log(txt);*/
                        return assert.notEqual(txt, '', "не найдены: "+ doc);
                    });
                }));
            });

        }

        return checkSpec();

Now he at least checks everything is fine and the step fails when the check fails. The problem is that when the check fails, the rest of the checks still pass to the end (if you do not remove the text output to the console, you can see that after the fall, the text of the following checks continues to be displayed). How to make it so that after the check fails, stop the rest of the checks? I tried to insert if (condition) {return}, but it does not help, maybe I also inserted it in the wrong place.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
V
Vitaly, 2016-11-27
@vitali1995

You need to wrap the promises returned in the loop in an array and return Promise.all(array) at the end.
This action starts waiting for all the promises in the array to be fulfilled. A promise is also returned, from which you can call
.then(...)
.catch(...)
In general, I suggest paying attention to the innovation: async/await - life becomes much easier with them.

D
Dmitry Belyaev, 2016-11-27
@bingo347

forEach always returns undefined, you need a map
To wait for all promises in the array to complete, use Promise.all
total:

function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return Promise.all(search.map(function(val, i) {
                    console.log(search.length); //debug printing
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        console.log(body);
                        assert.include(body, 'class="someClass"');
                    });
                }));
            });

        }

        return checkSpec();

_
_ _, 2016-11-28
@AMar4enko

var executeSequence = function(promiseFn, values, acc) {
  if (!values.length) return Promise.resolve(acc);
  var promise = promiseFn(values.shift());
  acc = acc || [];
  return promise.then(function(result) { 
    acc.push(result);
    return executeSequence(promiseFn, values, acc);
  });
};

var requestUrl = function(url) {
return new Promise((resolve, reject) => {
 request(url, function(error, response, body){
    if (error) {
       reject(error);
    }
     resolve(body);
});  
}

executeSequence(requestUrl, ['http://google.com', ...])
  .then(function(response) { 
    // response это массив из body для каждого из url по порядку
  })
  .catch(function(reason) {
    
  });

https://github.com/joliss/promise-map-series

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question