This repo holds the utils
JavaScript class that can simplify and reduce Postman test and pre-request code.
The utils
library is a simple JavaScript object that, when included in a collection folder's pre-request script, will be available to all scripts called after it. The object exposes various functions intended to make Postman tests shorter, simpler and more consistent.
The utils
library is intended for testing REST APIs. There are hardly any prerequisites for using the library, but you would get the most out of it if the REST APIs you are testing were consistent: if they used standrard HTTP status codes to report successful and unsuccessful operations in a predictable and consistent manner. For negative testing and for better reporting of test failures, it would be beneficial if the REST API returned an RFC 7807-compliant problem details object with a custom string property identifying error code, such as serviceCode
in this example (the name of the property can be different):
{
"type": "https://example.com/probs/bad-input",
"title": "Bad Input",
"detail": "Invalid email format: 'bademail@com'.",
"instance": "/users/12345",
"serviceCode": "BadInput"
}
For a single ad-hoc test, the utils
library will offer little value, but if you are using Postman for automated functional or regression testing, it will:
- allow you to run positive and negative test in a consistent manner
- eliminate the need to cut and paste standard test boilerplate code (logging the operation, processing errors, etc)
- provide standard handling and reporting of test failures
- make it easier to figure out the cause of test failures
- reduce code needed to validate returned results
With the utils
library, implementing a positive test can be done with one line of code, such as:
utils.test.positive(pm, null, 200);
And a negative test could be as simple as:
utils.test.negative(pm, null, 400, "BadRequest");
To use the utils
library, copy the utils.js
source code and paste it in the pre-request script of the test collection's root folder. Then you can call the utils
functions from anywhere in the test code base.
The utils
source code comments explain how to use the library, but a more detailed description is provided here.
Most utils
functions are logically grouped under the inner classes (namespaces).
Parameters which are common in the function groups are defined in the group sections. Similar to the pm
parameter described below, they are not included in the function definition unless the function specific usage differs from the common usage.
The following parameters are common to all utils
functions:
pm
: For the sake of consistency, allutils
functions expect the globalpm
object to be passed as the first parameter, including the ones that don't really need it.
The utils
functions are logically grouped in nested classes (namespaces) and include:
- Folder level functions for setting up tests
- Primary test functions for testing request results
- Data validation functions for checking data returned from requests
- Trace functions for trace logging
- General purpose functions for miscellaneous operations
Before we get to the function definitions, let's summarize how requests work, so we know what gets executed when (if you already understand how the Postman request worflow works, you can skip to the next section).
For each request in the test collection being executed, Postman first runs pre-request scripts defined in all request parent folders starting from the top level folder. Then Postman runs request's pre-request script, executes the request, and runs all post-request scripts defined in the parent folder just as it did with folder pre-requests. Finally, it runs request tests. And it is worth repeating: this logic gets executed for every request in the test collection. You may not need to run any scripts for any or all folders, which is fine: you simple do not add any code to them; but when you do, you may need to run the code once per test collection execution or for every request in the collection.
Let's use the following example:
- Collection [pre-request|test]
|
- Folder A [pre-request|test]
|
- Folder B [pre-request|test]
|
- REQUEST X [pre-request|test]
|
- REQUEST Y [pre-request|test]
Assuming that all folders and requests have pre-request and test scripts, the execution will go like this:
- Collection pre-request script.
- Folder A pre-request script.
- Folder B pre-request script.
- REQUEST X pre-request script.
- REQUEST X
- Collection test script.
- Folder A test script.
- Folder B test script.
- REQUEST X test script.
- Collection pre-request script.
- Folder A pre-request script.
- Folder B pre-request script.
- REQUEST Y pre-request script.
- REQUEST Y
- Collection test script.
- Folder A test script.
- Folder B test script.
- REQUEST Y test script.
Use folder level functions to run test or pre-request code attached to test collection folders (but not request scripts).
Folder level functions are grouped under the utils.run
namespace and include:
utils.run.once
: Invokes code in the specified custom inline function once per test collection run.utils.run.always
: Invokes code in the specified custom inline function for every request during test collection run.
The following parameters are common to all folder level functions:
name
: Unique name of the folder in the test collection. Because Postman API does not provide a way to determine the current folder, pass a unique name of the folder when calling these functions (the name may need to be unique in the collection) via thename
parameter.process
: Inline function containing the code to be executed once or always.onerror
: Optional function containing code to be executed on error in theprocess
function.
Invokes code in the specified custom inline function once per test collection run.
utils.run.once(pm, name, process, onerror)
Initialize settings for the test collection run in the collection folder's pre-request script.
utils.run.once(pm, "Client_Credentials_Flow_Tests", function() {
console.log("This code will be executed once in the begining of the test collection run.");
}, function() {
console.log("This code will be executed if an error occurs in code above.");
});
Invokes code in the specified custom inline function for every request during test collection run.
utils.run.always(pm, name, process, onerror)
Initialize settings for the test collection run in the collection folder's pre-request script.
utils.run.always(pm, "Client_Credentials_Flow_Tests", function() {
console.log("This code will be executed for every test.");
}, function() {
console.log("This code will be executed if an error occurs in code above.");
});
Use primary test functions to initialize and execute tests. Primary test functions are grouped under the utils.test
namespace and include:
utils.test.initialize
: Use to initialize request data in pre-request scripts.utils.test.positive
: Use to execute positive tests.utils.test.negative
: Use to execute negative tests.utils.test.neutral
: Use if you need to execute additional tests that must run separately from the primary (positive or negative) test defined for a request.
The following parameters are common to all primary test functions:
name
: All primary test functions require thename
parameter to hold the unique name of the request (or test). In most cases, instead of hard coding request (or test name), pass thenull
value and the functions will set the name to the globalpm.info.requestName
property holding the name of the request. You should only specify an explicitly defined name if you run multiple tests for a single request, so that you can differentiate between them in the test logs.process
: Inline function containing the code to be executed (this function is optional forutils.test.positive
andutils.test.negative
functions because they already provide the minimal test functionality that may be sufficient for certain cases).onerror
: The optional error handler that can be handy if you need to implement special logic (like stopping test execution or skipping to a specific test) on operation failure in the default or customprocess
function.
Use utils.test.initialize
to initialize request data in pre-request scripts.
utils.test.initialize(pm, name, process, onerror)
Initialize request data in the pre-request script.
utils.test.initialize(pm, null, function() {
console.log("Add initialization logic here.");
}, function() {
console.log("This code will be executed if an error occurs in code above.");
});
Use utils.test.positive
to run positive tests. By default, it will check the response's HTTP status code against the specified (or default) value. If the returned HTTP status code matches the expected value, this function will call additional custom code if one is specified via the process
parameter.
utils.test.positive(pm, name, status, process, onerror)
status
: Expected HTTP status code returned in HTTP response (default value:200
; it is recommended to explicitly set the expected value).
A positive test that only checks for the default 200 OK
HTTP status code passed in the HTTP response.
utils.test.positive(pm);
A positive test that only checks for the 204 No Content
HTTP status code passed in the HTTP response.
utils.test.positive(pm, null, 204);
A positive test that checks for the 200 OK
HTTP status code passed in the HTTP response and implements additional check.
utils.test.positive(pm, null, 200, function() {
console.log("Add custom validation checks here.");
});
A positive test that checks for the 200 OK
HTTP status code passed in the HTTP response and implements additional check and error handling.
utils.test.positive(pm, null, 200, function() {
console.log("Add custom validation checks here.");
}, function() {
console.log("This code will be executed if an error occurs in code above or default test logic.");
});
Use utils.test.negative
to run negative tests. By default, it will check the response's HTTP status code against the specified (or default) value. If the returned HTTP status code matches the expected value, this function will also check the value of the serviceCode
(or similar) property defined in the data object returned in HTTP response. You can also add additional checks in the custom code defined in the process
parameter.
utils.test.negative(pm, name, status, serviceCode, process, onerror)
status
: Expected HTTP status code returned in HTTP response (default value:400
; it is recommended to explicitly set the expected value).serviceCode
: Optional string value of the property holding error code returned by the HTTP response. By default, the name of the property is expected to beserviceCode
. To check a different property, add the name followed by the colon (:
) or equal (=
) character before the expected value, such as'errorCode=IllegalOperation'
.
A negative test that only checks for the default 400 Bad Request
HTTP status code passed in the HTTP response.
utils.test.negative(pm);
A negative test that only checks for the 401 Unauthorized
HTTP status code passed in the HTTP response.
utils.test.negative(pm, null, 401);
A negative test that checks for the 400 Bad Request
HTTP status code passed in the HTTP response and the specified serviceCode
returned via response data.
utils.test.negative(pm, null, null, 'IllegalNameValue');
A negative test that checks for the 401 Unauthorized
HTTP status code passed in the HTTP response and the specified errorCode
returned via response data.
utils.test.negative(pm, null, 401, 'errorCode:CallerIsNotAdmin');
A negative test that checks for the 400 Bad Request
HTTP status code passed in the HTTP response and implements additional check.
utils.test.negative(pm, null, 400, null, function() {
console.log("Add custom validation checks here.");
});
A negative test that checks for the 404 Not Found
HTTP status code passed in the HTTP response and implements additional check and error handling.
utils.test.negative(pm, null, 404, null, function() {
console.log("Add custom validation checks here.");
}, function() {
console.log("This code will be executed if an error occurs in code above or default test logic.");
});
The utils.test.neutral
function is intended for a rare case when you need to implement multiple tests for the same request. It is similar to the utils.test.positive
and utils.test.negative
functions, except it does not perform any default validation and totally relies on the custom test code specified by the caller in the process
parameter. Also, because multiple tests are associated with the request, it is recommended to give each of them a unique name (for example, you can append an incremented index to the default test name as illustrated in the example below). Generally, you should avoid using this function.
utils.test.neutral(pm, name, process, onerror)
A positive test that checks for the returned 200 OK
HTTP status code and some custom validation followed by two additional tests.
var i = 1;
utils.test.positive(pm, utils.name(pm, null, i++), 200, function() {
console.log("Add custom validation checks here.");
});
utils.test.neutral(pm, utils.name(pm, null, i++), function() {
console.log("Add more custom validation checks here.");
});
utils.test.neutral(pm, utils.name(pm, null, i++), function() {
console.log("Add even more custom validation checks here.");
});
Use data validation functions to check data returned by the HTTP response object. Data validation functions are grouped under the utils.expect
namespace in three categories:
- Response validation functions for checking HTTP response data
- Property validation functions for checking object properties
- String validation functions for checking string property values
Response validation functions check the type of data returned in HTTP response. They are grouped under the utils.expect.response
namespace and include:
utils.expect.response.text
: Expects HTTP response to return a simple data type, such as string.utils.expect.response.json
: Expects HTTP response to return any JSON object.utils.expect.response.one
: Expects HTTP response to return a single JSON element.utils.expect.response.many
: Expects HTTP response to return a JSON collection.utils.expect.response.empty
: Expects HTTP response to return an empty JSON collection.utils.expect.response.unique
: Expects HTTP response to return a JSON collection with a single element.utils.expect.response.not.empty
: Expects HTTP response to return a non-empty JSON collection.utils.expect.response.not.unique
: Expects HTTP response to return a JSON collection with two or more items.
Expects HTTP response to return a simple (not the JSON) data type, such as string.
utils.expect.response.text(pm)
Check if the HTTP response data can be initialized as text.
utils.expect.response.text(pm);
Expects HTTP response to return any JSON object. It can be a single element, a collection, an empty collection, basically, anything that comes in a JSON format.
utils.expect.response.json(pm)
Check if the HTTP response data contains a JSON object.
utils.expect.response.json(pm);
Expects HTTP response to return a single JSON element (not a collection and not a collection with a single item).
utils.expect.response.one(pm)
Check if the HTTP response data contains a single JSON element.
utils.expect.response.one(pm);
Expects HTTP response to return a JSON collection (can be empty or contain the specified minimum and/or maximum number of items). The utils.expect.response.many
function can be called via one of these shortcuts:
utils.expect.response.empty
to check for an empty collectionutils.expect.response.unique
to check for a collection with a single (unique) itemutils.expect.response.not.empty
to check for a non-empty collectionutils.expect.response.not.unique
to check for a collection with multiple items
utils.expect.response.many(pm, min = 0, max = -1)
min
: Minimum number of expected items in the collection (default value:0
).max
: Maximum number of expected items in the collection (default value:-1
; indicates that there is no maximum limit).
Check if the HTTP response data contains a JSON collection with at least 2 and at most 10 items.
utils.expect.response.many(pm, 2, 10);
Expects HTTP response to return an empty JSON collection (but not null
).
utils.expect.response.empty(pm)
Check if the HTTP response data contains an empty JSON collection (but not null
).
utils.expect.response.empty(pm);
Expects HTTP response to return a JSON collection with a single element (but not a single element matching the condition of the utils.expect.response.one function).
utils.expect.response.unique(pm)
Check if the HTTP response contains a JSON collection with a single element.
utils.expect.response.unique(pm);
Expects HTTP response to return a non-empty JSON collection (one or more items).
utils.expect.response.not.empty(pm)
Check if the HTTP response data contains a JSON collection with at least one item.
utils.expect.response.not.empty(pm);
Expects HTTP response to return a JSON collection with at least two items.
utils.expect.response.not.unique(pm)
Check if the HTTP response data contains a JSON collection with at least two items.
utils.expect.response.not.unique(pm);
Property validation functions check named properties of the specified objects. The primary benefits of these functions (compared to the underlying Chai assertions they use) is that they (a) always check to make sure that the properties exist before additional validation (so you can skip one test step) and (b) generate more complete error messages on assertion failures (the default assertion errors do not mention named of the properties being checked, which makes them not that useful). Property validation functions are grouped under the utils.expect.property
namespace and include:
utils.expect.property.exist
: Expects the specified object to have a property with the given name.utils.expect.property.equal
: Expects a named property of the specified object to be equal to the specific value.utils.expect.property.not.exist
: Expects the specified object to not have a property with the given name.utils.expect.property.not.equal
: Expects a named property of the specified object to not be equal to the specific value.
The following parameters are common to all property validation functions:
data
: Data object which property is being checked.name
: Name of the property being checked.
Expects the specified object to have a property with the given name.
utils.expect.property.exist(pm, data, name)
Check if the JSON object returned in the HTTP response contains a property id
.
var response = pm.response.json();
utils.expect.property.exist(pm, response, "id");
Expects a named property of the specified object to be equal to the specific value (can be any simple data type, such as boolean, integer, etc.).
utils.expect.property.equal(pm, data, name, value)
value
: Expected property value held by the specified object property (can be any simple data type includingnull
).
Check if the JSON object returned in the HTTP response contains a property active
holding the boolean value of true
.
var response = pm.response.json();
utils.expect.property.equal(pm, response, "active", true);
Expects the specified object to not have a property with the given name.
utils.expect.property.not.exist(pm, data, name)
Check if the JSON object returned in the HTTP response does not contain a property id
.
var response = pm.response.json();
utils.expect.property.not.exist(pm, response, "id");
Expects a named property of the specified object to not be equal to the specific value (can be any simple data type, such as boolean, integer, etc.).
value
: Expected property that the specified object property should not hold (can be any simple data type includingnull
).
Check if the JSON object returned in the HTTP response contains a property active
that does not hold the value of true
.
var response = pm.response.json();
utils.expect.property.not.equal(pm, response, "active", true);
String validation functions are a subset of property validation functions that focus on string properties. They are grouped under the utils.expect.property.string
namespace and include:
utils.expect.property.string.exact
: Expects the named object property to be equal to the specified string value.utils.expect.property.string.partial
: Expects the named object property to be contain the specified string value.utils.expect.property.string.start
: Expects the named object property to start with the specified string value.utils.expect.property.string.end
: Expects the named object property to end with the specified string value.utils.expect.property.string.match
: Expects the named object property to match the specified regular expression.utils.expect.property.string.not.match
: Expects the named object property to not match the specified regular expression.
data
: Data object which string property is being checked.name
: Name of the string property being checked.value
: String value to be checked against (can benull
).
Expects the named object property to be equal to the specified string value.
utils.expect.property.string.exact(pm, data, name, value, ignoreCase)
ignoreCase
: Indicates whether string comparison should be case insensitive (default value:false
).
Check if the JSON object returned in the HTTP response contains the string property name
holding the value of John
(check is case sensitive).
var response = pm.response.json();
utils.expect.property.string.exact(pm, response, "name", "John");
Expects the named object property to be contain the specified string value.
utils.expect.property.string.partial(pm, data, name, value, ignoreCase)
ignoreCase
: Indicates whether string comparison should be case insensitive (default value:false
).
Check if the JSON object returned in the HTTP response contains the string property name
holding the value of John
anywhere in the string, e.g. John Jr.
or Big John
(check is case sensitive).
var response = pm.response.json();
utils.expect.property.string.partial(pm, response, "name", "John");
Expects the named object property to start with the specified string value.
utils.expect.property.string.start(pm, data, name, value, ignoreCase)
ignoreCase
: Indicates whether string comparison should be case insensitive (default value:false
).
Check if the JSON object returned in the HTTP response contains the string property name
holding the value of John
in the beginning of the string, e.g. John Jr.
(check is case sensitive).
var response = pm.response.json();
utils.expect.property.string.start(pm, response, "name", "John");
Expects the named object property to end with the specified string value.
utils.expect.property.string.end(pm, data, name, value, ignoreCase)
ignoreCase
: Indicates whether string comparison should be case insensitive (default value:false
).
Check if the JSON object returned in the HTTP response contains the string property name
holding the value of John
at the end of the string, e.g. Big John
(check is case sensitive).
var response = pm.response.json();
utils.expect.property.string.end(pm, response, "name", "John");
Expects the named object property to match the specified regular expression.
utils.expect.property.string.match(pm, data, name, value)
Check if the JSON object returned in the HTTP response contains the string property name
holding the value that matches a regular expression /^John$/
.
var response = pm.response.json();
utils.expect.property.string.match(pm, response, "name", /^John$/);
Expects the named object property to not match the specified regular expression.
utils.expect.property.string.not.match(pm, data, name, value)
Check if the JSON object returned in the HTTP response contains the string property name
holding the value that doe not match a regular expression /^John$/
.
var response = pm.response.json();
utils.expect.property.string.not.match(pm, response, "name", /^John$/);
Trace functions print trace messages that can indicate the start and end of pre-request and test script execution. You can also customize trace function to print your custom trace messages.
There are three default trace levels:
0
: Trace logs are turned off.1
: Trace logs reflect only script start calls.2
: Trace logs reflect both function start and end calls.
You can use your own custom trace levels higher than level 2.
Trace functions belong to the utils.trace
namespace and are divided into two groups:
- Trace initialization for setting trace level
- Trace logging for writing trace log messages
To set the trace level (which will be stored in an environment variable for the duration of the test collection run), call one of the trace initialization functions from the test collection's pre-request folder (you only need to do this once). Trace initialization functions belong to the utils.trace.set
namespace and include:
utils.trace.set.none(pm)
: Sets trace level to0
.utils.trace.set.minimal(pm)
: Sets trace level to1
.utils.trace.set.default
: Same asutils.trace.set.all(pm)
.utils.trace.set.all(pm)
: Sets trace level to2
.utils.trace.set.custom(pm, level)
: Use this to set any custom trace level (parameterlevel
is expected to hold a positive integer value).
Set trace level to log both start and end of the scrips (when called from the test collection folder's pre-request script).
utils.run.once(pm, "Client_Credentials_Flow_Tests", function() {
utils.trace.set.all(pm);
});
Both, the folder level and the primary test functions already call the trace function to log the start and/or end of the operation, but if you want to add your own trace messages, you can do it via following function:
utils.trace.log(pm, message, level)
The utils.trace.log
function takes the trace message and the log level values. It will compare the log level to the level initialized via one of the utils.trace.set
functions (or the default) and if the specified level is the same or lower than the trace message will be logged; otherwise, it will be suppressed.
The following message will be only printed to console if the trace level is set to the custom value of 3
or higher (e.g. via utils.trace.set.custom(pm, 3)
).
utils.trace.log(pm, "This message will be printed only if current trace level of '3' or higher.", 3);
General-purpose functions include:
utils.name
: Builds the name of the test to be used in primary test functions or elsewhere.utils.wait
: Pauses script execution for the specified number of seconds or milliseconds.utils.stop
: Stops test execution.utils.skip
: Skips test execution to the specified test.
Builds the name of the test to be used in primary test functions or elsewhere. This function is used internally, but you can use it if you need to reference or build a non-default test name (i.e. name of the test that does not match the pm.info.requestName
value).
utils.name(pm, name, suffix)
-
name
: Name of the test. If not specified,pm.info.requestName
will be used. -
suffix
: If specified, the value will be appended to thename
parameter.
Logs name of the request with auto-incremented suffix.
var i = 1;
console.log(utils.name(pm, null, i++));
console.log(utils.name(pm, null, i++));
Pauses script execution for the specified number of seconds or milliseconds.
utils.wait(pm, timeout, seconds = true)
-
timeout
: Sleep/wait time in seconds (default) or milliseconds. -
seconds
: Indicates whether timeout is specified in seconds (default or if the value istrue
) or milliseconds (if the value isfalse
).
Pause execution for 5 seconds.
utils.wait(pm, 5);
Stops test execution.
utils.stop(pm, timeout, seconds = true)
Stop test run.
utils.stop(pm);
Skips test execution to the specified test.
utils.skip(pm, name)
name
: Name of the test case in the running collection which will be executed next.
Skip test execution to the request with the name 'User-Get-Positive-ById'.
utils.skip(pm, "User-Get-Positive-ById");
The undocumented functions and properties are intended for internal use and unless you want to extend or rewrite the framework, you should not care about them.