Scripts & pm APIs
Pre-req and Post-res scripts
-
The Postman format lets you write custom JavaScript in pre-req and post-res tabs that execute before and after a step respectively. When you export the collection, these scripts come bundled.
-
ReṼoman executes this JavaScript on the JVM. This ensures the same API metadata used for manual testing can be used as-is for automation — no resistance to modify, no overhead of separate manual/automation versions.
-
Pre-req JS runs first, before unmarshalling the request.
-
Post-res JS runs right after receiving an HTTP response.
-
npm modules with require(…)
ReṼoman supports using npm modules inside your pre-req and post-res JS. Install modules in any folder with npm install <module>, supply the parent folder of node_modules to the Kick config via nodeModulesPath(…) (absolute, or relative to the project directory), and require(…) them:
moment with npmnpm install moment
var moment = require("moment")
var _ = require('lodash')
pm.environment.set("$currentDate", moment().format(("YYYY-MM-DD")))
var futureDateTime = moment().add(365, 'days')
pm.environment.set('$randomFutureDate', futureDateTime.format('YYYY-MM-DD'))
pm.environment.set("$quantity", _.random(1, 10))
Loading node_modules from a jar is not supported. For example, /Users/username/some-path/revoman-root/build/libs/revoman-root-0.40.0.jar!/js is an invalid path. (See this known issue.)
|
|
| Don’t add too much code in pre-req/post-res scripts — it’s not intuitive to troubleshoot via debugging. Use them for simple operations understandable without debugging, and use Pre-Step/Post-Step Hooks for non-trivial operations (which are intuitive to debug). |
Supported pm script APIs
ReṼoman runs your collection’s pre-request and post-response JavaScript on the JVM through a real Postman-compatible sandbox. The following script-only pm APIs are supported and surface their effects on the Rundown:
| API | Behavior in ReṼoman |
|---|---|
|
Reads/writes flow into the mutable environment. Surfaced on |
|
Collection-scoped key/value store; values set in one step’s script are visible to later steps' scripts. Surfaced on |
|
Global-scoped key/value store; like |
|
Aggregate read view across all scopes, honoring Postman precedence ( |
|
Request/response fed into the script context. |
|
Assertion results recorded on |
|
Control-flow directives; now honored — see Control-flow directives. |
All three persistent scopes — pm.environment, pm.collectionVariables, pm.globals — are also resolved in {{key}} variable substitution, by the same precedence. Only the environment scope feeds the mutable environment and the warm-run ledger; collectionVariables and globals are sibling stores.
Two read-only fields on each StepReport expose script outcomes:
-
pmTestAssertions: List<PmTestAssertion>— everypm.test(…)result across the step’s pre-request and post-response scripts.PmTestAssertioncarriesname,passed,skipped,error, andexeType(the producing phase:PRE_REQ_JSorPOST_RES_JS). -
pmTestFailure: List<PmTestFailure>— the failed assertions of this step, grouped by phase (0–2 entries, pre-request first). Always populated when any assertion failed, independent of `failure’s precedence — see A failingpm.testfails the step. -
nextRequest: String?— the value passed topm.execution.setNextRequest(…), if any (honored by the sequencer).
Control-flow directives
ReṼoman now honors pm.execution.setNextRequest(name) (jump to a named step), setNextRequest(null) (stop the run), and pm.execution.skipRequest() (skip HTTP dispatch in pre-request scripts). These let your scripts implement conditional logic, loops, and early exits.
-
Jump:
pm.execution.setNextRequest("Step Name")causes the next executed step to be the named step (case-sensitive match on the step’snamefield). A jump disables the ledger warm-path from the divergence point onward. -
Stop:
pm.execution.setNextRequest(null)stops the run immediately after the current step.Rundown.stopReasonwill beSTOPPED_BY_DIRECTIVE. -
Skip:
pm.execution.skipRequest()(pre-request only) skips the HTTP dispatch for the current step; the step succeeds with no request/response. Post-response scripts are also skipped; the run continues with the next step.
Loops are bounded by the maxStepExecutionFactor Kick knob (default 10): if a run executes more than factor × collectionStepCount steps, it halts with Rundown.stopReason = LOOP_BUDGET_EXCEEDED. The terminal reason for any run appears on Rundown.stopReason (COMPLETED / STOPPED_BY_DIRECTIVE / HALTED_ON_FAILURE / LOOP_BUDGET_EXCEEDED).
-
pm.sendRequestis not supported. -
Collection-root
variable[]is not parsed;pm.collectionVariablesandpm.globalsare script-seeded only (a producer step’s script `.set`s a value, a downstream step reads it).
// --- pm.collectionVariables set in step 1, read in steps 2-3 (cross-step) ---
final StepReport byName = rundown.reportForStepName("pokemon-by-name");
assertThat(byName).isNotNull();
assertThat(byName.pmTestAssertions).isNotEmpty();
assertThat(byName.pmTestAssertions.stream().allMatch(a -> a.passed)).isTrue();
// --- pm.execution.setNextRequest: CAPTURED (not executed — Phase 2 reorders) ---
// ReVoman still runs steps linearly; we assert only that the directive was surfaced.
assertThat(byName.nextRequest).isEqualTo("pokemon-species");
// Proof it was NOT executed: pokemon-species still ran in linear order after pokemon-by-name.
assertThat(rundown.reportForStepName("pokemon-species")).isNotNull();
// Guard the crown-jewel cross-step collectionVariable proof against silently vanishing:
// a failing pm.test is DATA (passed=false), and allMatch on an empty list passes vacuously, so
// assert this step actually produced assertions.
assertThat(rundown.reportForStepName("pokemon-species").pmTestAssertions).isNotEmpty();
These script outcomes land on the Rundown; environment reads and writes flow through the mutable environment; and for logic too involved for a pre-req/post-res script, reach for Hooks instead.
A failing pm.test fails the step
A failing pm.test(…) assertion fails its step — and therefore the Rundown — matching Postman/newman semantics. By default the run continues to the next step (the step is simply marked failed); set haltOnAnyFailure(true) to fail-fast.
A pm.test failure carries the ExeType of the phase that produced it — PRE_REQ_JS or POST_RES_JS — so you can exempt it from halting via haltOnFailureOfTypeExcept(POST_RES_JS) { stepReport, rundown → … } (or PRE_REQ_JS), exactly as for a script error.
When both an HTTP/transport failure and a pm.test failure occur on the same step, both are surfaced: StepReport.failure carries the higher-precedence HTTP/transport cause (so a redundant pm.test('status 200') does not mask the real non-2xx response), while StepReport.pmTestFailure independently lists the assertion failures. skipped assertions (pm.test.skip) never contribute to failure.
Per-assertion results — including exeType — appear in the JSON Rundown under each step’s pmTestAssertions.