Documentation Index
Fetch the complete documentation index at: https://bruno-a6972042-mintlify-testing-jsonbody-jsonschema-1777266.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Bruno uses the Chai library ↗ for assertions. All Chai expect syntax works in Bruno tests.
Write JavaScript test scripts to validate API responses, handle complex logic, and automate testing workflows.
Basic Test Structure
test("test name", function () {
expect(res.getStatus()).to.equal(200);
});
Common Test Examples
Testing Status Codes
test("should return success", function () {
expect(res.getStatus()).to.equal(200);
});
test("should not return server error", function () {
expect(res.getStatus()).to.not.equal(500);
});
Testing Response Body
test("should return user data", function () {
const body = res.getBody();
expect(body).to.have.property("id");
expect(body.name).to.equal("John Doe");
expect(body.email).to.contain("@example.com");
});
test("should return array of users", function () {
const users = res.getBody();
expect(users).to.be.an("array");
expect(users).to.have.lengthOf(3);
expect(users[0]).to.have.property("id");
});
Testing Nested Objects
test("should validate nested user profile", function () {
const body = res.getBody();
expect(body.user.profile.name).to.equal("Alice");
expect(body.user.settings.theme).to.equal("dark");
expect(body.user.settings.notifications).to.be.true;
});
Testing with Conditional Logic
test("should validate response based on status", function () {
const status = res.getStatus();
const body = res.getBody();
if (status === 200) {
expect(body).to.have.property("data");
expect(body.data).to.not.be.empty;
} else if (status === 404) {
expect(body).to.have.property("error");
expect(body.error.message).to.contain("not found");
} else {
throw new Error(`Unexpected status code: ${status}`);
}
});
test("should validate user role permissions", function () {
const body = res.getBody();
if (body.user.role === "admin") {
expect(body.user.permissions).to.include("write");
expect(body.user.permissions).to.include("delete");
} else if (body.user.role === "user") {
expect(body.user.permissions).to.include("read");
expect(body.user.permissions).to.not.include("delete");
}
});
Testing Arrays and Loops
test("should validate all users have required fields", function () {
const users = res.getBody();
users.forEach((user) => {
expect(user).to.have.property("id");
expect(user).to.have.property("email");
expect(user.email).to.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
});
});
test("should find user by id", function () {
const users = res.getBody();
const targetUser = users.find((u) => u.id === 123);
expect(targetUser).to.exist;
expect(targetUser.name).to.equal("John");
});
test("should have correct content type", function () {
expect(res.getHeader("content-type")).to.contain("application/json");
});
test("should include authentication headers", function () {
expect(res.getHeader("x-api-key")).to.exist;
expect(res.getHeader("authorization")).to.not.be.empty;
});
Testing Response Time
test("should respond quickly", function () {
expect(res.getResponseTime()).to.be.lessThan(1000);
});
Advanced: Saving Values for Next Request
test("should save token for next request", function () {
const body = res.getBody();
expect(body).to.have.property("token");
expect(body.token).to.not.be.empty;
// Save token to environment variable
bru.setVar("authToken", body.token);
});
test("should extract and save user ID", function () {
const body = res.getBody();
if (body.users && body.users.length > 0) {
const firstUserId = body.users[0].id;
bru.setVar("userId", firstUserId);
}
});
Error Handling
test("should handle missing fields gracefully", function () {
const body = res.getBody();
if (!body.data) {
expect(body).to.have.property("error");
expect(body.error.code).to.be.oneOf([400, 404, 422]);
}
});
test("should validate error response structure", function () {
const status = res.getStatus();
if (status >= 400) {
const body = res.getBody();
expect(body).to.have.property("error");
expect(body.error).to.have.property("message");
expect(body.error.message).to.be.a("string");
}
});
Common Chai Assertions
// Equality
expect(value).to.equal(expected);
expect(value).to.not.equal(expected);
expect(value).to.eql(expected); // deep equality
// Type checking
expect(value).to.be.a("string");
expect(value).to.be.an("array");
expect(value).to.be.true;
expect(value).to.be.null;
// Property checks
expect(obj).to.have.property("key");
expect(obj).to.have.all.keys("name", "email");
// String checks
expect(str).to.contain("substring");
expect(str).to.match(/regex/);
// Number comparisons
expect(num).to.be.above(10);
expect(num).to.be.below(100);
expect(num).to.be.within(10, 100);
// Array checks
expect(arr).to.be.an("array");
expect(arr).to.have.lengthOf(3);
expect(arr).to.include("item");
expect(arr).to.be.empty;
Bruno-specific assertions
In addition to the standard Chai assertions, Bruno registers custom assertions for working with JSON response bodies.
jsonBody
Use jsonBody to validate the response body against a value or to check for the existence of a nested property. This assertion mirrors Postman’s pm.response.to.have.jsonBody(...) API and is convenient for collections imported from Postman.
test("body is valid JSON", function () {
// Passes when the body is a JSON object or array
expect(res.getBody()).to.have.jsonBody();
});
test("body deep equals expected object", function () {
expect(res.getBody()).to.have.jsonBody({
id: 1,
name: "Alice"
});
});
test("body has a nested property", function () {
// Supports dot notation, numeric brackets, and quoted bracket keys
expect(res.getBody()).to.have.jsonBody("user.profile.email");
expect(res.getBody()).to.have.jsonBody("items[0].id");
expect(res.getBody()).to.have.jsonBody('data["a.b"].name');
});
test("nested property equals value", function () {
expect(res.getBody()).to.have.jsonBody("user.profile.name", "Alice");
});
test("body should not have property", function () {
expect(res.getBody()).to.not.have.jsonBody("error");
});
| Call | Behavior |
|---|
jsonBody() | Asserts the body is a JSON object or array |
jsonBody(object) | Deep equality against the supplied object |
jsonBody("path") | Asserts the nested property exists |
jsonBody("path", value) | Asserts the nested property equals the supplied value |
All variants support negation via .not (for example, to.not.have.jsonBody("key")).
jsonSchema
Use jsonSchema to validate a response body against a JSON Schema. Bruno uses Ajv under the hood, so any JSON Schema draft supported by Ajv works here. An optional second argument forwards options to the Ajv instance.
test("body matches schema", function () {
const schema = {
type: "object",
required: ["id", "name", "email"],
properties: {
id: { type: "number" },
name: { type: "string" },
email: { type: "string", format: "email" }
}
};
expect(res.getBody()).to.have.jsonSchema(schema);
});
test("body matches schema with Ajv options", function () {
const schema = {
type: "object",
properties: {
createdAt: { type: "string", format: "date-time" }
}
};
// Pass Ajv options as the second argument
expect(res.getBody()).to.have.jsonSchema(schema, { strict: false });
});
When the body fails validation, the assertion error includes the Ajv validation errors so you can quickly see which fields are missing or have the wrong type.
Next Steps
For more advanced scripting capabilities, see: