Scripting and Testing

Writing Tests

Writing Tests

Test scripts run automatically after a response is received and verify that the response matches what you expected. Write them once; they run every time — both when you click Send manually and when the Collection Runner executes the request as part of an automated suite.


The Basics

Open any request, go to the Scripts tab, and write in the Test Script editor (the bottom half).

Every test follows the same pattern:

fc.test("A name that describes what you are checking", function () {
    // assertion goes here
    fc.expect(someValue).to.equal(expectedValue);
});
  • The name is what appears in the Test Results panel. Make it descriptive enough that a failure message is self-explanatory.
  • The function contains one or more assertions.
  • If any assertion inside the function throws, the test is marked failed with the error message. If no assertion throws, the test is marked passed.

You can write as many fc.test() blocks as you need.


The fc Object

The fc object is the entire test scripting API. It is also available as pm — both names refer to the same object, so Postman scripts work without modification.


Accessing the Response

fc.response.code

The HTTP status code as a number:

fc.test("Status is 200", function () {
    fc.expect(fc.response.code).to.equal(200);
});

fc.response.status

The HTTP status text as a string ("OK", "Not Found", "Internal Server Error", etc.):

fc.test("Status text is OK", function () {
    fc.expect(fc.response.status).to.equal("OK");
});

fc.response.responseTime

Round-trip time in milliseconds:

fc.test("Responds in under 1 second", function () {
    fc.expect(fc.response.responseTime).to.be.below(1000);
});

fc.response.text()

The raw response body as a string:

fc.test("Body mentions success", function () {
    fc.expect(fc.response.text()).to.include("success");
});

fc.response.json()

The response body parsed as JSON. Throws if the body is not valid JSON:

fc.test("User has an email", function () {
    var body = fc.response.json();
    fc.expect(body.email).to.exist;
});

fc.response.headers.get("header-name")

Get the value of a specific response header. Header names are case-insensitive:

var contentType = fc.response.headers.get("content-type");
fc.expect(contentType).to.include("application/json");

Response Assertion Shorthands

These shorthands wrap the most common checks in readable form:

// Status code
fc.response.to.have.status(200);
fc.response.to.have.status("OK");   // by status text

// Header presence (any value)
fc.response.to.have.header("x-request-id");

// Header with specific value
fc.response.to.have.header("content-type", "application/json");

// Body contains substring
fc.response.to.have.body("logged in");

// Status class shortcuts
fc.response.to.be.ok;           // any 2xx
fc.response.to.be.accepted;     // 202
fc.response.to.be.badRequest;   // 400
fc.response.to.be.unauthorized; // 401
fc.response.to.be.forbidden;    // 403
fc.response.to.be.notFound;     // 404
fc.response.to.be.serverError;  // any 5xx

JSON Body Assertions

Checking a nested field

fc.response.to.have.jsonBody(path) navigates into the JSON and returns a Chai assertion on that value. Use dot notation for nesting:

fc.test("User's city is London", function () {
    fc.response.to.have.jsonBody("address.city").that.equals("London");
});

JSON Schema Validation

The most powerful body assertion — validates the entire response against a JSON Schema definition. This catches structural changes: a field being renamed, a type changing from string to number, a required field disappearing.

fc.test("Response matches schema", function () {
    fc.response.to.have.jsonSchema({
        type: "object",
        required: ["id", "name", "email"],
        properties: {
            id:    { type: "integer" },
            name:  { type: "string", minLength: 1 },
            email: { type: "string", format: "email" },
            age:   { type: "integer", minimum: 0 }
        },
        additionalProperties: false
    });
});

If validation fails, the error message lists every property that did not match:

JSON Schema validation failed:
/email: must match format "email"
/age: must be >= 0

fc.expect — Chai Assertions

fc.expect(value) creates a Chai assertion chain. The full Chai API is available.

Equality

fc.expect(value).to.equal(expected)      // strict equality (===)
fc.expect(value).to.eql(expected)        // deep equality (objects, arrays)
fc.expect(value).to.not.equal(other)     // negation — add .not. anywhere

Existence and type

fc.expect(value).to.exist               // not null and not undefined
fc.expect(value).to.be.null
fc.expect(value).to.be.undefined
fc.expect(value).to.be.true
fc.expect(value).to.be.false
fc.expect(value).to.be.a("string")
fc.expect(value).to.be.a("number")
fc.expect(value).to.be.a("object")
fc.expect(value).to.be.an("array")

Numbers

fc.expect(number).to.be.above(100)       // number > 100
fc.expect(number).to.be.below(500)       // number < 500
fc.expect(number).to.be.at.least(100)    // number >= 100
fc.expect(number).to.be.at.most(500)     // number <= 500
fc.expect(number).to.be.within(100, 500) // 100 <= number <= 500

Strings and arrays

fc.expect(string).to.include("substring")
fc.expect(array).to.include(element)
fc.expect(array).to.have.length(3)
fc.expect(array).to.have.lengthOf.at.least(1)

Objects

fc.expect(object).to.have.property("key")
fc.expect(object).to.have.property("key", "expectedValue")
fc.expect(object).to.have.nested.property("user.address.city")
fc.expect(object).to.include({ name: "Alice" })

Multiple valid values

fc.expect(fc.response.code).to.be.oneOf([200, 201, 204])

Working with Variables

Test scripts often extract values from responses and save them for use in subsequent requests — the classic case is logging in and storing the access token.

Read from the active environment

var baseUrl = fc.environment.get("baseUrl");

Write to the active environment

var token = fc.response.json().access_token;
fc.environment.set("authToken", token);

Variables written in a test script are immediately available to all subsequent requests in the same Collection Runner run. Add {{authToken}} to the Authorization header of every downstream request.

Collection variables (scoped to the collection)

var sessionId = fc.collectionVariables.get("sessionId");
fc.collectionVariables.set("sessionId", fc.response.json().session_id);

Read data file values (Collection Runner only)

var expectedStatus = parseInt(fc.iterationData.get("expected_status"));
fc.test("Returns expected status", function () {
    fc.expect(fc.response.code).to.equal(expectedStatus);
});

Flow Control

Inside a test script you can influence what runs next in the Collection Runner:

// Jump to a specific request by its exact name
fc.execution.setNextRequest("Cleanup — Delete User");

// Skip the next request in the sequence
fc.execution.skipRequest();

// Stop the entire run immediately
fc.execution.abort();

These are most useful for conditional flows — for example, if a required setup step fails, jump directly to cleanup rather than continuing through requests that depend on it.


Logging and Debugging

Use console.log() to print values while the script runs. Output appears in the Console panel (`Cmd/Ctrl + ``) and in the Test Results detail view.

var body = fc.response.json();
console.log("Response id:", body.id);
console.log("Full body:", JSON.stringify(body, null, 2));

The raw response body is also available directly in the script scope as the responseBody string variable — useful as a fallback if fc.response.json() would throw:

console.log("Raw response:", responseBody);
try {
    var parsed = JSON.parse(responseBody);
    fc.expect(parsed.status).to.equal("ok");
} catch (e) {
    fc.test("Response is valid JSON", function() {
        throw new Error("Could not parse response as JSON: " + e.message);
    });
}

Test Results Structure

Each fc.test() call produces one row in the Test Results panel:

StateWhat it means
✅ GreenThe function completed without throwing
❌ RedAn assertion threw an error — the error message is shown

A summary at the top shows the total pass and fail count. When you run requests via the Collection Runner, the Tests column in the results table shows the pass/fail counts per request at a glance.


Postman Compatibility

Scripts written using the Postman pm API run without any changes. pm is a complete alias for fc:

// All of these are identical
pm.test("name", function() { ... });
fc.test("name", function() { ... });

pm.expect(value).to.equal(x);
fc.expect(value).to.equal(x);

pm.environment.set("key", "val");
fc.environment.set("key", "val");

If you are importing collections from Postman, your existing test scripts continue to work as-is.