StandardCucumberSteps 1.0.5

dotnet add package StandardCucumberSteps --version 1.0.5
                    
NuGet\Install-Package StandardCucumberSteps -Version 1.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StandardCucumberSteps" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StandardCucumberSteps" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="StandardCucumberSteps" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StandardCucumberSteps --version 1.0.5
                    
#r "nuget: StandardCucumberSteps, 1.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StandardCucumberSteps@1.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StandardCucumberSteps&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=StandardCucumberSteps&version=1.0.5
                    
Install as a Cake Tool

Standard Cucumber Steps

npm Maven Central NuGet Go

TLDR: Reusable Cucumber step definitions for TypeScript, Java, Go, and C# — a single canonical DSL for BDD testing across languages. An excellent fit for hands-off, agentic code development.

What this is

The downside of BDD / Cucumber is having to maintain the step code - code that links step text (Given... When... Then...) to executable code in the tests themselves.

Standard Cucumber Steps (SCS) is a library of pre-built Cucumber step definitions, available for TypeScript, Java, Go, and C#. Instead of writing Given, When, and Then glue code yourself, you import SCS and immediately get a rich vocabulary for calling functions, inspecting results, and asserting on data — all driven by a shared scenario language.

Why this is useful

Cucumber is a good fit for some testing problems and a poor fit for others. Before reaching for it, it is worth understanding the trade-offs:

Pro Readable by non-engineers Scenarios written in plain English can be reviewed and authored by product managers, QA analysts, and domain experts without reading code
Pro Living documentation Feature files stay in sync with the implementation by definition — if a scenario fails, the documentation is wrong
Pro Language-agnostic contracts The same .feature file can drive tests in TypeScript, Java, Go, and C# simultaneously, making it ideal for cross-language SDKs and generated code
Pro Encourages separation of concerns The glue layer (step definitions) is forced to stay thin; business logic cannot hide inside tests
Pro Reporting is excellent Step definitions pass and fail cleanly and you can see exactly how far a test has got without debugging it
Con Higher maintenance overhead Each scenario needs corresponding step definitions; large test suites can become hard to manage without discipline. This usually puts developers off using Cucumber as you feel you are writing everything twice.

SCS addresses the maintenance cost directly: writing step definitions is repetitive boilerplate that every project reimplements. SCS does it once, correctly, across four languages.

This is especially valuable when:

  • Testing a cross-language API or SDK — write the scenarios once, run them in each language's test suite to verify consistent behaviour.
  • Migrating between languages — the same feature files document the expected contract before, during, and after a migration.
  • Adopting BDD on an existing codebase — wire up your service with a few lines in a @Before hook and the step library covers the rest.
  • Writing tests for generated code — code generators that target multiple languages can share a single golden test suite.
  • Working with agentic AI coding - Feature files are an unusually clear form of instruction both for an AI coding agent and a human reviewer. See BDD and SCS for AI agentic coding for a full discussion.

Quick example

Let's say you have this interface (TypeScript):

interface BankAccount {

  deposit(amt: number)

  getBalance(): number

}

We can write this feature file to test the implementation:

Scenario: Depositing money increases the balance
  Given "account" is set up as a bank account with balance "0"
  When I call "{account}" with "deposit" using argument "100"
  And I call "{account}" with "deposit" using argument "50"
  And I call "{account}" with "getBalance"
  Then "{result}" is "150"

The Given step is the only language-specific glue you need to write — it puts your object into the shared props store. Every other step comes from SCS.

See the tutorial for a full walkthrough.

Quick Start

TypeScript

npm install @robmoffat/standard-cucumber-steps
import { setupGenericSteps, PropsWorld } from '@robmoffat/standard-cucumber-steps';

setWorldConstructor(PropsWorld);
setupGenericSteps();

Java (Maven)

<dependency>
  <groupId>io.github.robmoffat</groupId>
  <artifactId>standard-cucumber-steps</artifactId>
  <version>0.1.0</version>
</dependency>

Go

go get github.com/robmoffat/standard-cucumber-steps/go
import generic "github.com/robmoffat/standard-cucumber-steps/go"

world := generic.NewPropsWorld()
world.RegisterSteps(ctx)

C# (NuGet)

dotnet add package StandardCucumberSteps

See it in action

The same feature files run across all supported languages, producing consistent test results:

TypeScript

TypeScript test output

Java

Java test output

Go

Go test output

Bank account examples

The examples/ directory contains two small runnable TypeScript projects that illustrate the difference between the anti-pattern and the correct approach:

Example Description
examples/wrong Agent-generated bespoke step definitions — hardcoded to specific values, breaks on the second scenario
examples/right SCS-based — a single setup hook, both scenarios pass with zero additional glue code

Step Reference

Full documentation with examples for each step group:

  • Variables — storing and referencing props, boolean/null/numeric literals
  • JSONPath — navigating nested objects and arrays inside {...} references
  • Assertions — equality, contains, numeric comparisons, error assertions
  • Method Calls — calling functions and object methods
  • Async Steps — async functions and background jobs
  • Array Assertions — matching arrays and objects against data tables
  • Test Setup — invocation counters, async functions, delays

Variables

Step Description
Given "key" is "value" Store a string (or resolved literal) in props
Then "{key}" is "value" Assert prop equals value
When I refer to "{from}" as "to" Alias (copy) one prop to another
{varName} Prop lookup in any step argument
{null} {true} {false} {42} Literal values

JSONPath

Any {...} reference containing a dot or bracket is resolved as a path into the stored object. This applies in step arguments and DataTable column headers.

Syntax Meaning
{obj.field} Property of a stored object
{obj.a.b.c} Nested property access
{arr[0]} First element of a stored array
{arr[1].name} Property of an array element
address.city (DataTable header) Match a nested field in each array row

Assertions

Step Description
Then "{x}" is "value" String equality
Then "{x}" is null Assert null/nil
Then "{x}" is not null Assert not null
Then "{x}" is true Assert truthy
Then "{x}" is false Assert falsy
Then "{x}" is undefined Assert undefined/nil
Then "{x}" is empty Assert empty array or string
Then "{x}" is an error Assert is an error/exception
Then "{x}" is an error with message "msg" Assert error message
Then "{x}" is not an error Assert not an error
Then "{x}" contains "substring" Assert string contains
Then "{x}" is a string containing one of Assert contains one of (+DataTable)
Then "{x}" should be greater than "y" Numeric greater-than
Then "{x}" should be less than "y" Numeric less-than

Method Calls

Step Description
When I call "{fn}" Call a no-arg function
When I call "{fn}" using argument "{p1}" Call with one argument
When I call "{fn}" using arguments "{p1}" and "{p2}" Call with two arguments
When I call "{fn}" using arguments "{p1}", "{p2}", and "{p3}" Call with three arguments
When I call "{fn}" using arguments "{p1}", "{p2}", "{p3}", and "{p4}" Call with four arguments
When I call "{obj}" with "{method}" Call a method on an object
When I call "{obj}" with "{method}" using argument "{p1}" Call method with one argument
When I call "{obj}" with "{method}" using arguments "{p1}" and "{p2}" Call method with two arguments
When I call "{obj}" with "{method}" using arguments "{p1}", "{p2}", and "{p3}" Call method with three arguments
When I call "{obj}" with "{method}" using arguments "{p1}", "{p2}", "{p3}", and "{p4}" Call method with four arguments

Async Steps

Step Description
When I wait for "{fn}" Call and await in one step
When I wait for "{fn}" within "{ms}" ms Call and await with timeout
When I wait for "{fn}" using argument "{p1}" Call with arg and await
When I wait for "{fn}" using arguments "{p1}" and "{p2}" Call with two args and await
When I wait for "{fn}" using arguments "{p1}", "{p2}", and "{p3}" Call with three args and await
When I wait for "{fn}" using arguments "{p1}", "{p2}", "{p3}", and "{p4}" Call with four args and await
When I start "{fn}" as "jobName" Start async job in background
When I start "{fn}" using argument "{p1}" as "jobName" Start job with one arg
When I start "{fn}" using arguments "{p1}" and "{p2}" as "jobName" Start job with two args
When I start "{fn}" using arguments "{p1}", "{p2}", and "{p3}" as "jobName" Start job with three args
When I start "{fn}" using arguments "{p1}", "{p2}", "{p3}", and "{p4}" as "jobName" Start job with four args
When I wait for job "jobName" Wait for named job (30s timeout)
When I wait for job "jobName" within "{ms}" ms Wait with custom timeout

Array Assertions

Step Description
Then "{x}" is an array of objects with the following contents Exact ordered match (+DataTable)
Then "{x}" is an array of objects with at least the following contents Subset match (+DataTable)
Then "{x}" is an array of objects which doesn't contain any of Negative match (+DataTable)
Then "{x}" is an array of objects with length "{n}" Length assertion
Then "{x}" is an array of strings with the following values String array match (+DataTable)
Then "{x}" is an object with the following contents Single object field match (+DataTable)

Test Setup

Step Description
Given "handler" is a invocation counter into "count" Create a counting callable
Given "fn" is an async function returning "{value}" Create an async function
Given "fn" is an async function returning "{value}" after "{ms}" ms Create an async function with delay
Given we wait for a period of "{ms}" ms Sleep/delay

Shared Feature Files

The features/ directory contains .feature files that exercise every canonical step. Each language implementation points its test runner at this shared directory, so the same scenarios validate all four implementations.


Used by

SCS was extracted from three FINOS open-source projects. Factoring it out into a shared library means each project gets consistent behaviour.

Project Language Description
FDC3 TypeScript The FDC3 desktop interoperability standard; SCS drives its conformance test suite
FDC3-java-api Java Java implementation of the FDC3 API; uses SCS to verify the Java bindings against the same feature files
ccc-cfi-compliance Go FINOS Common Cloud Controls compliance testing; uses SCS as the generic step layer for cross-language contract verification

Each of these projects wires up its own domain objects in a single @Before hook and then delegates all step execution to SCS.

License

Apache 2.0

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 48 2/24/2026
1.0.3 78 2/22/2026
1.0.2 78 2/22/2026
1.0.1 78 2/22/2026
1.0.0 80 2/21/2026