Skip to Content

Assertions

Glubean gives you four verification tools with different failure behavior.

ctx.expect

Soft assertion by default. Several failures can be collected in one run without stopping execution.

ctx.expect(body.role).toBe("admin"); ctx.expect(body.features).toContain("beta-access");

If a particular expectation should stop execution immediately, chain .orFail():

ctx.expect(res).toHaveStatus(200).orFail();

Available matchers

// Equality ctx.expect(x).toBe(y); ctx.expect(x).toEqual(y); // Truthiness ctx.expect(x).toBeTruthy(); ctx.expect(x).toBeFalsy(); ctx.expect(x).toBeNull(); ctx.expect(x).toBeUndefined(); ctx.expect(x).toBeDefined(); // Numeric ctx.expect(n).toBeGreaterThan(5); ctx.expect(n).toBeGreaterThanOrEqual(5); ctx.expect(n).toBeLessThan(10); ctx.expect(n).toBeLessThanOrEqual(10); ctx.expect(n).toBeWithin(1, 10); // Strings & collections ctx.expect(s).toContain("sub"); ctx.expect(s).toMatch(/regex/); ctx.expect(s).toStartWith("pre"); ctx.expect(s).toEndWith("suf"); ctx.expect(arr).toHaveLength(3); // Objects ctx.expect(obj).toMatchObject({ key: "val" }); ctx.expect(obj).toHaveProperty("path.to.key", expectedValue); ctx.expect(obj).toHaveProperties(["a", "b"]); // HTTP responses ctx.expect(res).toHaveStatus(200); await ctx.expect(res).toHaveJsonBody({ key: "val" }); ctx.expect(res).toHaveHeader("content-type", /json/); // Modifiers ctx.expect(x).not.toBe(y); ctx.expect(x).toSatisfy(v => v > 0); ctx.expect(x).toBeType("string");

ctx.assert

Hard assertion. Stops execution immediately on failure.

ctx.assert(res.ok, "Request should succeed"); ctx.assert(body.id > 0, "User ID should be positive", { actual: body.id, expected: "> 0", });

ctx.validate

Schema validation using Zod, Valibot, ArkType, or other parse-style validators.

import { z } from "zod"; const UserSchema = z.object({ id: z.number(), name: z.string(), email: z.string().email(), }); ctx.validate(responseBody, UserSchema, "user response");

contract.http uses ctx.validate under the hood for both expect.schema (response body) and expect.headers (response headers). You rarely need to call it manually inside a contract — the declarative form is preferred.

Response header normalization

When contract.http validates expect.headers, it normalizes the response headers before calling ctx.validate:

  • Keys are lowercased (HTTP spec: header names are case-insensitive)
  • Values keep string | string[] shape (multi-value headers like Set-Cookie come through as arrays)

Your header schema should therefore use lowercase keys:

headers: z.object({ "content-type": z.string().regex(/^application\/json/), "x-request-id": z.string().uuid(), "set-cookie": z.array(z.string()).optional(), }),

If you validate headers manually via ctx.validate(res.headers, schema, label), the raw res.headers object is not pre-normalized — you’d need to lowercase-transform it yourself. Prefer expect.headers in contract.http cases.

ctx.warn

Non-failing tests for budgets and best-practice monitoring:

ctx.warn(durationMs < 500, "Response should stay under 500ms");

Warnings are visible in the Result Viewer and Cloud dashboard without failing the run.

Next

Last updated on