All Features

Complete reference for every module, assertion operator, and tool in Hephaestus v4.0.

πŸ”¬

Assertion System

assertions map

Per-field assertion rules using a shorthand map. Supports all operators below. Each field can have multiple operators. Conditional logic via when.

  • Use soft: true per-rule to log warning instead of failing
  • Use when: "expression" to conditionally skip
  • Global softFail: true applies soft behavior to all assertions

keysToFind

Simple key existence check. Specify a dot-notation path β€” the engine walks the response body and confirms the key exists (or is absent with ! prefix).

assertions map example
assertions: {
  "data.id":     { exists: true, type: "number" },
  "data.email":  { matches: "@" },
  "data.score":  { gte: 0, lte: 100 },
  "data.name":   { minLen: 1, maxLen: 100 },
  "data.active": {
    eq: true,
    soft: true,   // warning only
    when: "ctx.response.code === 200"
  },
  "data.items":  { type: "array", minLen: 1 },
  "error":       { absent: true },
},

keysToFind: ["data.id", "data.name", "!error"],
exists

Key exists in response

absent

Key must NOT be present

eq

Strict equality

ne

Not equal

gt

Greater than (number)

gte

Greater than or equal

lt

Less than (number)

lte

Less than or equal

type

typeof check

minLen

Min string/array length

maxLen

Max string/array length

includes

String/array includes

matches

Regex or substring match

soft

Log warning, don't fail

when

Conditional skip expression

absent

Must not exist

πŸ“

assertShape Β· assertOrder Β· assertUniquev3.6v3.8

assertShape β€” structural type check

Quick one-liner per field: declare the expected type. Options:

  • "string" "number" "boolean"
  • "object" "array"
  • "absent" β€” field must NOT exist
  • "any" β€” field must exist, any type

assertOrder β€” verify sort direction

Checks that an array is sorted by a field in the given direction ("asc" or "desc"). Specify type: "number" or "string".

assertUnique β€” no duplicatesv3.8

Checks that all values in an array (or sub-field values) are unique. Set by to check a nested field (e.g. "id").

Shape + Order + Unique
assertShape: {
  "data":        "object",
  "data.id":     "number",
  "data.name":   "string",
  "data.items":  "array",
  "data.active": "boolean",
  "error":       "absent",
  "meta":        "any",
},

assertOrder: {
  path:      "data.items",
  by:        "price",
  direction: "asc",
  type:      "number",
},

assertUnique: {
  path: "data.items",
  by:   "id",   // check item.id uniqueness
},
πŸ”’

assertEach β€” array item validationv3.5

Per-item rule validation

Validates every element of an array against a set of rules. Same operator syntax as assertions map. Supports minCount / maxCount for array length, and per-rule soft mode.

Global softFail: true makes all rule violations non-fatal.

assertEach
assertEach: {
  path:     "data.products",
  minCount: 1,
  maxCount: 200,
  rules: {
    "id":       { type: "number", gt: 0 },
    "name":     { type: "string", minLen: 1 },
    "price":    { gte: 0 },
    "category": { exists: true },
    "active":   {
      eq: true,
      soft: true,  // warn only per item
    },
  }
},
πŸ“Έ

Snapshot Regression Testing

How it works

On first run, response body is saved as a baseline in a collection variable. On subsequent runs, the current response is compared against that baseline.

  • strict β€” exact deep equality
  • non-strict β€” structure & types only (ignores new keys)
  • ignorePaths β€” skip dynamic fields (timestamps, IDs)
  • checkPaths β€” only compare specific sub-paths
πŸ“Έ Open Snapshot Viewer β†’
snapshot config
snapshot: {
  enabled:     true,
  mode:        "non-strict",
  ignorePaths: [
    "data.updatedAt",
    "data.requestId",
    "meta.timestamp"
  ],
  checkPaths: ["data.status", "data.type"],
  record: false,  // set true to force-rewrite the baseline (snapshotRecord)
},
πŸ”

Authentication

Basic Auth
auth: {
  enabled: true,
  type: "basic",
  basic: {
    username: "{{user}}",
    password: "{{pass}}"
  }
},
Bearer Token
auth: {
  enabled: true,
  type: "bearer",
  bearer: {
    token: "{{access_token}}"
  }
},
OAuth2 Client Credentials
auth: {
  enabled: true,
  type: "oauth2cc",
  oauth2cc: {
    tokenUrl: "{{tokenUrl}}",
    clientId: "{{clientId}}",
    clientSecret: "{{secret}}",
    scope: "read write",
  }
},
🎲

Random Data & Date Utilsv3.8

ctx.random + randomData
// Option 1: use ctx.random directly in scripts
ctx.random.uuid()          // β†’ "a7f3..."
ctx.random.email()         // β†’ "test42@example.com"
ctx.random.str(8)          // β†’ "xK9mPqRt"
ctx.random.int(1, 100)    // β†’ 42
ctx.random.bool()          // β†’ true/false
ctx.random.pick(['a','b']) // β†’ "a"
ctx.random.date()          // β†’ "2026-04-07"

// Option 2: auto-inject into pm.variables
randomData: {
  "email":   "random.email",
  "userId":  "random.int:1:9999",
  "orderId": "random.uuid",
  "name":    "random.str:10",
}
// β†’ {{email}}, {{userId}}, {{orderId}} in URL/Body
Date Utilities
// Configure in hephaestus.defaults or override
dates: {
  today:          "today",
  tomorrow:       "today+1d",
  yesterday:      "today-1d",
  nextWeek:       "today+7d",
  lastMonth:      "today-1m",
  startOfMonth:   "startOfMonth",
  endOfMonth:     "endOfMonth",
  q1Start:        "startOfQuarter",
}
// β†’ {{today}}, {{tomorrow}} injected as pm.variables
⚑

Resilience & Validationv3.7

retryOnStatus
// Auto-retry on 503 (service unavailable) or 429 (rate limit)
retryOnStatus: {
  statuses:   [503, 429],
  maxRetries: 3,
}
// Uses pm.setNextRequest to loop.
// Assertion pipeline is skipped on intermediate retries.
// Counter auto-cleaned on success.
envRequired
// Pre-flight: halt collection if required vars missing
envRequired: [
  "BASE_URL",
  "API_KEY",
  "CLIENT_SECRET"
]
// Fails fast with clear error message:
// [Hephaestus] ❌ Required env var missing: API_KEY
πŸ“‹

Logging & softFailv3.8

logLevel: "silent"

No console output. Only CI JSON if ci: true. Good for data-driven runs with thousands of iterations.

logLevel: "minimal"

Single-line summary per request: method, URL, status, time. Compact output for watch mode or large test suites.

logLevel: "normal"

Default. Full bordered summary box with response preview, all assertion results, saved variables.

logLevel: "verbose"

Normal + response headers. Useful for debugging auth, CORS, and caching issues.

softFail: true

Global flag. All assertion failures log as warnings instead of failing the Postman test. Overrides per-rule soft.

ci: true

Outputs structured JSON to console alongside human-readable output. Consumed by ci-to-junit.js.

πŸ› οΈ

CLI Tools

πŸ“ docs.js

Generate Markdown API docs from a Postman collection. Your tests become your documentation.

npm run docs -- col.json -o API.md

πŸ“Š summary.js

Rich Newman run summary: per-folder stats, slowest endpoints, most-failed assertions.

npm run summary -- results.json --md

πŸ” compare.js

Diff two Newman runs. Detect regressions, new failures, performance changes. Exit 1 on regression.

npm run compare -- before.json after.json

πŸ‘οΈ watch.js

Auto re-run Newman when collection or env changes. Press R to force rerun. Debounced.

npm run watch -- -c col.json

πŸ“„ generate-report.js

Beautiful self-contained HTML report from Newman JSON. Charts, pass rates, details.

npm run report -- results.json

πŸ“‹ ci-to-junit.js

Convert Newman JSON to JUnit XML for Jenkins, GitLab CI, and other tools.

npm run ci-to-junit -- results.json

πŸ§™ init.js

Interactive setup wizard. Generates defaults.json and environment template.

npm run init

🚚 migrate.js

Scan existing Postman collection and classify which requests need migration to Hephaestus.

npm run migrate -- col.json

🐳 docker-run.sh

Run full Newman + report pipeline in Docker. No local Node.js needed.

bash scripts/docker-run.sh -c col.json

🌍

Localization β€” locale ru Β· env3.9

One engine, two languages

The locale setting selects the language of every user-facing string the engine emits: generated test names, console logs, error messages, and status labels.

  • "ru" β€” default. Byte-identical output to prior releases.
  • "en" β€” the exact same engine, rendered in English.

Nothing about assertions or request behaviour changes β€” only the text you read. Defined in setup/defaults.json, resolved through the shared i18n catalog.

Why default "ru"

Existing suites keep their exact wording β€” test IDs, snapshots, and log-scraping stay stable across the upgrade. Opt into English by setting a single field.

locale
// setup/defaults.json (or per-request override)
locale: "ru",   // default β€” unchanged output

// switch the whole engine to English:
locale: "en",

// affects test names, logs, errors, status labels:
//   ru β†’ "🟒 Бтатус: 200 β€” УспСшно"
//   en β†’ "🟒 Status: 200 β€” OK"
πŸ›‘οΈ

Security Auditv3.9

Response hardening checks

Opt-in module (enabled: false by default). When on, each check emits its own pm.test so failures surface individually.

  • requireHeaders β€” security headers that must be present
  • forbidHeaders β€” headers that must NOT leak (server, tech fingerprints)
  • forbidBodyPatterns β€” strings that must not appear in the body (stack traces, DB errors)
  • checkCors β€” flags a wildcard Access-Control-Allow-Origin combined with Allow-Credentials

Sensible built-in defaults

When enabled without lists, the engine applies OWASP-style defaults: requires HSTS, CSP, X-Frame-Options, X-Content-Type-Options; forbids server, x-powered-by, x-aspnet-version; and scans the body for SQLSTATE, stack traces, ORA-0, and MySQL warnings. Default { enabled: false, checkCors: true }.

securityAudit
securityAudit: {
  enabled:   true,
  checkCors: true,   // wildcard ACAO + credentials
  requireHeaders: [
    "strict-transport-security",
    "content-security-policy",
    "x-frame-options",
    "x-content-type-options",
  ],
  forbidHeaders: [
    "server", "x-powered-by", "x-aspnet-version",
  ],
  forbidBodyPatterns: [
    "SQLSTATE", "stack trace", "ORA-0",
  ],
},
// each check β†’ its own pm.test
⏺️

snapshotRecord β€” force-rewrite baselinev3.9

Rewrite a snapshot in one run

When an endpoint intentionally changes, you need a fresh baseline. Set snapshot.record: true (or top-level snapshotRecord: true), run once, then remove the flag.

  • Ignores the existing snapshot entirely
  • Writes the current response as the new baseline
  • Stored in the collection-vars backend

Snapshot storage

snapshot.storage defaults to "collection-vars", the only backend that works offline. "postman-api" is unavailable offline β€” the engine warns once and falls back to collection-vars automatically.

snapshotRecord
// Step 1 β€” force a new baseline this run:
snapshot: {
  enabled: true,
  record:  true,   // rewrite baseline, ignore old
  storage: "collection-vars",
},

// or the top-level shorthand:
snapshotRecord: true,

// Step 2 β€” run once.
// Step 3 β€” remove the flag; back to compare mode.
πŸ“ˆ

SLA Percentiles β€” summary --slav3.9

Latency percentiles & a hard gate

The summary tool now reports p50 / p90 / p95 / p99 response times across the run. Pass --sla=<ms> to turn it into a gate.

  • Exits 1 when p95 exceeds the budget
  • Failed / no-response executions are excluded so they don't deflate percentiles
  • Drop it into CI to fail builds on latency regressions
summary --sla
# percentiles in the summary output
node scripts/summary.js results.json

# gate the run: fail if p95 > 800ms
node scripts/summary.js results.json --sla=800

# β†’ Response time  p50 120ms  p90 410ms
#                  p95 690ms  p99 1.2s
# β†’ SLA OK: p95 690ms <= 800ms  (exit 0)
πŸ“₯

OpenAPI / Swagger Importv3.9

Spec β†’ Hephaestus collection

Turn an existing API spec into a ready-to-run collection. Reads OpenAPI 3.x and Swagger 2.0 (JSON, or a common YAML subset).

  • One request per path + method
  • expectedStatus pre-filled from the spec's 2xx responses
  • Response schema pre-filled from the spec's schemas
  • Start asserting immediately, no hand-wiring
  • --negative also generates error-path tests

--negative only generates cases the spec lets it actually trigger — withheld auth, a substituted id, an emptied required body, a dropped required parameter. A spec that declares a 400 does not say what makes a request invalid, so no test is invented for it. Each negative request differs from the happy path by exactly one mutation.

openapi
# OpenAPI 3.x or Swagger 2.0 β†’ collection
node bin/hephaestus.js openapi openapi.json

# YAML subset also accepted
node bin/hephaestus.js openapi swagger.yaml

# plus error-path tests
node bin/hephaestus.js openapi openapi.json --negative

# each generated request comes with:
#   expectedStatus  (from 2xx responses)
#   schema          (from spec component schemas)
#
# --negative adds a "<tag> β€” negative" folder:
#   no auth        401/403   (auth disabled in pre-request)
#   unknown id     404       (path parameter substituted)
#   empty body     400/422   (required body sent as {})
#   missing <p>    400/422   (required query parameter dropped)
πŸ”

Snapshots β†’ Postman Examplesv3.9

Saved snapshots become native Examples

The sync-examples tool writes your saved snapshot baselines into a collection's native Postman Example Responses.

  • Turns regression baselines into documentation you can browse in Postman
  • Examples render in the Postman UI and in generated docs
  • Keeps captured responses and the collection in sync
sync-examples
# write saved snapshots into native
# Postman Example Responses
node bin/hephaestus.js sync-examples collection.json

# β†’ each request with a snapshot baseline
#   gains a matching Example Response,
#   visible in the Postman app.
βš’οΈ

New in 4.0v4.0

Engine β€” all opt-in, all off by default

  • graphql β€” GraphQL answers 200 even with an errors[] array; assert noErrors, errorCount/errorContains for negative tests, and dataShape under data.*.
  • snapshot.mode: "structural" β€” compares the response shape (leaf path β†’ type) and ignores values, so volatile timestamps and ids stop causing false diffs while a field added, removed or retyped still fails.
  • retryOnStatus.respectRetryAfter β€” honours the server's Retry-After, waiting up to retryAfterCapMs and refusing to hammer past it.
  • maxBytes β€” a response-size budget; the maxResponseTime for payload size.
  • securityAudit v2 β€” cookieFlags, checkJwt (rejects alg:none and expired tokens) and requireNoStore.
  • Override typo-guard β€” an unknown key warns with a "did you mean"; strictMode: true fails the run so CI blocks on a typo.

Any locale is now selectable

Locale selection was hardcoded to ru/en, so a fully translated third language could never be used. Any locale the catalog carries is now selectable, and npm run check:locales validates a contribution β€” completeness, parameter parity, argument types, status coverage.

CLI β€” gates and local tooling

  • doctor β€” pre-flight: engine integrity, version drift, config sanity.
  • coverage --spec β€” % of an OpenAPI spec your collection covers, with a --min gate.
  • flaky β€” assertions that flap across repeated runs (--fail-on-flaky).
  • trends + summary --history β€” pass-rate and p95 sparklines from a local run log.
  • bench β€” what the engine actually costs per request (~1.6 ms), with a --max-ms budget.
  • mock β€” replay saved snapshots as a local API.
  • generate β€” interactive wizard that prints a ready-to-paste override.
  • panel β€” local dev panel: run history, snapshots, defaults editor, docs.

Every gate exits 1 when it trips β€” see the CI guide.

override
// a few of the new fields
const override = {
    graphql: { noErrors: true },
    snapshot: { enabled: true, mode: "structural" },
    retryOnStatus: {
        statuses: [503, 429],
        respectRetryAfter: true
    },
    maxBytes: 1048576,
    strictMode: true
};