Skip to content

Vayu Scripting Guide

Vayu uses QuickJS for JavaScript execution in pre-request and test scripts. The scripting API is compatible with Postman's pm object, making it easy to migrate tests from Postman.

Quick Start

// Test script example
pm.test('Status is 200', function() {
  pm.expect(pm.response.code).to.equal(200);
});

pm.test('Response has user data', function() {
  const json = pm.response.json();
  pm.expect(json).to.have.property('id');
  pm.expect(json.name).to.be.a('string');
});

The pm Object

pm.test()

Define a test with assertions.

pm.test('Test name', function() {
  // Assertions here
});

pm.expect()

Create Chai-style expectations for assertions.

pm.expect(value).to.equal(expected);
pm.expect(value).to.not.equal(expected);
pm.expect(value).to.be.true;
pm.expect(value).to.be.false;
pm.expect(value).to.be.null;
pm.expect(value).to.be.undefined;
pm.expect(value).to.exist;
pm.expect(value).to.be.a('string');
pm.expect(value).to.be.an('array');
pm.expect(value).to.include(item);
pm.expect(value).to.have.length(n);
pm.expect(value).to.be.above(n);
pm.expect(value).to.be.below(n);
pm.expect(value).to.have.property('key');

Response Object (pm.response)

Access HTTP response data:

pm.response.code              // Status code (number, e.g., 200)
pm.response.status            // Alias for code
pm.response.responseTime      // Perceived latency in ms (submit → completion).
                              // In load tests this includes generator-side
                              // queue wait. For pure server wire time, use
                              // responseTimeWire.
pm.response.responseTimeWire  // CURLINFO_TOTAL_TIME in ms - DNS + TCP + TLS +
                              // send + recv. Matches the pre-v0.3 meaning of
                              // responseTime; use this to assert on server SLAs
                              // independent of generator load.
pm.response.responseTimeQueueWait // Generator-side queue overhead in ms,
                              // i.e. responseTime − responseTimeWire (clamped
                              // to >= 0). For single-shot sends this is ~0.
pm.response.headers           // Headers object (lowercase keys)
pm.response.body              // Raw body string
pm.response.text()            // Body as string
pm.response.json()            // Parse JSON (throws if invalid)

Response Assertions

pm.response.to.have.status(200);
pm.response.to.have.header('Content-Type');
pm.response.to.have.jsonBody();

Request Object (pm.request)

Access request data:

pm.request.method            // HTTP method (string)
pm.request.url               // Full URL (string)
pm.request.headers           // Request headers (object)
pm.request.body              // Request body (string, if any)

Environment Variables (pm.environment)

Access and modify environment variables:

// Get variable
const token = pm.environment.get('auth_token');

// Set variable (persists to environment)
pm.environment.set('auth_token', 'new_token_value');

Variables (pm.variables)

Access collection and global variables:

// Get variable (searches: environment → collection → global)
const value = pm.variables.get('baseUrl');

// Set variable
pm.variables.set('baseUrl', 'https://api.example.com');

Variable Resolution Order: 1. Environment variables 2. Collection variables 3. Global variables

Console Output

Log messages that appear in test results:

console.log('Response:', pm.response.json());
console.info('Info message');
console.warn('Warning message');
console.error('Error message');

Examples

Validate JSON Response

pm.test('User has correct fields', function() {
  const json = pm.response.json();
  pm.expect(json).to.have.property('id');
  pm.expect(json.name).to.be.a('string');
  pm.expect(json.email).to.include('@');
});

Check Status Codes

pm.test('Success response', function() {
  pm.expect(pm.response.code).to.be.below(400);
});

Set Variables from Response

// Extract token from response and save to environment
const json = pm.response.json();
pm.environment.set('userId', json.id);
pm.environment.set('token', json.token);

Pre-request Script

Modify request before sending:

// Add timestamp header
pm.request.headers['X-Timestamp'] = Date.now().toString();

// Add signature header
const secret = pm.environment.get('secret');
const data = pm.request.body + secret;
pm.request.headers['X-Signature'] = computeHash(data);

Response Time Assertion

pm.test('Response time is acceptable', function() {
  pm.expect(pm.response.responseTime).to.be.below(1000);
});

Array Validation

pm.test('Returns array of users', function() {
  const users = pm.response.json();
  pm.expect(users).to.be.an('array');
  pm.expect(users.length).to.be.above(0);
  pm.expect(users[0]).to.have.property('id');
});

Header Validation

pm.test('Has Content-Type header', function() {
  pm.response.to.have.header('Content-Type');
  pm.expect(pm.response.headers['content-type']).to.include('application/json');
});

Limitations

QuickJS supports ES2020 features with some limitations:

  • No ES2021+ features: No optional chaining (?.), nullish coalescing (??), etc.
  • No Node.js APIs: No require(), fs, http, etc.
  • Sandboxed: No filesystem or network access
  • Memory limit: 64MB per script execution
  • Timeout: 5 seconds per script (default), enforced by a wall-clock deadline - an infinite-loop script is aborted and reported as an error rather than hanging the engine. Configurable via the scriptTimeout setting (milliseconds); 0 disables the limit.

Script Execution Context

Pre-request Scripts

  • Execute before sending the HTTP request
  • Can modify pm.request (headers, body)
  • Can access pm.environment and pm.variables
  • Cannot access pm.response (request hasn't been sent yet)

Test Scripts (Post-request)

  • Execute after receiving the HTTP response
  • Can access pm.request and pm.response
  • Can access pm.environment and pm.variables
  • Test results are included in the response

Load Test Scripts

  • Test scripts in load tests are executed deferred (after test completion)
  • Only a sample of responses are validated (configurable)
  • Results are aggregated and reported in the final report
  • POST /runs's tests field carries the collection chain's test scripts as well as the request's own, composed the same way as POST /execute (see Script Parts below) - a collection-level assertion is now checked under load, not only in design mode

Script Parts

A script's effective source is composed of parts: the collection chain's own script, then the request's own script, in that order. Each route accepts its own field(s), each in either of two forms:

  • POST /execute takes preRequestScript / postRequestScript (legacy single string, already-joined text) or preRequestScripts / postRequestScripts (a list of parts). The load path (POST /runs) does not read either of these two keys.
  • POST /runs takes tests (the deferred validation script), either as a legacy single string or as a list of parts. POST /execute does not read tests.

A list of parts is an array of objects, each recording where it came from - { "origin": "collection" | "request", "id": "...", "name": "...", "script": "..." } - so a stored run can say which part is whose.

When both the list and the legacy string are sent for the same field, the list wins; they are never merged. Parts that are empty or only whitespace are dropped.

The parts are joined with a blank line ("\n\n") and run as a single script in one shared JavaScript scope - one call to the script engine per field (engine.execute() for preRequestScript(s) / postRequestScript(s), engine.execute_test() for tests), not one call per part. That means a const or let declared in the collection's part is visible to the request's part, exactly as if one person had typed the whole thing into one editor. It also means a syntax error's reported line number is counted from the start of the joined text, not from the start of whichever part actually has the mistake.

Error Handling

Script errors are caught and reported:

// If script throws, error is captured
try {
  const json = pm.response.json();
} catch (e) {
  // Error is reported in test results
}

Test failures don't stop script execution - all tests run and results are collected.

Best Practices

  1. Use descriptive test names: pm.test('Status code is 200', ...)
  2. Validate structure before accessing: Check if JSON exists before accessing properties
  3. Use environment variables: Store sensitive data in environments, not scripts
  4. Keep scripts simple: Complex logic should be in your application code
  5. Log debugging info: Use console.log() to debug script issues

API Reference

For complete API documentation, see the Scripting Completions API which lists all available pm.* functions and properties.