Using native javascript promises in postman

Hi,

Javascript and node now has native support for Promises. I was hoping we could use these in Postman and newman as well to chain async sendRequest calls.

Although declaring and using new Promise works but chaining does not work.

For example look at the code below (put this in test script of any request)

var promiseMethod = function(text) {
   var promise = new Promise(function(resolve, reject){
      console.log('Enter: ' + text);
      setTimeout(function() {
         console.log('Complete: ' + text);
         resolve({data: text + ' 123'});
      }, 2000);
   });
   return promise;
};

promiseMethod('first')
   .then((v) => {return promiseMethod('second');})
   .then((v) => {return promiseMethod('third');})

The Postman Console output for this is:

Enter: first
Complete: first
Enter: second

Whereas if run through NODE or even Chrome console, the output is:

Enter: first
Complete: first
Enter: second
Complete: second
Enter: third
Complete: third

Whats the reason, that only the 1st Promise call is handled by postman/newman but chained calls do not work ?

1 Like

Hi @aksbenz This is a known issue - we’re working to get this working correctly. As a temporary workaround, you can use this:

 var interval = setTimeout(function() {}, 10000),
  promiseMethod = function(text) {
   var promise = new Promise(function(resolve, reject){
      console.log('Enter: ' + text);
      setTimeout(function() {
         console.log('Complete: ' + text);
         resolve({data: text + ' 123'});
      }, 2000);
   });
   return promise;
};

promiseMethod('first')
   .then((v) => {return promiseMethod('second');})
   .then((v) => {return promiseMethod('third');})
   .then((v) => {clearTimeout(interval);})

This essentially adds a timeout that’s closed when all promises are resolved. This makes the Postman script module to wait till that time before proceeding to send the request.

1 Like

Hi @abhijit do you have any update on this? are promises working properly with the latest version of postman?

We are evaluating Postman as a platform to run our E2E tests on and not having promises seriously impacts our ability to write non-trivial scripts.

Currently, I need to do 3 API calls to setup the application to be ready for testing. With callbacks this is seriously hell.

3 Likes

I need to use the result of the promise as an environment variable - but it seems it’s getting set too late. Any suggestions?

"use strict";
var lock = setTimeout(function() {}, 3000);
var secret = '<redacted>';

postman.setEnvironmentVariable("nonce", Math.ceil(new Date().getTime() / 1000));

hash('SHA-256', secret + '' + postman.getEnvironmentVariable('nonce')).then(function(sha) {
    postman.setEnvironmentVariable("nonce_token", sha);
    clearTimeout(lock);
});


console.log(hash('SHA-256', secret + '' + postman.getEnvironmentVariable('nonce')));

async function hash(digest, inputString) {
	return Array.from(new Uint8Array(crypto.subtle.digest(digest, new TextEncoder("utf-8").encode(inputString)))).map(b => (b.toString(16).padStart(2, "0"))).join('');
}

Edit:
Worked around the issue using

require("crypto-js");
CryptoJS.SHA256(secret + '' + postman.getEnvironmentVariable('nonce')).toString(CryptoJS.enc.Hex);

Hey guys, thanks for the tips here. I had the same issue and just documented the solution (using a global setTimeout) at Stack Overflow.

Hello All,

Postman Tests with chained promises is executing only the first promise but not chained promises. I am not sure whats wrong with this code but it is executing only 1st promise and ignoring the rest.

I have tried based on the above solution but didn’t work. Kindly help me in this regard.

const interval = setTimeout(() => {}, Number.MAX_SAFE_INTEGER);

let promiseNumber = 0;

function resolvedPromise() {
    return new Promise((resolve, reject) => {
        pm.sendRequest('https://postman-echo.com/get', (err, res) => {
            if (err) {
                console.log(err);
                reject();
            } else {
                console.log(`Resolved promise ${++promiseNumber}`);
                resolve(pm.response.to.have.status(200));
            }
        });
    });
}

resolvedPromise()
    .then(resolvedPromise)
    .then(resolvedPromise)
    .then(() => clearTimeout(interval))
    .catch(err => {
        console.log(err);
        clearTimeout(interval);
    });

Thanks
Dinesh

It doesn’t seem to work in the newer versions of postman. I have tried numerous iterations of this solution to no luck. I have found that going to a lovely (/sarcasm) callback approach works…

let promiseNumber = 0;
function resolvedPromise(cb) {
        pm.sendRequest('https://postman-echo.com/get', (err, res) => {
            if (err) {
                console.log(err);
                cb(err);
            } else {
                console.log(`Resolved promise ${++promiseNumber}`);
                cb(res.json());
            }
        });
}

resolvedPromise(()=>resolvedPromise(()=> resolvedPromise(()=>{})))
1 Like

Any update on this? Is it confirmed that the setTimeout technique for chaining promises with pm.sendRequest is NOT working in the latest version of Postman sandbox?

I’m on 7.22.1 and I also cannot seem to get the setTimeout work around to work either.

2 Likes

I confirm that the workaround is not working for me.

currently on version 7.34.0

There is any update on this issue?
I’ve implemented the code below to asynchronously get domain values from my API. The promises are ok and run well, but pm.globals.set(“domains”, values) don’t persist “values” content. I’ve tried using environment, but still, “values” are never saved to the “domains” variable.
But the content is console logged perfectly. Can anyone figure out what’s going wrong?


function GetItem(id) {

    return new Promise((resolve, reject) => {

        const host = pm.environment.get('gateway');
        const key = pm.environment.get('Ocp-Apim-Subscription-Key');

        const request = {
            url: `${host}/api/${id}`,
            method: 'GET',
            header: {
                'Content-Type': 'application/json',
                'Ocp-Apim-Subscription-Key' :  `${key}`
            }
        };

        return pm.sendRequest(request, (error, response) => {
            if(error) reject(error);

            if(response.status==="OK") 
                resolve({domain:id, items: response.json()});

            reject(new Error(`HTTP error! status: ${response.status}.`));
        });
    });
}

Promise.all([
    GetItem('assistency'),
    GetItem('claim-type'),
    GetItem('coverage-type'),
    GetItem('property-type'),
    GetItem('type-of-use'),
    GetItem('insurance-type'),
    GetItem('location-type'),
    GetItem('payment-type')
]).then(values=> {
    pm.globals.set("domains", values);
    const domains = pm.globals.get("domains");
    console.log(domains);
}).catch(e=>console.log(e));

@m4cm3nz
I don’t think this is fixed.

Try this with a global timeout:

var lock = setTimeout(function() {}, 30000);

function GetItem(id) {

    return new Promise((resolve, reject) => {

        const host = pm.environment.get('gateway');
        const key = pm.environment.get('Ocp-Apim-Subscription-Key');

        const request = {
            url: `${host}/api/${id}`,
            method: 'GET',
            header: {
                'Content-Type': 'application/json',
                'Ocp-Apim-Subscription-Key' :  `${key}`
            }
        };

        return pm.sendRequest(request, (error, response) => {
            if(error) reject(error);

            if(response.status==="OK") 
                resolve({domain:id, items: response.json()});

            reject(new Error(`HTTP error! status: ${response.status}.`));
        });
    });
}

Promise.all([
    GetItem('assistency'),
    GetItem('claim-type'),
    GetItem('coverage-type'),
    GetItem('property-type'),
    GetItem('type-of-use'),
    GetItem('insurance-type'),
    GetItem('location-type'),
    GetItem('payment-type')
]).then(values=> {
    pm.globals.set("domains", JSON.stringify(values));
    const domains = pm.globals.get("domains");
    console.log(domains);
    clearTimeout(lock);
}).catch(e => {
     clearTimeout(lock);
     console.log(e)
    });
1 Like

Has anyone made a formal bug-report, i.e. raised an issue, about this in GitHub?
If the answer is yes, what is the link to that issue?


BTW, I am currently inserting:
const lock = setTimeout(() => {}, 43210);
as the first row in my code, and later:
clearTimeout(lock); // Unlock the timeout.
as the first row in the final callback.
It works great as a workaround, so thanks for suggestiing it! :+1:

I think this post could help in resolving this issue of running chained requests in a series (wouldn’t really call it synchronously since requests are actually async in nature :thinking: ): Async Operations!

This can be one temporary solution till promises are natively supported in Postman.

I am very much looking forward to seeing promises natively supported in Postman! :slightly_smiling_face:

I will be a huge step up.

Update: As of Postman v10.6.7, this bug has been fixed, and the workaround is no longer required!

If you’re interested in the technical details behind the fix, it was made in the open source postman-sandbox repo, available here: Support Promise execution in the sandbox. by kevinswiber · Pull Request #872 · postmanlabs/postman-sandbox · GitHub

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.