npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@termwright/gherkin

v0.7.7

Published

Gherkin feature files as native @termwright/test cases through a Vitest plugin

Readme

@termwright/gherkin

Run physical Gherkin .feature files as native @termwright/test cases. The package is a Vite/Vitest transform: it parses the feature and emits the test module in memory, so it does not create generated source files or introduce a second test scheduler. Parsing and expressions use the official Cucumber libraries, pinned exactly to compatible versions in this package: @cucumber/[email protected], @cucumber/[email protected], and @cucumber/[email protected].

Native host

Run termwright test, termwright watch or termwright ui. The native host installs the Gherkin transform and discovers physical .feature files beside ordinary test modules automatically. Feature/Rule/Scenario/Example identity, tags and physical source locations remain part of the same Vitest collection, AttemptContext and resource lifecycle; there is no second scheduler.

The host uses the documented colocated step-definition conventions; no plugin registration or duplicate include list is required. Catalogue entries carry an explicit Gherkin kind, Feature/Rule ancestry, tags and physical source line rather than reconstructing structure from a title.

Step definitions

A paired module default-exports inert definitions. They are scoped to the feature which imported them; nothing is registered process-wide.

import { Given, Then, When, defineSteps } from '@termwright/gherkin';

export default defineSteps(
  Given('a starting value of {int}', ({ world }, value) => {
    world.value = value;
  }),
  When('I add {int}', ({ world }, amount) => {
    world.value = Number(world.value) + Number(amount);
  }),
  Then('the result is {int}', ({ expect, world }, total) => {
    expect(world.value).toBe(total);
  }),
);

The first callback argument contains the native Termwright fixtures (terminal, termwright, termwrightOptions, and step), Vitest expect, a fresh mutable world for the Scenario/Outline row, and physical Scenario metadata. It also exposes scenario-owned resources, its timeout signal, and the defer/use shortcuts. Captures follow it. A DocString or DataTable, when present, is the last argument.

Tags can map directly to native scheduler admission and timeout policy during collection, without wrapping test in a project proxy:

gherkinPlugin({
  scenario: ({ tags }) => ({
    timeout: tags.includes('@slow') ? 30_000 : 5_000,
    resources: tags.includes('@exclusive')
      ? { terminals: 2, hostPressure: 'exclusive' }
      : { terminals: 1 },
  }),
});

Project fixtures

An explicit plugin can use a project-owned test.extend() API. Its module must export named test, expect, and describe; list the custom fixture names so the generated Vitest callback can request them statically:

// fixtures.ts
import { describe, expect, test as base } from '@termwright/test';

export { describe, expect };
export interface ProjectFixtures {
  account: { name: string };
}
export const test = base.extend<ProjectFixtures>({
  account: async ({}, use) => {
    await use({ name: 'Ada' });
  },
});
import { fileURLToPath } from 'node:url';
import { gherkinPlugin } from '@termwright/gherkin';
import type { ProjectFixtures } from './fixtures.js';

gherkinPlugin<ProjectFixtures>({
  fixtureNames: ['account'],
  generatedImports: {
    test: fileURLToPath(new URL('./fixtures.ts', import.meta.url)),
    runtime: '@termwright/gherkin/runtime',
  },
});

Use the same fixture interface on definitions. The generic is additive: native fixtures, world, scenario, expect, defer, and use remain available.

Given<ProjectFixtures>('an account', ({ account, world }) => {
  world.name = account.name;
});

Fixture names are explicit because Vitest discovers fixture dependencies from the callback's static destructuring. Project fixture teardown remains native Vitest teardown: it runs after Gherkin After hooks and scenario cleanup, and before the teardown of fixtures it depends on.

defineParameterType(...) declares a custom Cucumber Expression parameter type without global registration. Step(...) declares a keyword-neutral step; Given, When, and Then provide readable authoring names but, like Cucumber, matching is based on the expression rather than the feature keyword.

Pairing and precedence

Patterns are resolved relative to featureRoot:

  • [filepath] is the complete relative feature path without .feature.
  • [filepart] expands from nearest to farthest. For foo/bar/baz.feature, it expands as foo/bar/baz, foo/bar, foo, then ..
  • A pattern without either token is global.

For each feature step, the first tier containing a match wins: [filepath], then each [filepart] distance, then global. More than one match in that same nearest tier is an error. Files and matches are sorted deterministically. Paired files are registered as Vite watch dependencies, and a glue hot update also invalidates its importing feature module. Pattern roots are watched and pairing is resolved again when matching glue is created, deleted, or renamed.

Every Scenario and every Scenario Outline example row becomes its own native test. Outline rows receive a deterministic [example N] suffix so each row has its own catalogue id and rerun target even when the Outline title contains no placeholders. Background and feature steps run through Termwright's step() fixture. The emitted source map points test declarations to the physical Scenario line and step calls to their physical Gherkin lines.

Those boundaries are first-class UI events, not labels reconstructed from a generated Vitest title. While a Scenario runs, the runner receives the keyword, prose, physical file:line:column, outcome, and stable step id. A terminal launched inside Given joins the already-open step, so its live screen and driver actions appear beneath the authored prose. The same ids and metadata are retained in the trace for replay. A Scenario without a terminal or driver actions still shows its Given/When/Then lifecycle; the UI does not invent an empty terminal session for it.

Supported surface

This package exposes the plugin, step definitions, custom parameter types, Background, Scenarios, Scenario Outlines, DocStrings, DataTables, scenario hooks, Cucumber tag-expression filtering, and project fixtures composed through Vitest's native test.extend() and test.override() APIs. The termwright ui host uses it for discovery, Run all, file/Scenario runs and reruns without writing generated source files. Editor-specific configuration is outside the runtime integration.