@probitas/scenario

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.

Package Description
@probitas/builder Uses these types to build scenarios
@probitas/runner Executes scenario definitions
@probitas/discover Discovers 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)
  • Source - File and line number for error reporting

Function Types

Loader Utilities

Selector Utilities

Selectors provide powerful filtering capabilities:

Installation

deno add jsr:@probitas/scenario

Interfaces

interface

#LoadScenariosOptions

interface LoadScenariosOptions

Options for loading scenarios from files.

Examples

Handling import errors

const scenarios = await loadScenarios(files, {
  onImportError: (file, err) => {
    console.error(`Failed to load ${file}:`, err);
  }
});
NameDescription
onImportErrorCallback invoked when a scenario file fails to import.
Properties
  • onImportError?(scenarioFile: string | URL, err: unknown) => unknown

    Callback invoked when a scenario file fails to import.

    Use this for custom error handling or logging. If not provided, import errors are logged but otherwise silently ignored (the file is skipped and loading continues with other files).

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).

Examples

Typical scenario structure

// Created by: scenario("Login Flow").step(...).build()
const definition: ScenarioDefinition = {
  name: "Login Flow",
  options: {
    tags: ["auth", "smoke"],
    stepOptions: { timeout: 30000, retry: { maxAttempts: 1, backoff: "linear" } }
  },
  entries: [
    { kind: "resource", value: { name: "api", fn: ... } },
    { kind: "step", value: { name: "Login", fn: ..., options: ... } },
    { kind: "step", value: { name: "Verify", fn: ..., options: ... } }
  ],
  source: { file: "/tests/auth.probitas.ts", line: 5 }
};
NameDescription
nameHuman-readable scenario name (displayed in reports and CLI)
tagsTags for filtering and organizing scenarios.
stepsOrdered sequence of entries (resources → setups → steps)
sourceSource source where the scenario was defined
Properties
  • readonlynamestring

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

  • 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
    
  • readonlystepsreadonly StepDefinition[]

    Ordered sequence of entries (resources → setups → steps)

  • readonlysource?Source

    Source source where the scenario was defined

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": { ... } } }
  ],
  "source": { "file": "/tests/auth.probitas.ts", "line": 5 }
}
NameDescription
nameScenario name
tagsTags for filtering and organizing scenarios.
stepsEntry metadata (functions omitted for serialization)
sourceSource source where the scenario was defined
Properties
  • readonlynamestring

    Scenario name

  • 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
    
  • readonlystepsreadonly StepMetadata[]

    Entry metadata (functions omitted for serialization)

  • readonlysource?Source

    Source source where the scenario was defined

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"],
  stepOptions: {
    timeout: 60000,
    retry: { maxAttempts: 2, backoff: "linear" }
  }
};
NameDescription
tagsTags for filtering and organizing scenarios.
stepOptionsDefault options applied to all steps in this scenario.
Properties
  • 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
    
  • 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.

interface

#Selector

interface Selector

Parsed selector for filtering scenarios.

Created by parseSelector. Used by matchesSelector and applySelectors to filter scenarios.

Examples
// Result of parseSelector("tag:api")
const selector: Selector = {
  type: "tag",
  value: /api/i,
  negated: false
};
NameDescription
typeType of match: "tag" for tags, "name" for scenario name
valueRegular expression pattern for matching (case-insensitive)
negatedIf true, selector matches scenarios that do NOT match the pattern
Properties
  • readonlytypeSelectorType

    Type of match: "tag" for tags, "name" for scenario name

  • readonlyvalueRegExp

    Regular expression pattern for matching (case-insensitive)

  • readonlynegatedboolean

    If true, selector matches scenarios that do NOT match the pattern

interface

#Source

interface Source

Source source in a file for error reporting and debugging.

Captured automatically when defining scenarios, steps, and setups. Used by reporters to show meaningful stack traces.

Examples
// Example source object
const source: Source = {
  file: "/project/tests/auth.probitas.ts",
  line: 42
};
NameDescription
fileAbsolute file path where the element was defined
lineLine number in the file (1-indexed)
columnColumn number in the file (1-indexed)
Properties
  • readonlyfilestring

    Absolute file path where the element was defined

  • readonlyline?number

    Line number in the file (1-indexed)

  • readonlycolumn?number

    Column number in the file (1-indexed)

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

scenario("Chained Steps")
  .step("First", () => ({ id: 123 }))
  .step("Second", (ctx) => {
    console.log(ctx.previous.id);  // 123 (typed as number)
  })
  .build();

Using shared store

scenario("Store Example")
  .setup((ctx) => {
    ctx.store.set("startTime", Date.now());
  })
  .step("Check duration", (ctx) => {
    const start = ctx.store.get("startTime") as number;
    console.log(`Elapsed: ${Date.now() - start}ms`);
  })
  .build();
NameDescription
indexCurrent step index (0-based).
previousResult from the previous step.
resultsAll accumulated results as a typed tuple.
storeShared key-value storage for cross-step communication.
resourcesNamed resources registered with `.resource()`.
signalAbort signal that fires on timeout or manual cancellation.
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.

  • readonlyresultsreadonly unknown[]

    All accumulated results as a typed tuple.

    Allows accessing any previous result by index:

    ctx.results[0]  // First step's result
    ctx.results[1]  // Second step's result
    
  • 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.

  • readonlyresourcesRecord<string, unknown>

    Named resources registered with .resource().

    Resources are typed based on their registration:

    .resource("db", () => createDbConnection())
    .step((ctx) => ctx.resources.db.query(...))
    
  • 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.

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.

NameDescription
kind
nameHuman-readable step name (displayed in reports)
fnStep function to execute
timeoutMaximum execution time in milliseconds.
retryRetry configuration for handling transient failures
sourceSource source where the step was defined (for error messages)
Properties
  • readonlykind"step" | "resource" | "setup"
  • readonlynamestring

    Human-readable step name (displayed in reports)

  • readonlyfnStepFunction<T>

    Step function to execute

  • readonlytimeoutnumber

    Maximum execution time in milliseconds.

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

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

    Retry configuration for handling transient failures

  • readonlysource?Source

    Source source where the step was defined (for error messages)

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
timeoutMaximum execution time in milliseconds.
retryRetry configuration for handling transient failures
Properties
  • readonlytimeout?number

    Maximum execution time in milliseconds.

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

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

    Retry configuration for handling transient failures

Functions

function

#applySelectors

function applySelectors(scenarios: ScenarioDefinition[], selectorInputs: readonly string[]): ScenarioDefinition[]

Filter scenarios using selector strings with AND/OR/NOT logic.

This is the main entry point for scenario filtering. It combines multiple selector strings with the following logic:

  • Multiple strings: OR condition (match any)
  • Comma-separated in string: AND condition (match all)
  • ! prefix: NOT condition (exclude matches)
Parameters
    • Array of scenarios to filter
  • selectorInputsreadonly string[]
    • Selector strings from CLI -s flags
Returns

ScenarioDefinition[] — Filtered scenarios matching the selector criteria

Examples

OR logic - match any selector string

// Scenarios with "api" tag OR "db" tag
applySelectors(scenarios, ["tag:api", "tag:db"]);

AND logic - match all within comma-separated

// Scenarios with BOTH "api" AND "critical" tags
applySelectors(scenarios, ["tag:api,tag:critical"]);

Combined AND/OR/NOT

// (api AND critical) OR (db AND !slow)
applySelectors(scenarios, [
  "tag:api,tag:critical",
  "tag:db,!tag:slow"
]);

Exclude by name pattern

// All scenarios except those with "wip" in name
applySelectors(scenarios, ["!wip"]);
function

#loadScenarios

async function loadScenarios(scenarioFiles: readonly unknown[], options?: LoadScenariosOptions): Promise<ScenarioDefinition[]>

Load scenario definitions from file paths.

Dynamically imports scenario files and extracts their default exports. Supports both single scenario exports and arrays of scenarios.

Parameters
  • scenarioFilesreadonly unknown[]
    • Absolute file paths or file:// URLs to load
    • Optional error handling configuration
Returns

Promise<ScenarioDefinition[]> — Array of loaded scenario definitions

Examples

Loading discovered files

import { discoverScenarioFiles } from "@probitas/discover";
import { loadScenarios } from "@probitas/scenario";

const files = await discoverScenarioFiles({
  includes: ["**\/*.probitas.ts"]
});
const scenarios = await loadScenarios(files);

Loading specific files

const scenarios = await loadScenarios([
  "/project/tests/auth.probitas.ts",
  "/project/tests/api.probitas.ts"
]);
function

#matchesSelector

function matchesSelector(scenario: ScenarioDefinition, selector: Selector): boolean

Check if a scenario matches a single selector.

Tests whether the scenario's name or tags match the selector's pattern. Does not apply negation - returns the raw match result.

Parameters
Returns

boolean — `true` if the scenario matches the pattern (before negation)

Examples
const scenario = { name: "Login Test", options: { tags: ["auth"] } };

matchesSelector(scenario, { type: "tag", value: /auth/i, negated: false });
// → true

matchesSelector(scenario, { type: "name", value: /login/i, negated: false });
// → true

matchesSelector(scenario, { type: "tag", value: /api/i, negated: false });
// → false
function

#parseSelector

function parseSelector(input: string): Selector[]

Parse a selector string into an array of Selector objects.

Selector syntax:

  • tag:pattern - Match scenarios with a tag matching the pattern
  • name:pattern - Match scenarios with a name matching the pattern
  • pattern - Shorthand for name:pattern
  • !selector - Negate the selector (exclude matches)
  • sel1,sel2 - Combine selectors with AND logic
Parameters
  • inputstring
    • Selector string to parse
Returns

Selector[] — Array of parsed Selector objects (comma-separated = multiple selectors)

Examples

Basic selectors

parseSelector("tag:api");
// → [{ type: "tag", value: /api/i, negated: false }]

parseSelector("login");  // Shorthand for name:login
// → [{ type: "name", value: /login/i, negated: false }]

Negation

parseSelector("!tag:slow");
// → [{ type: "tag", value: /slow/i, negated: true }]

Combined selectors (AND logic)

parseSelector("tag:api,!tag:slow");
// → [
//     { type: "tag", value: /api/i, negated: false },
//     { type: "tag", value: /slow/i, negated: true }
//   ]

Type Aliases

type

#SelectorType

type SelectorType = "tag" | "name"

Type of selector for filtering scenarios.

  • "tag": Match against scenario tags
  • "name": Match against scenario name
type

#SetupCleanup

type SetupCleanup = void | unknown | 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
type

#StepFunction

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

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.

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