@probitas-test/core

Core scenario definition types and utilities.

This package provides the fundamental type definitions that represent scenario structures, along with utilities for loading scenario files and filtering scenarios using selectors. It serves as the foundation layer that other Probitas packages build upon.

PackageDescription
@probitas-test/builderUses these types to build scenarios
@probitas-test/runnerExecutes scenario definitions
@probitas-test/discoverDiscovers scenario files to load

Type Definitions

The type system is designed around immutable data structures:

Options Types

  • ScenarioOptions - Scenario-level configuration (tags, default step options)
  • StepOptions - Step execution settings (timeout, retry strategy)
  • Import Origin from @probitas-test/core/origin for file and line information

Function Types

Loader Utilities

Selector Utilities

Selectors provide powerful filtering capabilities:

Installation

npm install @probitas-test/core

Interfaces

interface

#ScenarioDefinition

interface ScenarioDefinition

Complete, immutable definition of a scenario.

This is the core type produced by the builder and consumed by the runner. It contains everything needed to execute a scenario: its name, options, and ordered sequence of entries (steps, resources, setups).

Scenario definitions are:

  • Immutable: The entries array is frozen after creation
  • Self-contained: All options have defaults applied
  • Portable: Can be serialized (minus functions) for tooling
Examples

Typical scenario structure

import type { ScenarioDefinition } from "@probitas-test/core";

// Created by: scenario("Login Flow").step(...).build()
const definition: ScenarioDefinition = {
  name: "Login Flow",
  tags: ["auth", "smoke"],
  steps: [
    {
      kind: "resource",
      name: "api",
      fn: () => fetch,
      timeout: 30000,
      retry: { maxAttempts: 1, backoff: "linear" },
    },
    {
      kind: "step",
      name: "Login",
      fn: () => {},
      timeout: 30000,
      retry: { maxAttempts: 1, backoff: "linear" },
    },
    {
      kind: "step",
      name: "Verify",
      fn: () => {},
      timeout: 30000,
      retry: { maxAttempts: 1, backoff: "linear" },
    },
  ],
  origin: { path: "/tests/auth.probitas.ts", line: 5 },
};
console.log(definition);
NameDescription
nameHuman-readable scenario name (displayed in reports and CLI)
originOrigin where the scenario was defined
stepsOrdered sequence of entries (resources → setups → steps)
tagsTags for filtering and organizing scenarios.
timeoutMaximum time in milliseconds for the entire scenario to complete.
Properties
  • readonlynamestring

    Human-readable scenario name (displayed in reports and CLI)

  • readonlyorigin?Origin

    Origin where the scenario was defined

  • readonlystepsreadonly StepDefinition<unknown>[]

    Ordered sequence of entries (resources → setups → steps)

  • readonlytagsreadonly string[]

    Tags for filtering and organizing scenarios.

    Tags can be used with the CLI to run specific subsets:

    probitas run -s "tag:api"           # Run scenarios tagged "api"
    probitas run -s "tag:api,tag:fast"  # Run scenarios with both tags
    probitas run -s "!tag:slow"         # Exclude slow scenarios
    
  • readonlytimeout?number

    Maximum time in milliseconds for the entire scenario to complete.

    When set, overrides the RunOptions timeout for this specific scenario. When timeout occurs, a ScenarioTimeoutError is thrown.

interface

#ScenarioMetadata

interface ScenarioMetadata

Serializable scenario metadata (without executable functions).

Used by the JSON reporter and tooling to output scenario information without including non-serializable function references.

Examples

JSON reporter output

{
  "name": "Login Flow",
  "options": { "tags": ["auth"], "stepOptions": { ... } },
  "entries": [
    { "kind": "step", "value": { "name": "Login", "options": { ... } } }
  ],
  "origin": { "path": "/tests/auth.probitas.ts", "line": 5 }
}
NameDescription
nameScenario name
originOrigin where the scenario was defined
stepsEntry metadata (functions omitted for serialization)
tagsTags for filtering and organizing scenarios.
timeoutMaximum time in milliseconds for the entire scenario to complete.
Properties
  • readonlynamestring

    Scenario name

  • readonlyorigin?Origin

    Origin where the scenario was defined

  • readonlystepsreadonly StepMetadata[]

    Entry metadata (functions omitted for serialization)

  • readonlytagsreadonly string[]

    Tags for filtering and organizing scenarios.

    Tags can be used with the CLI to run specific subsets:

    probitas run -s "tag:api"           # Run scenarios tagged "api"
    probitas run -s "tag:api,tag:fast"  # Run scenarios with both tags
    probitas run -s "!tag:slow"         # Exclude slow scenarios
    
  • readonlytimeout?number

    Maximum time in milliseconds for the entire scenario to complete.

    When set, overrides the RunOptions timeout for this specific scenario.

interface

#ScenarioOptions

interface ScenarioOptions

Configuration options for scenario execution.

Defines metadata and default behavior for an entire scenario.

Examples
const options: ScenarioOptions = {
  tags: ["api", "integration", "slow"],
  timeout: 30000,
  stepOptions: {
    timeout: 60000,
    retry: { maxAttempts: 2, backoff: "linear" }
  }
};
NameDescription
stepOptionsDefault options applied to all steps in this scenario.
tagsTags for filtering and organizing scenarios.
timeoutMaximum time in milliseconds for the entire scenario to complete.
Properties
  • readonlystepOptions?StepOptions

    Default options applied to all steps in this scenario.

    Individual steps can override these defaults by specifying their own options in the .step() call.

  • readonlytags?readonly string[]

    Tags for filtering and organizing scenarios.

    Tags can be used with the CLI to run specific subsets:

    probitas run -s "tag:api"           # Run scenarios tagged "api"
    probitas run -s "tag:api,tag:fast"  # Run scenarios with both tags
    probitas run -s "!tag:slow"         # Exclude slow scenarios
    
  • readonlytimeout?number

    Maximum time in milliseconds for the entire scenario to complete.

    When specified, this timeout applies to the total execution time of all steps in the scenario. If the scenario exceeds this limit, a ScenarioTimeoutError is thrown.

    Priority: scenario timeout > RunOptions timeout

interface

#StepContext

interface StepContext

Execution context provided to steps, resources, and setup hooks.

The context provides access to:

  • Previous step results with full type inference
  • All accumulated results as a typed tuple
  • Named resources registered with .resource()
  • Shared storage for cross-step communication
  • Abort signal for timeout and cancellation handling
Examples

Accessing previous result

import type { StepContext } from "@probitas-test/core";

// Steps receive context with the previous step's result
const stepFn = (ctx: StepContext) => {
  // ctx.previous contains the result from the previous step
  const prev = ctx.previous as { id: number };
  console.log(prev.id); // Access typed result
};
console.log(stepFn);

Using shared store

import type { StepContext } from "@probitas-test/core";

// The store is shared across all steps in a scenario
const setupFn = (ctx: StepContext) => {
  ctx.store.set("startTime", Date.now());
};

const stepFn = (ctx: StepContext) => {
  const start = ctx.store.get("startTime") as number;
  console.log(`Elapsed: ${Date.now() - start}ms`);
};
console.log(setupFn, stepFn);
NameDescription
indexCurrent step index (0-based).
previousResult from the previous step.
resourcesNamed resources registered with `.resource()`.
resultsAll accumulated results as a typed tuple.
signalAbort signal that fires on timeout or manual cancellation.
storeShared key-value storage for cross-step communication.
Properties
  • readonlyindexnumber

    Current step index (0-based).

    Useful for conditional logic based on position in the scenario.

  • readonlypreviousunknown

    Result from the previous step.

    Fully typed based on what the previous step returned. For the first step, this is unknown.

  • readonlyresourcesRecord<string, unknown>

    Named resources registered with .resource().

    Resources are typed based on their registration:

    import type { StepContext } from "@probitas-test/core";
    
    interface DbResource {
      query(sql: string): unknown;
    }
    
    // Access resources registered with .resource()
    const stepFn = (ctx: StepContext) => {
      const db = ctx.resources["db"] as DbResource;
      return db.query("SELECT 1");
    };
    console.log(stepFn);
    
  • readonlyresultsreadonly unknown[]

    All accumulated results as a typed tuple.

    Allows accessing any previous result by index:

    import type { StepContext } from "@probitas-test/core";
    
    const stepFn = (ctx: StepContext) => {
      ctx.results[0]; // First step's result
      ctx.results[1]; // Second step's result
    };
    console.log(stepFn);
    
  • readonlysignal?AbortSignal

    Abort signal that fires on timeout or manual cancellation.

    Pass this to fetch() or other APIs that support AbortSignal for proper timeout handling.

  • readonlystoreMap<string, unknown>

    Shared key-value storage for cross-step communication.

    Use this for data that doesn't fit the step result pattern, such as metadata or configuration set during setup.

interface

#StepDefinition

interface StepDefinition<T = unknown>

Immutable definition of a scenario step.

Contains all information needed to execute a single step: the step function, its options, and debugging metadata.

Step definitions are created by the builder and consumed by the runner. They are immutable and should not be modified after creation.

NameDescription
fnStep function to execute
kind—
nameHuman-readable step name (displayed in reports)
originOrigin where the step was defined (for error messages)
retryRetry configuration for handling transient failures
timeoutMaximum execution time in milliseconds.
Properties
  • readonlyfnStepFunction<T>

    Step function to execute

  • readonlykind"step" | "resource" | "setup"
  • readonlynamestring

    Human-readable step name (displayed in reports)

  • readonlyorigin?Origin

    Origin where the step was defined (for error messages)

  • readonlyretry?{ readonly backoff?: "linear" | "exponential"; readonly maxAttempts?: number }

    Retry configuration for handling transient failures

  • readonlytimeout?number

    Maximum execution time in milliseconds.

    If the step takes longer, a TimeoutError is thrown. Default: 30000 (30 seconds)

interface

#StepOptions

interface StepOptions

Configuration options for individual step execution.

Controls timeout and retry behavior for a step. These options can be set at:

  1. Step level (highest priority)
  2. Scenario level (applies to all steps in scenario)
  3. Default values (30s timeout, no retry)
Examples
const options: StepOptions = {
  timeout: 60000,  // 60 seconds
  retry: {
    maxAttempts: 3,
    backoff: "exponential"  // Waits 1s, 2s, 4s between retries
  }
};
NameDescription
retryRetry configuration for handling transient failures
timeoutMaximum execution time in milliseconds.
Properties
  • readonlyretry?{ readonly backoff?: "linear" | "exponential"; readonly maxAttempts?: number }

    Retry configuration for handling transient failures

  • readonlytimeout?number

    Maximum execution time in milliseconds.

    If the step takes longer, a TimeoutError is thrown. Default: 30000 (30 seconds)

Types

type

#SetupCleanup

type SetupCleanup = void | (() => void | Promise<void>) | Disposable | AsyncDisposable

Cleanup handler returned by setup functions.

Setup functions can return various cleanup mechanisms that are automatically invoked after the scenario completes (regardless of success or failure).

Supported cleanup patterns:

  • void / undefined: No cleanup needed
  • () => void: Synchronous cleanup function
  • () => Promise<void>: Async cleanup function
  • Disposable: Object with [Symbol.dispose]() method
  • AsyncDisposable: Object with [Symbol.asyncDispose]() method
Examples

Cleanup function

import type { SetupCleanup } from "@probitas-test/core";

// Setup functions can return a cleanup function
const setupWithCleanup = (): SetupCleanup => {
  const file = Deno.makeTempFileSync();
  return () => Deno.removeSync(file); // Cleanup function
};
console.log(setupWithCleanup);

Disposable object

import type { SetupCleanup } from "@probitas-test/core";

// Setup functions can return an AsyncDisposable
const setupWithDisposable = async (): Promise<SetupCleanup> => {
  const conn: AsyncDisposable = {
    async [Symbol.asyncDispose]() {
      // cleanup logic
    },
  };
  return conn;
};
console.log(setupWithDisposable);
type

#StepFunction

type StepFunction<T = unknown> = (ctx: StepContext) => T | Promise<T>

Function signature for step execution.

A step function receives the execution context and returns a value (sync or async) that becomes available to subsequent steps.

Examples

Sync step returning data

import type { StepFunction } from "@probitas-test/core";

const step: StepFunction<{ name: string }> = (_ctx) => {
  return { name: "Alice" };
};

Async step with API call

import type { StepFunction } from "@probitas-test/core";

interface User {
  id: number;
  name: string;
}

const step: StepFunction<User> = async (ctx) => {
  const response = await fetch("/api/user", { signal: ctx.signal });
  return response.json();
};
type

#StepMetadata

type StepMetadata = Omit<StepDefinition, "fn">

Serializable step metadata (without the function).

Used for JSON output, tooling, and inspection without executing code.

Search Documentation