Waiting for elements in the response goes to infinite loop

I was wondering if anyone could help me out here:) I have a POST request to make a booking and then a Get request to fetch ‘below booking status’ -
BOOK_RECEIVED, BOOKING and BOOKED
response json:-

{
    "statusHistory": [
        {
            "message": "booking received",
            "datetime": "2020-11-11T00:39:15.043Z",
            "statusCode": "BOOK_RECEIVED"
        },
        {
            "message": "booking",
            "datetime": "2020-11-11T00:39:15.149Z",
            "statusCode": "BOOKING"
        },
        {
            "message": "booked",
            "datetime": "2020-11-11T00:39:20.701Z",
            "statusCode": "BOOKED"
        }
    ]
}

It takes a few seconds to move from BOOK_RECEIVED to BOOKING to BOOKED.
So, I have added the below code to the ‘Tests’ in the Get request to poll:-

var getStatus = function(){
     bodyData=JSON.parse(responseBody);
      var statusArray= bodyData.statusHistory.map(
            function(filter) {
                return filter.statusCode; 
            });
            return statusArray;
  }

while(getStatus().length<3){  
      setTimeout(()=>{},1000);
      postman.setNextRequest(pm.info.requestId);
}

The issue I face is that it goes into an infinite loop and I can’t figure out why. Could anyone suggest a better way of handling it or how to fix this one?

What is getStatus() returning? Have you logged that out to know what it returns an array?

Hello
I think the main problem is the length of the array
The length fonction give you the max number that the array can hold
To investigate the problem
Remove the while and check that you get the right length of the statuscode you have
After you check the length you get check the compare you have with 3
Hope that help you out

@danny-dainton, getStatus() returns those three statuses. I have checked (outside the loop) and it does return BOOK_RECEIVED, BOOKING and BOOKED. The issue is all those statuses aren’t available straight away. So, I use the loop until the array length is 3. This is where it goes to infinite loop.

I have checked and it does return the length of the array available. But the issue is I don’t get all statuses straightaway. So, need to poll for few seconds to get the length==3. This is where it goes to infinite loop

You can see in the screenshot that it has returned two statuses straightaway. Then I use the loop until I have 3. At least that’s what I am trying to achieve.

Hello again
Check the return value of “ getStatus().length “ in the log output ??

It does output the correct number of elements in the array.

I was just messing about and haven’t tried this out yet but would something basic like this work:

I changed it so you not needing to create a new array each time to check the length, this would just go a get the last object in the array and check the statusCode.

let bodyData = pm.response.json(),
    lastStatusObject = bodyData.statusHistory[bodyData.statusHistory.length -1]

if (lastStatusObject.statusCode !== "BOOKED" ){  
    setTimeout(()=>{},1000);
    postman.setNextRequest(pm.info.requestName);
} else if (lastStatusObject.statusCode === "BOOKED" ) {
    postman.setNextRequest(null);
}

Might be totally wrong and not what you’re looking for, I was just curious :smiley:

1 Like

No, that’s amazing @danny-dainton. It worked:) Thank you. Only issue is I can’t assert :-

pm.expect(response.statusHistory[2].statusCode).to.eql("BOOKED");

error –
TypeError: Cannot read property 'statusCode' of undefined

The above assert gets executed before pm.setNextRequest() and of course it can’t find that key/value in the array when it’s run first time. So, is there anyway we could wait for the setNextRequest() to complete before I assert? I have read that setNextRequest() gets executed last always…

Not completely sure without having that in front of me to run but you could use _.get() to check to see if that object is present in the array, if it is…run the test.

if(_.get(response.statusHistory, '[2].statusCode') !== undefined) {
    pm.test("Status is BOOKED", () => {
        pm.expect(response.statusHistory[2].statusCode).to.eql("BOOKED")
    });
}

or you could add something different that runs a ‘skipped’ test unless the object is present :man_shrugging:

let skipTest = _.get(response.statusHistory, '[2].statusCode') === undefined;

(skipTest ? pm.test.skip : pm.test)("Status is BOOKED", () => {
    pm.expect(response.statusHistory[2].statusCode).to.eql("BOOKED")
});
1 Like

That worked. Thanks again @danny-dainton. I have only been using Postman for last 30 days or so, so, unfortunately have lots of questions :). I appreciate the help

1 Like

@danny-dainton, Just one more question out of curiosity on the first solution you gave. How does it iterate without a loop until it gets the BOOKED status. I can see it as shown below —

image

As you’re using the runner, the loop is coming from the postman.setNextRequest(pm.info.requestName) statement and that will keep going until you tell it to stop.

In this case, you’re setting the next request, to be the same request, so it’s just going to keep repeating that until the condition in the if statement is met.

Once the else if condition returns true, it goes down the other path and hits the postman.setNextRequest(null) which is the command to exit the workflow.

This would only loop if you’re using the Collection Runner to run the request.

There are lots of different ways/methods to loop through something, the for and while loops are the common ones but this wasn’t really needed here as the looping action is being done by the internal Postman function.

Hope that makes sense. :smiley:

1 Like

Yep, that makes perfect sense. Didn’t realize postman.setNextRequest(pm.info.requestName)would loop. Great explanation. Thanks

1 Like