@probitas-test/builder
Builder module for creating scenario definitions with a fluent, type-safe API.
This package provides the scenario fn function that returns a builder
for constructing scenario definitions. The builder uses method chaining to define
resources, setup functions, and test steps with full TypeScript type inference.
Links
- GitHub Repository
- @probitas-test/probitas - Main package (recommended for most users)
Related Packages
| Package | Description |
|---|---|
| @probitas-test/core | Core type definitions used by this builder |
| @probitas-test/runner | Executes scenarios built with this package |
Key Features
- Fluent API: Chain methods naturally to build complex scenarios
- Type-safe context: Each step receives typed access to previous step results
- Resource management: Register resources with automatic lifecycle handling
- Setup/Cleanup: Define setup functions with automatic cleanup support
- Configurable defaults: Override timeout and retry settings at any level
Core Exports
scenario- Factory function to create a new scenario builderStepContext- Type representing the context passed to step functionsStepFunction- Type signature for step functionsSetupFunction- Type signature for setup functionsResourceFunction- Type signature for resource fn functionsBuilderScenarioOptions- Partial options for scenario configurationBuilderStepOptions- Partial options for step configurationDEFAULT_SCENARIO_OPTIONS- Default values for scenario optionsDEFAULT_STEP_OPTIONS- Default values for step options
Installation
npm install @probitas-test/builderFunctions
#scenario
function scenario(name: string, options?: ScenarioOptions): ScenarioBuilderInitCreate a new scenario builder with a fluent API.
This is the primary entry point for defining scenarios. It returns a builder that provides a type-safe, chainable API for constructing test scenarios.
The builder pattern enables:
- Type-safe chaining: Return values flow through steps with full type inference
- Resource management: Automatic lifecycle handling with Disposable support
- Flexible configuration: Override defaults at scenario or step level
Parameters
namestringHuman-readable scenario name (shown in test reports)
options?ScenarioOptionsOptional configuration for tags, timeouts, and retry behavior
Examples
Basic scenario with type-safe step chaining
import { scenario } from "@probitas-test/builder";
// Mock user service for example
const createUser = (_data: { email: string }) =>
Promise.resolve({ id: "user-123" });
const verifyEmail = (_userId: string) => Promise.resolve();
export default scenario("User Registration")
.step("Create user", async () => {
const user = await createUser({ email: "test@example.com" });
return { userId: user.id };
})
.step("Verify email", async (ctx) => {
// ctx.previous is typed as { userId: string }
await verifyEmail(ctx.previous.userId);
})
.build();
Scenario with tags for filtering
import { scenario } from "@probitas-test/builder";
scenario("Payment Integration", {
tags: ["integration", "payment", "slow"],
stepOptions: { timeout: 60000 } // 1 minute timeout for all steps
})
.step("Process payment", async () => {
return { success: true };
})
.build();
// Run with: probitas run -s "tag:payment"
Scenario with resources and setup
import { scenario } from "@probitas-test/builder";
// Mock Database for example
const Database = {
connect: () =>
Promise.resolve({
rollback: () => {},
insert: (_data: { id: number }) => {},
query: (_sql: string) => [{ id: 1 }],
}),
};
scenario("Database Test")
.resource("db", async () => await Database.connect())
.setup((ctx) => {
// Run migrations
return () => ctx.resources.db.rollback();
})
.step("Insert data", (ctx) => ctx.resources.db.insert({ id: 1 }))
.step("Query data", (ctx) => ctx.resources.db.query("SELECT * FROM users"))
.build();
Types
#BuilderStepContext
type BuilderStepContext<P = unknown, A extends readonly unknown[] = readonly unknown[], R extends Record<string, unknown> = Record<string, unknown>> = StepContext
& { readonly previous: P; readonly resources: R; readonly results: A }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 { scenario } from "@probitas-test/builder";
scenario("Chained Steps")
.step("First", () => ({ id: 123 }))
.step("Second", (ctx) => {
console.log(ctx.previous.id); // 123 (typed as number)
})
.build();
Using shared store
import { scenario } from "@probitas-test/builder";
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();
#BuilderStepDefinition
type BuilderStepDefinition<T = unknown, P = unknown, A extends readonly unknown[] = readonly unknown[], R extends Record<string, unknown> = Record<string, unknown>> = StepDefinition & { readonly fn: BuilderStepFunction<T, P, A, R> }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.
#BuilderStepFunction
type BuilderStepFunction<T = unknown, P = unknown, A extends readonly unknown[] = readonly unknown[], R extends Record<string, unknown> = Record<string, unknown>> = (ctx: BuilderStepContext<P, A, R>) => 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 { BuilderStepFunction } from "@probitas-test/builder";
const step: BuilderStepFunction<{ name: string }> = (_ctx) => {
return { name: "Alice" };
};
Async step with API call
import type { BuilderStepFunction } from "@probitas-test/builder";
type User = { id: string; name: string };
const step: BuilderStepFunction<User> = async (ctx) => {
const response = await fetch("/api/user", { signal: ctx.signal });
return response.json();
};
