Scenario DSL

Reference the Blackbox BDD scenario DSL, including scenario, background, given, when, then, given.each, outline, shared, and isolated flows.

The Scenario DSL is Blackbox’s explicit BDD authoring surface.

Use it when plain Playwright tests are not structured enough for faithful feature generation, or when the team wants scenarios to be readable in code before they become Gherkin.

The DSL gives Blackbox stronger intent than decompiling arbitrary test code because the author names the behavior grammar directly:

Given* When+ Then+

Then is the conclusion of the behavior. A scenario without a Then may execute code, but it does not express an observable claim.

Minimal Scenario

import { expect, scenario } from './testbed.js';
scenario('subscribe-flow', 'subscribing to the pro tier', ({ given, background }) => {
background('the system is reset', async ({ system }) => {
await system.reset();
});
given('alice is an existing user with no active subscription', async ({ request, system, when }) => {
await when('alice POSTs /subscriptions with a valid card', async ({ then }) => {
const response = await request.post(`${system.bff.hostBaseUrl}/subscriptions`, {
data: { userId: 'alice', paymentMethodId: 'pm_card_visa' },
});
await then('the response status is 201', async () => {
expect(response.status()).toBe(201);
});
});
});
});

This maps to:

@flow:subscribe-flow
Feature: subscribing to the pro tier
Background:
Given the system is reset
Scenario: alice is an existing user with no active subscription
When alice POSTs /subscriptions with a valid card
Then the response status is 201

Verbs

VerbPurposeGherkin mapping
scenario(slug, description, body)Define a behavior flow with a stable slug and human description@flow:<slug> and Feature: <description>
background(label, fn)Shared setup that runs before each scenario inside the scenario bodyBackground: Given <label>
given(precondition, fn)Define the scenario precondition and arrangement frameScenario: <precondition> plus arrangement lines
when(action, fn)Define the action being exercisedWhen <action>
then(expectation, fn)Define an observable assertionThen <expectation> or And <expectation>
given.each(rows)(precondition, fn)Define a scenario outline from row dataScenario Outline and Examples
outline(slug, description, rows, body)Define a parameterized flow directlyScenario Outline and Examples
scenario.isolated(...)Mark a scenario that needs a fresh isolation groupSame Gherkin; isolation is runtime metadata
scenario.shared(parentSlug, slug, description, body)Join a serial flow to a parent scenario’s isolation groupSame Gherkin; shared-state chain is runtime metadata

Isolation Verbs

Use scenario.isolated when sibling scenarios must not share system state. This is the shape the reshaper uses for test.describe.parallel(...) siblings.

Use scenario.shared(parentSlug, ...) when a serial chain intentionally carries state from one scenario to the next. The parent slug must already be registered. This is the shape the reshaper uses for serial describe chains.

Use outline or given.each when the same behavior should run over rows of examples.

How The Analyzer Reads The DSL

The blackbox-features analyzer detects BDD-DSL files by looking for scenario(...) plus BDD verbs such as given, when, then, or background.

From there it builds an analyzed feature:

DSL elementAnalyzed feature field
scenario(slug, description, ...)feature description and @<slug> tag
background(label, ...)background step with given phase
given(label, ...)scenario and first given step
when(label, ...)when step
then(label, ...)then step
given.each([...])scenario examples table

This is more reliable than decompiling arbitrary Playwright because the behavior phases are explicit.

Lint Rules That Apply

features lint applies to DSL-authored and decompiled scenarios.

The most important rules are:

RuleWhy it matters
aaa-shapeEnforces Given* When+ Then+ in that order
missing-thenPrevents scenarios with no observable conclusion
opaque-stepWarns when decompiled text is too generic to review
placeholder-tokenWarns when generated placeholders are unresolved
missing-backgroundSuggests Background when setup repeats
imperative-scenarioFlags overly low-level UI action lists
empty-scenarioBlocks scenarios with no steps

Relationship To Feature Files

The DSL is not a replacement for .feature files. It is the source shape that makes feature files more faithful.

The normal path is:

  1. Author or reshape a test into the Scenario DSL.
  2. Run blackbox features lint.
  3. Run blackbox features emit.
  4. Commit the generated .feature file if it is part of the review surface.
  5. Run blackbox features check in CI to catch syntax failure and feature-file drift.

Relationship To Runtime Effects

The Scenario DSL names behavior. Effects prove boundary behavior.

A then(...) block may contain ordinary response assertions, effect catalog matchers, or both. Feature files remain readable; effect catalogs and coverage reports carry the runtime proof.

Stability

The DSL surface is alpha. The core grammar is stable enough to document: scenarios should arrange, act, and conclude. Migration helpers such as reshape, scaffold, and wrap may change faster than the hand-authored DSL.

  1. Writing Scenarios
  2. Generating Feature Files
  3. Feature Files, BDD, and Staleness
  4. CLI Reference