pm.sendRequest doesn't seem to work inside of a collection level Utility pre-request script function

I’m attempting to set up the below script in my test collection to enhance the flexibility of my tests. However, the utils function receives the data but the pm.sendRequest doesn’t execute. Is there a problem with my script or is this simply something not possible with the setup? I’ve attempted to move the setup into the collection post-script, folder pre- and post-scripts and even the request pre-request script. Thanks in advance for the help!

//
//***********Start of collection Pre-request script*/
//
//Note: This is an attempted workaround needed due to Newman not supporting Packages and will throw failures for pm.require()
var _ = require("lodash"),
    momentJs = pm.collectionVariables.get("momentJs"),
    momentTimezone = pm.collectionVariables.get("momentTimezone");

//Check if data is already present to prevent repeated calls to CDNJS
if (_.isEmpty(momentJs) || _.isEmpty(momentTimezone)) {

    //Get latest moment.js version (required for moment-timezone usage)
    pm.sendRequest("https://api.cdnjs.com/libraries/moment.js?fields=version", (err, res) => {
        if (err) {
            console.log(err);
        }

        //Get moment.js library and set as a collection variable
        pm.sendRequest(`https://cdnjs.cloudflare.com/ajax/libs/moment.js/${res.json().version}/moment.min.js`, (error, resp) => {
            if (error) {
                console.log(error);
            }
            pm.collectionVariables.set("momentJs", resp.text())

            //Get latest moment-timezone version
            pm.sendRequest("https://api.cdnjs.com/libraries/moment-timezone?fields=version", (err, res) => {
                if (err) {
                    console.log(err);
                }

                //Get moment-timezone library and set as a collection variable
                pm.sendRequest(`https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/${res.json().version}/moment-timezone-with-data-10-year-range.min.js`, (error, resp) => {
                    if (error) {
                        console.log(error);
                    }
                    pm.collectionVariables.set("momentTimezone", resp.text())
                });
            });
        });
    });
};

//Utility function that stores mutiple functions used throughout the collection assertions
utils = {
    getZoneId: (city, state) => {
        const getZoneIdRequest = {
            url: pm.variables.replaceIn(`{{apiEndpoint}}/${city}/${state}`),
            method: 'GET',
            header: {
                "mockHeader1": pm.variables.replaceIn("{{mockHeader1}}"),
                "mockHeader2": pm.variables.replaceIn("{{mockHeader2}}")
            }
        };
        return new Promise((resolve, reject) => {
            pm.sendRequest(getZoneIdRequest, (error, res) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(res.json());
                }
            });
        });
    }
}
//
//***********End of collection Pre-request script*/
//

//
//***********Start of request Post-response script*/
//
var responseBody = pm.response.json();

//invoke the moment.js and moment-timezone libraries
(new Function(pm.collectionVariables.get("momentJs")))();
(new Function(pm.collectionVariables.get("momentTimezone")))();

//Make external call for extra data to use in assertion to compare with response
pm.sendRequest(`http://mock.endpoint`, (err, res) => {
    var mockDataResponse = res.json();

    (async () => {
        try {
            //Call utils function with city/state data from the mockDataResponse to narrow to the correct zoneId for moment-timezone conversion
            const zoneIdResponse = await utils.getZoneId(mockDataResponse.mockObject.city, mockDataResponse.mockObject.state);

            pm.test("Compare UTC", () => {
                var expected = moment.tz(`${mockDataResponse.mockObject.date} ${mockDataResponse.mockObject.time}`, zoneIdResponse.zoneId).toISOString(),
                    actual = responseBody.mockObject.utc;
                pm.expect(actual, `UTC values do not match`).to.eql(expected);
            });
        } catch (error) {
            console.error(error);
        }
    })();
});
//
//***********End of request Post-response script*/
//

I would suggest that you try and get this working in its basic form before trying to run as a utility function.

Here is an example.. Can you see if this works in the first instance.

if (!pm.globals.has("moment_js") || !pm.globals.has("moment_tz")) {
    pm.sendRequest("https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.js", (mtzErr, mtzRes) => {
        pm.sendRequest("https://momentjs.com/downloads/moment.js", (mjsErr, mjsRes) => {
            pm.globals.set("moment_js", mjsRes.text());
            pm.globals.set("moment_tz", mtzRes.text());
        })
    })
}

(new Function(pm.globals.get("moment_js")))();
(new Function(pm.globals.get("moment_tz")))();

console.log(moment.tz("2024-06-26T16:55:00", "America/New_York").format("YYYY-MM-DDTHH:mm:ss ZZ")); //2024-06-26T16:55:00 -0400
console.log(moment.tz("2024-12-26T16:55:00", "America/New_York").format("YYYY-MM-DDTHH:mm:ss ZZ")); // 2024-12-26T16:55:00 -0500

/*
Using the examples from the https://momentjs.com/timezone/ website and logging them to the Postman Console
*/

// Format Dates in Any Timezone

let jun = moment("2024-06-01T12:00:00Z");
let dec = moment("2024-12-01T12:00:00Z");

console.log(jun);
console.log(dec);

console.log(jun.tz('America/Los_Angeles').format('ha z'));  // 5am PDT
console.log(dec.tz('America/Los_Angeles').format('ha z'));  // 4am PST

console.log(jun.tz('America/New_York').format('ha z'));     // 8am EDT
console.log(dec.tz('America/New_York').format('ha z'));     // 7am EST

console.log(jun.tz('Asia/Tokyo').format('ha z'));           // 9pm JST
console.log(dec.tz('Asia/Tokyo').format('ha z'));           // 9pm JST

console.log(jun.tz('Australia/Sydney').format('ha z'));     // 10pm EST
console.log(dec.tz('Australia/Sydney').format('ha z'));  

// Convert Dates Between Timezones

let newYork    = moment.tz("2024-06-01 12:00", "America/New_York");
let losAngeles = newYork.clone().tz("America/Los_Angeles");
let london     = newYork.clone().tz("Europe/London");

console.log(newYork.format());    // 2024-06-01T12:00:00-04:00
console.log(losAngeles.format()); // 2024-06-01T09:00:00-07:00
console.log(london.format());     // 2024-06-01T17:00:00+01:00

I’m having a bit of a problem at the moment with global variables not being consistently set.

I wanted to test this afresh so I deleted the existing variables for both functions. I can see Postman hitting the correct end points, but for whatever reason, its not setting the global variables correctly. However, eventually it all starts working again (without me making any changes). It’s like there is a delay in setting the global variables. I’m using the web version of Postman so I’m not expecting any delays.

If I can get it to work properly and consistently like it used to, I’ll then have a go at extending this to get the latest versions like in your example.

You have to consider the async nature of sendRequest, but I did a quick test of this before the inconsistency started and this seems to work ok and in right order, so I think this will work once I’ve resolved the inconsistency issue.

It is worth noting that your code won’t actually check for new versions. Once it has stored the moment libraries, it won’t check it again unless you delete the existing variables. Pretty much the same as the code I’ve just provided.

I’ve also seen issues previously with using CDNs with incorrect information being return from the function, which is why I’m pulling it directly from the Moment website. The console logs I’ve included in my code are from the Moment website and are useful for checking that libraries are working correctly.

I appreciate the help with this! The above is a trimmed version as my larger setup calls daily to get the latest version CDN supports among other data I cannot post here. This was the first time I’ve attempted to use CDN instead of a self-built function for time zone conversion, so thank you for letting me know they as well may return incorrect information. In terms of basic form, I have this working as I want inside a local request but wanted to further globalize the setup to be easily used by others with the utils function setup. However, once moved into a utils function, it stops before the sendRequest is executed. Almost like it’s not in the correct location in how postman runs code from pre-request to post-response.

You have to send PM as a parameter when using local functions in that way.

For example…

Pre-request script

utils = {
    getZoneId: (pm, city) => {
        const getZoneIdRequest = {
            url: `https://postman-echo.com/get?city=${city}`,
            method: 'GET',
        };
        return new Promise((resolve, reject) => {
            pm.sendRequest(getZoneIdRequest, (error, res) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(res.json());
                }
            });
        });
    }
}

Post-response script

utils.getZoneId(pm, "Manchester");

Console logs

image

Awesome, that did the trick! Thanks again for your help with this

1 Like