I have some duplicate code I want to refactor and store in a postman collection variable. This function code is only duplicated once in my postman unit tests but I don't want even one duplication. So, I'm trying to store it in a collection variable and execute it however many times I need it.
As an arrow-function it works perfectly.
const parseMillisecondsIntoReadableTime = milliseconds => {
// From the milliseconds parm, this function calculates
// hours (h), minutes (m) and seconds (s) and returns a string like: "0h 29m 59s".
return parseInt(h) + 'h ' + parseInt(m) + 'm ' + parseInt(s) + 's';
};
Now I want to store this function in a postman collection variable.
Object.prototype.parseMillisecondsIntoReadableTime = function(milliseconds) {
// same code as above
// From milliseconds parm, this calculates
// hours (h), minutes (m) and seconds (s) and returns this string.
return parseInt(h) + 'h ' + parseInt(m) + 'm ' + parseInt(s) + 's';
};
This usage works perfectly.
let obj = {};
const timeToExpire = obj.parseMillisecondsIntoReadableTime(pm.collectionVariables.get('access_token_expiry')-new Date());
console.log('access_token valid for: ' + timeToExpire);
But, on unit tests somehow Postman references the function name in this error:
Response schema validation successful | Error: schema is invalid: data.properties['metadata'].properties['parseMillisecondsIntoReadableTime'] should be object,boolean.
The response object does have a schema with data and metadata properties. That's ok. How this error is occurring is perplexing.
This is the failing test.
pm.test("Response schema validation successful", () => {
const responseData = pm.response.json();
const successSchema = JSON.parse(pm.collectionVariables.get("successSchema"));
pm.expect(require("ajv")().validate(successSchema, responseData)).to.be.true;
});
This is the successSchema layout.
const successSchema = {
type: "object",
properties: {
metadata: {
type: "object",
properties: {
status: { type: "string" }
},
required: ["status"]
},
data: {
type: "object",
properties: {
brandName: { type: "string" },
goodsSupplierNumber: { type: "string" },
supplierNumber: { type: "string" }
},
required: ["brandName", "goodsSupplierNumber", "supplierNumber"]
},
errors: {
type: "array",
items: {
type: "object",
properties: {
code: { type: "string" },
message: { type: "string" }
},
required: ["code", "message"]
}
}
},
required: ["metadata", "data", "errors"]
};
pm.collectionVariables.set("successSchema", JSON.stringify(successSchema));
Final note: All my unit tests (322) worked until I tried to use a stored function in the collection variable.
One of the better ways to setup a re-usable function is to use a global variable in a pre-request script.
For example (the function itself is not important, its just an example). You can put this at the request, folder or collection level.
utils = {
parseMillisecondsIntoReadableTime: function (milliseconds) {
var seconds = Math.floor((milliseconds / 1000) % 60),
minutes = Math.floor((milliseconds / (1000 * 60)) % 60),
hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + ":" + minutes + ":" + seconds;
}
};
This is preferred to using EVAL which is not recommended, or by updating the prototype chain.
You can then call the method using.
var currentTime = +new Date(); // in milliseconds
console.log(currentTime);
console.log(utils.parseMillisecondsIntoReadableTime(currentTime));
With the resulting console logs.
If you want to use Postman functions, then you need to pass the pm method like following.
utils = {
statusCode: function (pm, code) {
pm.test(`Status code is ${code}`, () => {
pm.response.to.have.status(code);
})
return utils;
},
response: function (pm) {
console.log(pm.response.json());
return utils;
}
};
Which you can then call using..
utils.response(pm);
utils.statusCode(pm, 200);