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

co-gherkin

v1.1.1

Published

Gherkin BDD testing for Vitest - A lightweight, TypeScript-first BDD testing framework

Readme

🥒 Co-Gherkin

BDD Testing, Together

BDD (Behavior-Driven Development) testing with Gherkin syntax for Vitest and Playwright

npm version License: MIT TypeScript Vitest Playwright


🚀 What is Co-Gherkin?

Co-Gherkin brings the power of Gherkin (Given-When-Then) syntax to modern JavaScript testing frameworks: Vitest for unit/integration tests and Playwright for E2E tests.

Why "Co"?

Inspired by co-working philosophy, Co-Gherkin promotes collaborative testing where:

  • ✅ Product managers write scenarios in plain English
  • ✅ Developers implement step definitions
  • ✅ QA validates behavior automatically
  • ✅ Everyone speaks the same language

🎯 Meta-Testing: We Practice What We Preach

Co-Gherkin tests itself using Co-Gherkin! 🔄

That's right - we use our own BDD framework to test our own code. This means:

  • 💯 >99% test coverage achieved through BDD scenarios
  • 🧪 Real-world validation - if it works for us, it works for you
  • 📂 Examples - Check out our examples/ folder for a fully working Calculator project
  • 📖 Living documentation - our test features are usage examples
  • 🔍 Quality assurance - we trust our own tool enough to depend on it

Check out our test features to see Co-Gherkin in action testing itself!

The Problem

  • Cucumber.js doesn't work well with Vitest
  • Playwright BDD is E2E only, not for unit/integration tests
  • No native Gherkin support in Vitest ecosystem

The Solution: Co-Gherkin

Feature: User Login
  Scenario: Successful login
    Given I am on the login page
    When I enter valid credentials
    Then I should see the dashboard

📦 Installation

npm install co-gherkin --save-dev

🎯 Quick Start

1. Create a .feature file

features/login.feature:

Feature: User Login

  Scenario: Successful login
    Given I am on the login page
    When I enter "[email protected]" and "password123"
    Then I should see the dashboard

2. Define steps

tests/login.steps.ts:

import { Given, When, Then } from "co-gherkin";
import { render, screen } from "@testing-library/react";
import { LoginPage } from "../pages/LoginPage";

Given("I am on the login page", () => {
  render(<LoginPage />);
});

When("I enter {string} and {string}", (email: string, password: string) => {
  // Your test logic
});

Then("I should see the dashboard", () => {
  expect(screen.getByText("Dashboard")).toBeInTheDocument();
});

3. Run the feature

tests/login.test.ts:

import { runFeature } from "co-gherkin";
import { resolve } from "path";
import "./login.steps";

runFeature(resolve(__dirname, "../features/login.feature"));

4. Execute with Vitest

npm run test

🎭 Playwright E2E Testing

Co-Gherkin also works with Playwright for End-to-End testing!

1. Configure Co-Gherkin for Playwright

tests/e2e/playwright-setup.ts:

import { configureGherkin } from "co-gherkin";
import { test } from "@playwright/test";

// Configure co-gherkin to use Playwright's test functions
configureGherkin({
  describe: test.describe,
  it: test,
  beforeAll: test.beforeAll,
  afterAll: test.afterAll,
  beforeEach: test.beforeEach,
  afterEach: test.afterEach,
});

2. Define E2E Steps

tests/e2e/steps/login.steps.ts:

import { Given, When, Then } from "co-gherkin";
import { expect } from "@playwright/test";
import { getPage } from "./playwright-context"; // Your context helper

Given("I am on the login page", async () => {
  const page = getPage();
  await page.goto("/login");
});

When(
  "I enter {string} and {string}",
  async (email: string, password: string) => {
    const page = getPage();
    await page.locator('input[type="email"]').fill(email);
    await page.locator('input[type="password"]').fill(password);
    await page.locator('button[type="submit"]').click();
  }
);

Then("I should see the dashboard", async () => {
  const page = getPage();
  await expect(page).toHaveURL(/.*dashboard/);
});

3. Run the Feature with Playwright

tests/e2e/login.spec.ts:

import { runFeatureSync } from "co-gherkin";
import { resolve } from "path";
import "./playwright-setup"; // Configure co-gherkin
import "./steps/login.steps"; // Import steps

// Use runFeatureSync for Playwright (synchronous test generation)
runFeatureSync(resolve(__dirname, "./features/login.feature"));

4. Execute with Playwright

npx playwright test

Key Differences: Vitest vs Playwright

| Aspect | Vitest | Playwright | | ------------------- | ---------------- | ----------------------------- | | Function | runFeature() | runFeatureSync() | | Test Generation | Dynamic | Synchronous | | Configuration | Auto-detect | configureGherkin() required | | Use Case | Unit/Integration | E2E |


✨ Features

  • Multi-Framework Support - Works with Vitest AND Playwright
  • Vitest Native - Built specifically for Vitest unit/integration tests
  • Playwright E2E - Full support for Playwright E2E tests
  • TypeScript First - Full type safety and IntelliSense
  • Lightweight - Zero heavy dependencies
  • Fast - Powered by Vitest's and Playwright's speed
  • Full Gherkin Support:
    • ✅ Given, When, Then, And, But, * keywords
    • Background - Shared setup steps
    • Scenario Outline - Data-driven tests with Examples
    • Data Tables - Structured test data
  • Regex Patterns - Capture groups for dynamic values
  • Hooks - BeforeScenario and AfterScenario lifecycle
  • Unit + Integration + E2E - Complete testing solution
  • Easy Migration - From Cucumber or Playwright BDD

📚 API Reference

Step Definitions

Define test steps using Gherkin keywords:

import { Given, When, Then, And } from "co-gherkin";

Given("I am on the {string} page", (pageName: string) => {
  // Setup code
});

When("I click the {string} button", (buttonName: string) => {
  // Action code
});

Then("I should see {string}", (text: string) => {
  // Assertion code
});

And("the page title is {string}", (title: string) => {
  // Additional assertion
});

Regex Patterns

Use regex for more complex matching:

Given(/^I have (\d+) items in my cart$/, (count: string) => {
  const itemCount = parseInt(count);
  // Your logic
});

Background

Share common setup steps across scenarios:

Feature: Shopping Cart

  Background:
    Given I am logged in
    And I have an empty cart

  Scenario: Add item to cart
    When I add "Product A" to cart
    Then cart should have 1 item

  Scenario: Remove item from cart
    When I add "Product A" to cart
    And I remove "Product A" from cart
    Then cart should be empty

Scenario Outline

Data-driven testing with examples:

Feature: Calculator

  Scenario Outline: Add two numbers
    Given I have entered <a> into the calculator
    And I have entered <b> into the calculator
    When I press add
    Then the result should be <result>

    Examples:
      | a  | b  | result |
      | 1  | 2  | 3      |
      | 5  | 7  | 12     |
      | 10 | 15 | 25     |

Data Tables

Pass structured data to steps:

Given the following users exist:
  | name  | email           | role  |
  | Alice | [email protected]  | admin |
  | Bob   | [email protected]    | user  |
Given("the following users exist:", (dataTable: string[][]) => {
  dataTable.forEach(([name, email, role]) => {
    createUser({ name, email, role });
  });
});

Hooks

Execute code before/after each scenario:

import { BeforeScenario, AfterScenario } from "co-gherkin";

BeforeScenario(() => {
  // Setup: clear database, reset state, etc.
});

AfterScenario(() => {
  // Cleanup: close connections, clear mocks, etc.
});

Feature Runner

Run a feature file with Vitest (dynamic):

import { runFeature } from "co-gherkin";
import { resolve } from "path";

runFeature(resolve(__dirname, "./features/my-feature.feature"));

Run a feature file with Playwright (synchronous):

import { runFeatureSync } from "co-gherkin";
import { resolve } from "path";

runFeatureSync(resolve(__dirname, "./features/my-feature.feature"));

Configuration

Configure co-gherkin for different test frameworks:

import { configureGherkin } from "co-gherkin";
import { test } from "@playwright/test";

configureGherkin({
  describe: test.describe,
  it: test,
  beforeAll: test.beforeAll,
  afterAll: test.afterAll,
  beforeEach: test.beforeEach,
  afterEach: test.afterEach,
});

Note: Configuration is only required for Playwright. Vitest auto-detects when globals: true is enabled.


🎨 Example Project Structure

my-project/
├── features/
│   ├── login.feature
│   ├── signup.feature
│   └── checkout.feature
├── tests/
│   ├── steps/
│   │   ├── login.steps.ts
│   │   ├── signup.steps.ts
│   │   └── common.steps.ts
│   ├── login.test.ts
│   ├── signup.test.ts
│   └── checkout.test.ts
└── vitest.config.ts

🔧 Configuration

vitest.config.ts:

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
  },
});

🆚 Comparison

| Feature | Co-Gherkin | Cucumber.js | Playwright BDD | | ---------------- | -------------- | ----------- | -------------- | | Vitest Support | ✅ Native | ❌ No | ❌ No | | TypeScript | ✅ First-class | ⚠️ Partial | ✅ Yes | | Unit Tests | ✅ Yes | ✅ Yes | ❌ E2E only | | Speed | ⚡ Fast | 🐢 Slow | ⚡ Fast | | Bundle Size | 🪶 Light | 📦 Heavy | 📦 Heavy | | Background | ✅ Yes | ✅ Yes | ✅ Yes | | Scenario Outline | ✅ Yes | ✅ Yes | ✅ Yes | | Data Tables | ✅ Yes | ✅ Yes | ✅ Yes |


🛣️ Roadmap

See our detailed roadmap for planned features.

v1.0.0 (Stable)

  • [x] Core engine (Parser + Runner)
  • [x] TypeScript definitions
  • [x] Step definition system
  • [x] Hooks (BeforeScenario, AfterScenario)
  • [x] Background support
  • [x] Scenario Outline with Examples
  • [x] Data Tables
  • [x] >99% Code Coverage

Future Ideas

  • [ ] Tags support (@smoke, @integration)
  • [ ] VS Code Extension with syntax highlighting

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

MIT © David García


👤 Author

David García


🙏 Acknowledgments

Built with ❤️ for the Vitest community

"Testing, Together" - The Co-Gherkin Philosophy