0

I'm currently struggling with a problem regarding pm.sendRequest in Postman Pre-request script. I'm trying to run a Request within a for loop, but something it doesn't work properly.

Pre-request Script

var numberOfCampaigns = 2; //this number can have any value from 1 to 20)
for (var j = 0; j < numberOfCampaigns; j++) {
    console.log(`J1:` + j);
  var request_call = {
    url: pm.environment.get("api-url"),
    method: "POST",
    header: {
      "content-type": "text/xml",
      SOAPAction: "add",
    },
    body: {
      mode: "raw",
      raw: "some-body"},
  };
  pm.sendRequest(request_call, (err, res) => {
    if (err) {
    } else {
      console.log(`J2:` + j);
        length = 2
        for (var i = 0; i < length; i++) {
        pm.environment.set(`someVariable_` + i + `_` + j, responseJson[i]);       
        console.log(`someVariable:`+i+`_`+j+`:`+ pm.environment.get(`someVariable_` + i + `_`+j));
      }
    }
  });
  console.log(`J3:` + j);
}

Console output:

J1:0
J3:0
J1:1
J3:1
POST https://api-url/
J2:2
someVariable_0_2:...
someVariable_1_2:...
POST https://api-url/
J2:2
someVariable_0_2:...
someVariable_1_2:...
GET https://api-url2/ (The actual Request)

I don't understand why the J2 console output is 2 instead of being 1 for the first Request then 2 for the second Request

Could you please help ?

UPDATE

After @Keith response I tried to make some changes:

var numberOfCampaigns = 2

const _dummy = setInterval(() => {}, 300000 );

function sendRequest(req) {
    
    return new Promise((resolve, reject) => {
        pm.sendRequest(req, (err,res) => {
            if (err) {
                console.log(err);
                return reject(err);
        }
      console.log(`J2:` + j);
      for (let i = 0; i < length; i++) {  
        pm.environment.set(`someVariable_` + i + `_` + j, responseJson[i]);       
        console.log(`someVariable:`+i+`_`+j+`:` + pm.environment.get(`someVariable_` + i + `_`+j));
      }
        return resolve(res);
    })
    });
}

(async function main() {
    for(var j=0; j<numberOfCampaigns; j++){
        var request_call = {
        url: pm.environment.get("api-url"),
        method: "POST",
        header: {
          "content-type": "text/xml",
          SOAPAction: "add",
        },
        body: {
          mode: "raw",
          raw: pm.environment.get(`parameter`+j},
        };
        await sendRequest(request_call);
        clearInterval(_dummy);
    }
})();
Paracetamol12
  • 35
  • 1
  • 8

1 Answers1

1

Your scripts are asynchronous - pm.sendRequest makes the request and calls your callback function when that request completes.

That may take varying amounts of time.

I would expect your script to start:

J1:0
J3:0
J1:1
J3:1

Because all of those are synchronous.

J2: will appear when your HTTP requests return, but by then your loop will have finished, so they will both show J2:2.

Note that i will work because it's inside your callback function, and var j is global - JS doesn't apply closures to loops or blocks unless you use let j and the callback would keep the reference to it anyway.

You may even get the someVariable logs out of order because the requests won't queue - whatever server may finish the second request before the first one.

The best way to avoid this is with await or Promise.all to makes sure that your JS outside of the callback doesn't run until the async actions have finished.

Keith
  • 150,284
  • 78
  • 298
  • 434
  • I understand, but how can I implement all those request using await or Promise beacuse I'm not that expert in JS and its kinda difficult for me. I saw (https://community.postman.com/t/executing-sync-requests-programmatically-from-a-pre-request-or-test-scripts/14678/2) that I can implement, but I can't understand how can I do this in my case beacuse for me the number of sendRequest may be different for each request. – Paracetamol12 May 13 '21 at 15:33
  • @Paracetamol12 yes, that link uses `await`, if you use it it will mean that your loop pauses (and doesn't increment) until the request finishes. `await` sounds like the best way to get your code to work, but you'll need `async` on the top level method. – Keith May 13 '21 at 15:45
  • ,I added an update to the original post with my changes, but I don't why It works only for the first Request then I recieve `RefferenceError: j is not defined` then Sending request is loading forever. Did I made something bad in the code ? – Paracetamol12 May 13 '21 at 16:22
  • @Paracetamol12 yes, now `var j` is inside a function it's no longer visible to `sendRequest` - add a parameter to the function `sendRequest(req, j)` and then do `await sendRequest(request_call, j)` to pass it through. – Keith May 13 '21 at 16:24
  • Thank you very much @Keith, I don't know how to thank you, now everything works great, after your sugesstion and to get clearInterval(_dummy) out of from for. Thank you again – Paracetamol12 May 13 '21 at 16:36