moonspec

    BDD test framework for MoonBit with Gherkin and Cucumber Expressions

    bdd
    cucumber
    gherkin
    testing
    moonbit
    Download zip
    Author
    Version
    0.12.0
    License
    Apache-2.0
    Last updated
    6 days ago
    Downloads
    15K

    #moonspec

    BDD test framework for MoonBit with Gherkin and Cucumber Expressions.

    #Sync and async execution

    The sync APIs and async import migration below are pre-1.0 changes that first ship in 0.12.0; 0.11.0 does not contain these APIs. Version 0.12.0 and later need MoonBit 0.10.20 or newer: they use the #derive(...) attribute syntax and the moonbitlang/core/json package API, which older toolchains do not accept. On an older toolchain, use 0.11.0. The tested toolchain is moon/moonrun 0.1.20261104 with moonc and core 0.10.20+65efd5b93, and moonbitlang/async 0.22.4. The JavaScript examples also test the async facade with moonbitlang/async 0.22.7.

    ExecutionPackage imported as @moonspecExecuted targets
    Syncmoonrockz/moonspecwasm-gc, wasm, js, native
    Asyncmoonrockz/moonspec/asyncwasm, js, native

    wasm-gc uses WebAssembly GC; wasm is the separate linear-memory backend. Wasm-GC is sync-only until upstream async support is verified. LLVM remains experimental and is outside this support matrix.

    The root exports run_sync and run_or_fail_sync for ordinary test blocks. run_sync(factory, options) returns RunResult; run_or_fail_sync raises a structured failure report. Existing async callers change one package import:

    import {
    "moonrockz/moonspec/async" @moonspec,
    }

    Keep existing run / run_or_fail calls, their async effects and test bodies. The optional facade re-exports the shared types and sync APIs. Retain the moonbitlang/async test-driver import for async tests. Root and runner no longer export async aliases. Step handlers and all six hook handlers keep their synchronous APIs.

    Separate packages keep the root dependency graph free of the async runtime. A virtual package cannot change a function's effect from sync to async, so no virtual packages or implementation overrides are required.

    run_sync rejects parallel(true) with SyncExecutionError::ParallelNotSupported before World factories, hooks or events. max_concurrent applies only to async parallel execution. Both execution modes share failed-only retries and fresh Worlds per attempt. Dry-run suppresses step handlers and case/step hooks, but before/after TestRun hooks still execute.

    For generated sync tests, select --execution sync or config execution: "sync". CLI selection wins over merged config, then the async default. Execution is independent of mode and test_kind. Sync generation embeds the complete original source in FeatureSource::Text and emits ordinary tests calling run_or_fail_sync. Async defaults retain FeatureSource::File, async test and run_or_fail.

    Text and Parsed do not read source files. File input and file/stderr output depend on the host. Sync output write failures raise SyncExecutionError::HostIoFailed; async output retains best-effort writes. Raw Wasm and browser hosts must supply the standard MoonBit host ABI used by the program. Embedding feature text does not provide a browser filesystem.

    Run the real generated example from this repository root:

    mise run examples:sync-wasm -- wasm-gc mise run examples:sync-wasm # all four sync targets

    For one shared World, steps, hooks and options factory, use the target-policy guide and multi-target example. Scalar execution still defaults to async. Object policy opts into separate common/sync/async packages and requires shared public factories in your own module; World fields stay private. Nearer config replaces the whole policy, and CLI --execution wins. Fresh options and stateful sinks are required on every call. Sync parallel mode raises a typed error before World factories, hooks or events. All policy --moonx rules reject until a supporting registry release is verified; use the local CLI on PATH.

    mise run examples:multi-target

    The example verifies sync on four targets, async on three, both modes together on native, safe regeneration and unchanged manual generation without writes. The guide records pre-1.0 constructor and GenerationError migration.

    #Installation

    moon add moonrockz/moonspec

    Add moonrockz/moonspec to the import array in your moon.pkg.

    #Quick Start

    Define a World, implement step definitions, and run against inline Gherkin:

    #derive(Default)
    struct CalcWorld { mut result : Int }

    pub extend CalcWorld with Default::{default}

    impl @moonspec.World for CalcWorld with configure(self, setup) {
    setup.given0("a calculator", fn() { self.result = 0 })
    setup.when2("I add {int} and {int}", fn(a : Int, b : Int) {
    self.result = a + b
    })
    setup.then1("the result should be {int}", fn(n : Int) raise {
    assert_eq(self.result, n)
    })
    }

    test "Feature: Calculator" {
    let feature =
    #|Feature: Calculator
    #| Scenario: Addition
    #| Given a calculator
    #| When I add 2 and 3
    #| Then the result should be 5
    @moonspec.run_or_fail_sync(CalcWorld::default,
    @moonspec.RunOptions::new([@moonspec.FeatureSource::Text("calc", feature)]),
    )
    }

    Each scenario gets a fresh World via #derive(Default). MoonBit structs are reference types -- mutations in closures are visible across step handlers.

    #Generate Tests with the CLI

    The moonspec CLI writes the wiring for you. You write .feature files and annotated step functions. The CLI then generates the World configure impl and one moon test test per scenario. Build rules keep the generated tests in step with the feature files.

    You can use the CLI in two ways. Both run the same commands.

    Installed CLImoonx (no install)
    Set upmoon install moonrockz/moonspec/cmd/moonspecNone. moonx comes with the MoonBit toolchain
    Run a commandmoonspec <command>moonx moonrockz/moonspec/cmd/moonspec@latest <command>
    Build rulesmoonspec gen build ... --apply... gen build ... --apply --moonx

    moon install puts moonspec in ~/.moon/bin. With --moonx, the build rule runs a pinned CLI version through moonx, so nobody who builds the project needs to install the CLI.

    The following workflow preserves the async generator default. For sync, use the root package, omit the async test-driver import and pass --execution sync to gen tests or gen build.

    #1. Add the dependencies

    moon add moonrockz/moonspec moon add moonbitlang/async

    In the moon.pkg of the package that holds your steps (here src):

    import { "moonrockz/moonspec/async" @moonspec, } import { "moonrockz/moonspec/format", "moonbitlang/async", } for "wbtest"

    #2. Write a feature file

    features/calculator.feature:

    Feature: Calculator Scenario: Addition Given a calculator When I add 2 and 3 Then the result should be 5

    #3. Write annotated step functions

    src/calc.mbt:

    #moonspec.world
    #derive(Default)
    struct CalcWorld {
    mut result : Int
    }

    pub extend CalcWorld with Default::{default}

    #moonspec.given("a calculator")
    fn given_calculator(world : CalcWorld) -> Unit {
    world.result = 0
    }

    #moonspec.when("I add {int} and {int}")
    fn when_add(world : CalcWorld, a : Int, b : Int) -> Unit {
    world.result = a + b
    }

    #moonspec.then("the result should be {int}")
    fn then_result(world : CalcWorld, expected : Int) -> Unit raise Error {
    assert_eq(world.result, expected)
    }

    #4. Generate the World impl

    moonspec gen steps # or: moonx moonrockz/moonspec/cmd/moonspec@latest gen steps

    This scans src (-d sets another directory) and writes src/calcworld_steps_gen.mbt. The file implements World for CalcWorld with one registration per annotated function:

    // Generated by moonspec gen steps — DO NOT EDIT
    #warnings("-unused_value")
    impl @moonspec.World for CalcWorld with configure(self, setup) {
    setup.given0("a calculator", fn() {
    given_calculator(self)
    })
    setup.when2("I add {int} and {int}", fn(_arg0 : Int, _arg1 : Int) {
    when_add(self, _arg0, _arg1)
    })
    setup.then1("the result should be {int}", fn(_arg0 : Int) raise {
    then_result(self, _arg0)
    })
    }

    Run it again when you add or change a step function. The parameters after the world select the registration:

    Step function parametersRegistration
    (world) or (world, a : A, ...)given0, given2, ... (typed, up to 22)
    (world, a : A, ..., ctx : @moonspec.Ctx)given1_ctx, ... (typed plus Ctx, up to 22)
    (world, ctx : @moonspec.Ctx)given("...", fn(ctx) ...), a handler that reads its own arguments
    any of the above with handler=true in the attributegiven("...", fn(ctx) ...), decoding typed values with no arity check; T? is None for a missing argument

    Typed values are decoded with FromStepArg (Int, String, @moonspec.DataTable, ...). The attributes are #moonspec.given, when, then and step.

    #5. Add build rules and generate the tests

    moonspec gen build features/calculator.feature -w CalcWorld --apply # or: moonx moonrockz/moonspec/cmd/moonspec@latest gen build \ # features/calculator.feature -w CalcWorld --apply --moonx

    This adds a rule and a dev_build entry to src/moon.pkg and writes src/calculator_feature_wbtest.mbt, with one async test per scenario. From then on, moon regenerates the test file before each moon check, moon build and moon test when the feature file changes.

    #6. Run the tests

    moon test

    Each scenario is its own test, so moon test -f "Feature: Calculator / Scenario: Add*" runs a subset and moon test --outline lists them.

    Pass --execution sync to generate ordinary tests with complete embedded source and run_or_fail_sync. Generated sync tests do not read the source file.

    Commit the generated files. moon does not run build rules when your package is a dependency of another module.

    #CLI commands

    CommandPurpose
    gen steps [-d <dir>]Generate the World configure impl from #moonspec.* attributes
    gen build <features...> -w <World> [--apply] [--moonx] [-p <pkg>] [--test-kind <kind>] [--execution <execution>]Print or apply moon.pkg build rules; with --apply, also generate missing test files
    gen tests <features...> -w <World> -o <dir or file.mbt> [--test-kind <kind>] [--execution <execution>]Generate test files once, without build rules
    check <features...>Parse feature files and report errors
    versionPrint the CLI version

    Generated test files are white-box tests (*_wbtest.mbt) by default, so they can use a private World impl, such as the one gen steps generates. Pass --test-kind test (or set test_kind: "test" in moonspec.json5) for black-box *_test.mbt files; these see only the package's public API. An -o value that ends in .mbt is the exact file name. A moonspec.json5 file can set world, the codegen mode and other defaults; see Config File.

    #Features

    • World trait -- per-scenario state with #derive(Default)
    • StepLibrary trait -- composable, reusable step groups
    • Cucumber Expressions -- 11 built-in parameter types, custom typed handles, and capture decoders
    • Expression tools -- registry-aware expression factory and candidate generator
    • Gherkin -- Feature, Scenario, Scenario Outline, Background, Rules, Data Tables, Doc Strings
    • Markdown with Gherkin -- .feature.md files are parsed as MDG
    • Lifecycle hooks -- before/after for test run, test case, and test step
    • Tag filtering -- boolean expressions (@smoke and not @slow)
    • Retries -- @retry(N) tags or global config
    • Dry-run -- validate wiring without execution
    • Skip -- @skip / @ignore with optional reason
    • Parallel execution -- bounded concurrency via @async.all()
    • Attachments -- text, binary, or URL on steps and hooks
    • Structured errors -- run_or_fail with snippets and suggestions
    • Codegen -- generate moon test runners from .feature and .feature.md files
    • Formatters -- Pretty, Cucumber Messages (NDJSON), JUnit XML

    #Cucumber Expression Parameters

    ExpressionMoonBit TypeStepValue Variant
    {int}IntIntVal(Int)
    {float}DoubleFloatVal(Double)
    {double}DoubleDoubleVal(Double)
    {long}Int64LongVal(Int64)
    {byte}ByteByteVal(Byte)
    {short}IntShortVal(Int)
    {bigdecimal}@decimal.DecimalBigDecimalVal(@decimal.Decimal)
    {biginteger}BigIntBigIntegerVal(BigInt)
    {string}StringStringVal(String)
    {word}StringWordVal(String)
    {}StringAnonymousVal(String)

    Custom types: setup.add_param_type_strings(name, patterns, transformer?).

    #Typed parameters and expression tools

    Define custom domain values with setup.define_param_type1 or composable @moonspec.Captures decoders through setup.define_param_type_with. Retrieve values with ctx[index].get(handle):

    let color : @moonspec.ParameterType[String] = setup.define_param_type1(
    "color", ["red|blue"], fn(text) { text },
    )
    setup.given("I pick {color}", fn(ctx) raise {
    assert_eq(ctx[0].get(color), "red")
    })

    The expression factory and generator are available through the same setup, using its registered parameter types:

    let factory = setup.expression_factory()
    let expression = factory.create_expression("I pick {color}")
    let candidates = setup.expression_generator().generate_expressions("I pick red")
    // candidates[0].source() is "I pick {color}".

    The factory creates expression objects for validation and explicit matching. Anchored patterns and /.../ patterns create regex objects; other patterns create Cucumber Expressions. The generator returns candidates and parameter metadata, honoring custom types' use_for_snippets flags. Choose a candidate's source() to register a Cucumber step pattern.

    ParameterType, Captures, Captures1, ExpressionFactory, CucumberExpressionGenerator, StepExpression, GeneratedExpression, Match, and the expression/parameter error types are re-exported by @moonspec. Step registration currently accepts Cucumber Expressions, and automatic undefined-step snippets use moonspec's built-in inference. The factory and generator are exposed for users' own tools and workflows.

    See the expression tools guide for full examples.

    #Step Registration

    Register steps inside World::configure using typed arity-suffixed methods. The numeric suffix indicates how many parameters the handler takes:

    setup.given0("a calculator", fn() { self.result = 0 })
    setup.given1("a user named {string}", fn(name : String) { self.user = name })
    setup.when2("I add {int} and {int}", fn(a : Int, b : Int) { self.result = a + b })
    setup.then1("the result should be {int}", fn(n : Int) raise { assert_eq(self.result, n) })
    setup.step0("the system is ready", fn() { () }) // matches any keyword

    The _ctx variants provide access to the full Ctx as the last parameter:

    setup.given1_ctx("a user named {string}", fn(name : String, ctx : Ctx) {
    self.user = name
    self.feature = ctx.scenario().feature_name
    })

    Arities 0--22 are supported for all keywords (given, when, then, step). The original setup.given("pattern", fn(ctx) { ... }) form remains available for advanced use cases.

    #Ctx and StepArg

    Ctx provides indexed access to matched arguments. Each StepArg has value (typed StepValue) and raw (original text). Use struct destructuring: match ctx[0] { { value: IntVal(n), .. } => ... }.

    Other methods: ctx.value(0) returns StepValue directly, ctx.args() returns ArrayView[StepArg], ctx.scenario() returns ScenarioInfo (feature name, scenario name, tags), ctx.step() returns StepInfo (keyword, text).

    #StepLibrary

    Composable step groups via the StepLibrary trait. Returns ArrayView[StepDef]:

    struct AccountSteps { world : BankWorld }

    impl @moonspec.StepLibrary for AccountSteps with steps(self) {
    let defs : Array[@moonspec.StepDef] = [
    @moonspec.StepDef::given1("a balance of {int}", fn(n : Int) {
    self.world.balance = n
    }),
    ]
    defs[:]
    }

    // Compose libraries in World::configure:
    setup.use_library(AccountSteps::new(self))

    #Hooks

    Register lifecycle hooks on Setup. "After" variants receive HookResult:

    setup.before_test_case(fn(ctx) {
    println("Starting: " + ctx.scenario().scenario_name)
    })
    setup.after_test_case(fn(_ctx, result) {
    // result: HookResult::Passed or HookResult::Failed(Array[HookError])
    ignore(result)
    })

    All six: before/after_test_run, before/after_test_case, before/after_test_step.

    #Attachments

    All context types (Ctx, CaseHookCtx, StepHookCtx, RunHookCtx) support attachments:

    ctx.attach("log output", "text/plain")
    ctx.attach_bytes(png_bytes, "image/png", file_name="screenshot.png")
    ctx.attach_url("https://example.com/report", "text/html")

    #RunOptions

    Configure a test run with RunOptions::new(features):

    MethodDefaultDescription
    parallel(Bool)falseAsync parallel execution; sync rejects true before effects
    max_concurrent(Int)4Max scenarios in async parallel mode only
    tag_expr(String)""Boolean tag filter expression
    scenario_name(String)""Filter scenarios by name
    retries(Int)0Global retry count for failed scenarios
    dry_run(Bool)falseValidate wiring without execution
    skip_tags(Array[String])["@skip", "@ignore"]Tags that skip scenarios
    add_sink(&MessageSink)--Add a formatter for envelope output
    add_formatter(sink, dest)--Register formatter with output destination
    clear_sinks()--Remove all sinks and formatters

    Feature sources: FeatureSource::Text(uri, content) for inline Gherkin, FeatureSource::File(path) for host-dependent file reads, and FeatureSource::Parsed(uri, feature) for a parsed feature without a source read.

    #Formatters

    Three built-in formatters (all implement MessageSink):

    • Pretty -- @format.PrettyFormatter::new() -- colored console output
    • JUnit -- @format.JUnitFormatter::new() -- XML for CI
    • Messages -- @format.MessagesFormatter::new() -- Cucumber Messages NDJSON

    Register with a destination:

    options.add_formatter(@format.PrettyFormatter::new(), @moonspec.OutputDest::Stdout)
    options.add_formatter(@format.JUnitFormatter::new(), @moonspec.OutputDest::File("report.xml"))

    Output destinations: @moonspec.OutputDest::Stdout, @moonspec.OutputDest::Stderr, @moonspec.OutputDest::File(path).

    When no formatters are configured, defaults to pretty output on stdout.

    #Tag Filtering

    opts.tag_expr("@smoke") // only @smoke
    opts.tag_expr("@smoke and not @slow") // boolean operators
    opts.tag_expr("@smoke or @regression") // either tag

    #Retrying, Dry-Run, Skip

    Retrying -- global or per-scenario @retry(N) tag (overrides global). Both sync and async retry only Failed scenarios, never Undefined, Pending or Skipped. Each retry creates a fresh World:

    opts.retries(2) // retry failed scenarios up to 2 times

    Dry-run -- validate step wiring without execution. Matched steps report as Skipped("dry run"), undefined steps report with snippets. Before/after TestRun hooks still execute; case/step hooks and handlers do not. Dry-run never retries:

    opts.dry_run(true)

    Skip -- scenarios tagged @skip or @ignore are skipped by default. Add a reason with @skip("flaky on CI"). Configure:

    opts.skip_tags(["@skip", "@ignore", "@wip"])

    #Config File

    moonspec.json5 controls codegen and runtime behavior:

    { world: "MyWorld", mode: "per-scenario", // or "per-feature", or per-file map execution: "async", // default; choose "sync" for embedded ordinary tests steps: { output: "steps.mbt", exclude: ["features/wip/**"] }, skip_tags: ["@skip", "@ignore"], formatters: [ { type: "pretty", output: "stdout" }, { type: "junit", output: "reports/results.xml" } ] }

    #Packages

    PackageDescription
    moonrockz/moonspecSync facade: World, Setup, Ctx, RunOptions, run_sync, run_or_fail_sync
    moonrockz/moonspec/asyncOptional facade: root exports plus async run, run_or_fail and parallel scheduling
    moonrockz/moonspec/coreWorld, Setup, HookRegistry, StepRegistry, Ctx
    moonrockz/moonspec/runnerShared sync executor, tag filtering, retries, hooks and results
    moonrockz/moonspec/formatPretty, Messages, JUnit formatters
    moonrockz/moonspec/codegenGenerate test files from Gherkin features
    moonrockz/moonspec/configConfiguration parsing (moonspec.json5)
    moonrockz/moonspec/scanner#moonspec.* attribute scanner for gen steps
    moonrockz/moonspec/cliCLI implementation
    moonrockz/moonspec/cmd/moonspecCLI executable (moonspec)

    #Documentation

    Full docs, CLI reference, architecture, and examples: https://moonrockz.github.io/moonspec/, or github.com/moonrockz/moonspec

    Upgrading from 0.11.0? See the 0.12.0 migration guide. Upgrading from 0.10.x? See the 0.11.0 migration guide first.

    #License

    Apache-2.0

    AmbiguousParameterTypeError

    Cucumber expression tools and typed parameter APIs available to consumers.

    Attachable

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Captures

    Cucumber expression tools and typed parameter APIs available to consumers.

    Captures1

    Cucumber expression tools and typed parameter APIs available to consumers.

    CaseHookCtx

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Cells

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Column

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Columns

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Ctx

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    CucumberExpressionGenerator

    Cucumber expression tools and typed parameter APIs available to consumers.

    DataTable

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    DocString

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    ExpressionError

    Cucumber expression tools and typed parameter APIs available to consumers.

    ExpressionFactory

    Cucumber expression tools and typed parameter APIs available to consumers.

    FeatureResult

    Result of executing a feature.

    FeatureSource

    Input source for a feature to be loaded into the cache.

    FromStepArg

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    GeneratedExpression

    Cucumber expression tools and typed parameter APIs available to consumers.

    HookError

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    HookHandler

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    HookRegistry

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    HookResult

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    HookType

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Match

    Cucumber expression tools and typed parameter APIs available to consumers.

    MoonspecError

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    OutputDest

    Destination for formatter output.

    ParameterType

    Cucumber expression tools and typed parameter APIs available to consumers.

    ParameterTypeError

    Cucumber expression tools and typed parameter APIs available to consumers.

    PendingAttachment

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    RegisteredHook

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Row

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    Rows

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    RunHookCtx

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    RunOptions

    Options for configuring a test run.

    RunResult

    Complete result of a test run.

    RunSummary

    Summary of an entire run.

    The retried field counts scenarios that required more than one attempt, regardless of their final outcome. A scenario that fails on the first attempt but passes on retry is counted as both passed and retried.

    ScenarioInfo

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    ScenarioResult

    Result of executing a scenario.

    ScenarioStatus

    Aggregate status of a scenario.

    Setup

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepArg

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepDef

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepExpression

    Cucumber expression tools and typed parameter APIs available to consumers.

    StepHookCtx

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepInfo

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepKeyword

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepLibrary

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepMatchResult

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepRegistry

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepReport

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepResult

    Result of executing a single step.

    StepSource

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    StepStatus

    Status of a single step execution.

    StepValue

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    SyncExecutionError

    An execution option or host operation unsupported by synchronous execution.

    World

    moonspec — BDD test framework for MoonBit.

    Re-exports core types and runner functions so users import just moonrockz/moonspec and use @moonspec.World, @moonspec.run_sync, etc.

    color_enabled

    fn color_enabled(no_color? : Bool) -> Bool

    Decide whether moonspec output uses ANSI colors.

    no_color is the value compiled into the test (from RunOptions, moonspec.json5 or moonspec gen tests --no-color). Environment variables override it at runtime:

    • MOONSPEC_COLOR=always or MOONSPEC_COLOR=never forces color on or off.
    • NO_COLOR with any non-empty value turns color off (https://no-color.org).

    run_or_fail_sync

    fn[W :
    World
    ] run_or_fail_sync(factory : () -> W, options :
    RunOptions
    ) -> Unit raise

    Run features synchronously, raising a structured report for any failure.

    run_sync

    Run features sequentially without an event loop. Rejects parallel execution before effects. Formatter file and stderr write failures raise SyncExecutionError::HostIoFailed.

    Source Files