Christine Edwards
Christine Edwards

Reputation: 99

promise not resolving before return

I am parsing through an array of files and posting to the database. As part of that, I need to keep totals of the data in the files, and a count of successful record insertions into the database. The promise is not waiting for all the records to be written to the database.

I am looking for the parserResults method to return the testResults back to the calling .reduce. It does pass it back, but the insertSuccess = 0.

I put in some console logs to see what it is doing and the finalResult is displaying on the console before the incremented insertSuccess counter is incremented.

Console.log results

In parseresults ui-results-11705.json
In parseresults ui-results-14981.json
In parseresults ui-results-14982.json
In parseresults ui-results-28274.json
In parseresults ui-results-368.json

finalResult =  { insertSuccess: 0,
  insertFailed: 0,
  testPassedCount: 2,
  testFailedCount: 3 }

insertSuccess 1
insertSuccess 2
insertSuccess 3
insertSuccess 4
insertSuccess 5

This is the code calling the function that will parse the files

 matches.reduce(function (p, val) {
    return p.then(function () {
      console.log('p', p);
      return parser.parseResults(val);
    });
}, Promise.resolve()).then(function (finalResult) {
     console.log('finalResult = ', finalResult);
}, function (err) {
     console.log('error in reduce', err);
});

Here is the method being called

protractorParser.prototype.parseResults = function (fileName) {
    return new Promise((resolve, reject) => {
        console.log('In parseresults', fileName);
        var currentFile = './testing/results/' + fileName
        json.readFile(currentFile, function (err, obj) {
            if (err != null) {
                console.log('error reading file', err);
                reject(err);
            } else {
                resolve(obj);
            }
        });
    }).then(function (obj) {
        var results = [];


        for (var suite in obj) {
            var specs = obj[suite].specs;
            for (let i = 0; i < specs.length; i++) {
                const assert = specs[i];
                const tcR = /TC[\d]+/;
                const tc = assert.description.match(tcR);

                let Passed = 1;
                let Message = '';
                let Stack = '';
                if (assert.failedExpectations.length) {
                    const expectation = assert.failedExpectations[assert.failedExpectations.length - 1];
                    Passed = 0;
                    Message = expectation.message;
                    Stack = expectation.stack.split('\n')[1].trim();
                    testResults.testFailedCount++
                } else {
                    testResults.testPassedCount++
                }
                if (tc != null) {

                    const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
                    const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
                    results.push(promise.then(() => {

                        testResults.insertSuccess++;
                        console.log('insertSuccess', testResults.insertSuccess);

                    },
                        err => { console.log('… failed', err); throw err; }
                    ));

                } else {
                    console.log('no test case found for test: ' + assert.description + ' -- skipping');
                    // I don't think you want to `throw err` here, right?
                }
            }
        }
        return (Promise.all(results), testResults);
    });
};

I have played around with several different scenarios in the code and can't seem to figure it out. Any help would be greatly appreciated. Thanks Christine

Upvotes: 1

Views: 1017

Answers (1)

jfriend00
jfriend00

Reputation: 707406

parseResults() is not properly returning a promise, therefore your p.then() inside the .reduce() loop doesn't wait for anything.

Change this:

return (Promise.all(results), testResults);

to this:

return Promise.all(results).then(() => testResults);

The code you were using: return (Promise.all(results), testResults); was only returning testResults, not a promise. What I think you want is to know when all the promises are done and then to make testResults be the resolved value. To do that, you use .then() on the Promise.all() and then return testResults from that .then() handler. That will return a single promise whose resolved value is testResults.

FYI, you may not need to do that at all because testResults appears to be a higher scoped variable that you could just refer to directly. If you're willing to do that, then you would just change to:

return Promise.all(results);

And, then don't use finalResult in your final .then() handler, just refer to the higher scoped testResults variable directly.


FYI, a cleaner implementation of this could pass in an object that each iteration of the loop returns and passes on to the next iteration so there's no reference at all to a higher scoped variable and everything is more self contained. Then, you would use the first type of return I showed you, but you'd return the passed in object, not the higher scoped object.

Upvotes: 2

Related Questions