Skip to content

Repository files navigation

Yadda

NPM version NPM downloads Node.js CI codecov Code Style Dependencies

Yadda brings true BDD to JavaScript test frameworks such as node:test, Mocha and Jasmine. By true BDD we mean that the ordinary language (e.g. English) steps are mapped to code, rather than merely decorating it. This matters because just like comments the decorative steps used by tools such as Jasmine and Mocha can fall out of date and are a form of duplication.

Why Yadda?

  • Mature and stable. Yadda has been around since 2012 and its API has long since settled. It's battle-tested in real-world suites.
  • Zero dependencies. Yadda installs nothing else into your node_modules. No transitive supply chain, no version conflicts, less maintenance.
  • Small, well-factored codebase. Just over 2,000 lines of source (excluding tests and examples), built from deliberately tiny functions averaging a few lines each — mostly the feature parser and runner plugins, atop a smaller interpreter core. It is easy to read, easy to reason about, and easy to extend.
  • High test coverage. Covered by ~200 meaningful tests at ~87% line / ~98% branch coverage, run against current LTS and current Node.js releases.
  • True BDD. Steps map to real functions, so your specifications cannot silently drift away from the behaviour they describe.
  • Markdown feature files. Write specifications as GitHub-flavoured markdown so they render beautifully on GitHub, with headings for features and scenarios, list items for steps, fenced blocks for doc-strings, and markdown tables for data. See Markdown Feature Files.
  • Unopinionated. Yadda is not a test runner or a test framework — its one job is to map lines of text to function calls. It plugs into the runner you already use.

Yadda vs. Cucumber

Yadda's BDD implementation is like Cucumber's in that it maps ordinary language steps to code. You could of course use CucumberJS, but we find Yadda less invasive, and prefer its flexible syntax to Gherkin's rigidity.

Yadda CucumberJS
Dependencies 0 30+ transitive dependencies
Source size ~2,000 lines (zero deps) Substantially larger, plus its dependency tree
Runner Bring your own (node:test, Mocha, Jasmine, …) Ships its own runner
Language syntax Flexible — steps need not follow rigid Given/When/Then Gherkin only
Step conflicts Reduced via dynamic library selection and dictionaries More prone to clashes across a large step catalogue
Step data Dictionaries can source values (e.g. from a remote system), not just match literals Literal capture groups

Three things in particular set Yadda apart:

  • Dynamic library selection. You can compose different step libraries per scenario, so the same phrase can mean different things in different contexts without conflicting. See Step Libraries.
  • Dictionaries. Named, reusable terms that both reduce step conflicts and let step parameters be converted or sourced — turning matched text into integers, dates, parsed tables, or even entities fetched from a remote system. See Dictionaries.
  • A more flexible language. Steps do not have to start with Given/When/Then, terms can be aliased, and localisation is built in for many languages. See Feature Files and Localisation.

Installation

npm install --save-dev yadda

Yadda 3.0 is Node-only and requires Node.js >= 20. In-browser bundles were removed in 3.0 — see Migrating to 3.0.

Usage

1. Decide upon a directory structure

.
├── test.js
├── lib
│   └── Wall.js
└── test
    ├── features
    │   └── bottles.feature
    └── steps
        └── bottles-library.js

2. Write your first feature

test/features/bottles.feature

Feature: 100 Green Bottles

Scenario: Should fall from the wall

  Given 100 green bottles are standing on the wall
  When 1 green bottle accidentally falls
  Then there are 99 green bottles standing on the wall

3. Implement the step library

test/steps/bottles-library.js

import assert from 'node:assert';
import Yadda from 'yadda';
import Wall from '../../lib/Wall.js';

const { ContextParamLibrary, localisation: { English } } = Yadda;
const library = English.localise(new ContextParamLibrary());

export default library
  .given('$NUM green bottles are standing on the wall', (ctx, number) => {
    ctx.wall = new Wall(Number(number));
  })
  .when('$NUM green bottle accidentally falls', (ctx, number) => {
    ctx.wall.fall(Number(number));
  })
  .then('there are $NUM green bottles standing on the wall', (ctx, number) => {
    assert.equal(Number(number), ctx.wall.bottles);
  });

4. Integrate Yadda with your test runner (here, node:test)

test.js

import Yadda from 'yadda';
import library from './test/steps/bottles-library.js';

const { plugins: { nodetest }, FeatureFileSearch, createInstance } = Yadda;
const { featureFile, scenarios, steps } = nodetest.StepLevelPlugin.init();

new FeatureFileSearch('./test/features').each((file) => {
  featureFile(file, (feature) => {
    const yadda = createInstance(library);

    scenarios(feature.scenarios, (scenario) => {
      const ctx = {};
      steps(scenario.steps, (step, done) => {
        yadda.run(step, ctx, done);
      });
    });
  });
});

5. Write the code under test

lib/Wall.js

export default class Wall {
  constructor(bottles) {
    this.bottles = bottles;
  }

  fall(n) {
    this.bottles -= n;
  }
}

6. Run your tests

node --test

Documentation

  • Getting Started — installation, the interpreter, and your first suite
  • Step Libraries — mapping text to functions, sync/async/promise steps, aliases, dynamic selection
  • Dictionaries — reusable terms, converters, and sourcing step data
  • Managing State — sharing context across steps and libraries
  • Localisation — writing features in other languages
  • Events — hooking into scenario/step/execute events for debugging
  • Feature Files — the full feature-file syntax reference
  • Plugins — integrating with node:test, Mocha and Jasmine
  • API Reference — the public API surface
  • Migrating to 3.0 — breaking changes from 2.x

Examples

The examples directory demonstrates every key feature and how to integrate Yadda with common test runners. To run one:

git clone https://github.com/acuminous/yadda.git
cd yadda
npm install
npm link
cd examples/<desired-example>
npm install
npm test

Contributing

Pull requests are welcome. Please read CONTRIBUTORS.md first — it describes the principles and conventions that keep the Yadda codebase small and consistent.

License

ISC

About

A BDD javascript library

Resources

Stars

429 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages