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

@genesislcap/bdd-ui-automation

v0.1.27

Published

Reusable Cucumber, Playwright, and Allure BDD UI step library.

Readme

BDD UI Automation

Reusable Cucumber, Playwright, and Allure BDD UI step library.

This package is designed for consumer applications that only want to write feature files and environment config. Consumers install the npm package, configure Cucumber to load the compiled support and step entrypoints, and use the shared Gherkin vocabulary.

Consumer setup

Install the package:

npm install @genesislcap/bdd-ui-automation

Initialize a consumer project structure:

npx bdd-ui-init-resources

To include sample files as a starting point:

npx bdd-ui-init-resources --include-samples

The initializer creates:

resources/
  1-payload/
  2-actual/
  3-expected/
  4-config/
    bdd-ui.config.json
  5-input/
  features/
support/
cucumber.js

Then add or review cucumber.js:

module.exports = {
  default: {
    require: [
      './node_modules/@genesislcap/bdd-ui-automation/dist/support/index.js',
      './node_modules/@genesislcap/bdd-ui-automation/dist/steps/index.js'
    ],
    paths: ['resources/features/**/*.feature'],
    format: [
      'progress',
      'allure-cucumberjs/reporter'
    ],
    publishQuiet: true
  }
};

Add resources/4-config/bdd-ui.config.json:

{
  "baseUrl": "https://qa.example.com",
  "browser": "chromium",
  "headless": true,
  "timeout": 30000,
  "trace": true,
  "screenshotOnFailure": true,
  "viewport": {
    "width": 1440,
    "height": 900
  },
  "resourcePaths": {
    "payload": "resources/1-payload",
    "actual": "resources/2-actual",
    "expected": "resources/3-expected",
    "config": "resources/4-config",
    "input": "resources/5-input",
    "features": "resources/features"
  },
  "jsonComparison": {
    "engine": "jar",
    "output": "json"
  },
  "grids": {
    "trade": "[data-testid=\"trade-grid\"]"
  },
  "selectors": {
    "login-form": "[data-test-id=\"login-form\"]",
    "qte-form": "[data-test-id=\"qte-form\"]",
    "open-full-ticket-button": "[data-test-id=\"open-full-ticket-button\"]"
  },
  "uiScanner": {
    "language": "react-tsx",
    "include": [".tsx", ".ts"],
    "exclude": [".test.", ".spec.", ".stories.", "\\node_modules\\"]
  },
  "screenshots": {
    "expectedDir": "resources/3-expected/screenshots",
    "actualDir": "resources/2-actual/screenshots",
    "diffDir": "resources/2-actual/screenshots-diff",
    "mode": "compare",
    "threshold": 0.1,
    "maxDiffPixels": 0
  },
  "fieldVerification": {
    "Notional": {
      "mode": "normalized"
    },
    "Counterparty": {
      "mode": "contains"
    },
    "Premium BPS": {
      "mode": "pattern",
      "expectedPattern": "^\\d+\\.\\d{2}$"
    },
    "Trade Date": {
      "mode": "formatted",
      "expectedPattern": "^\\d{2}/\\d{2}/\\d{4}$"
    },
    "Internal Notes": {
      "mode": "none"
    }
  },
  "auth": {
    "loginPath": "/login",
    "successUrlContains": "/home"
  },
  "credentials": {
    "standardUser": {
      "username": "qa-user",
      "password": "secret"
    }
  }
}

The generated starter config also includes a minimal jsonComparison section so new consumer projects are ready for the bundled comparator flow without needing to invent a config shape later.

Generate a starter selector inventory from a consumer UI codebase:

npx bdd-ui-init-selectors --ui-path "C:\\work\\code\\sales-trader-hub\\client" --write

By default the generator reads uiScanner.language from bdd-ui.config.json, scans React/TSX source files, merges stable data-test-id / data-testid values into selectors, promotes obvious grid selectors into grids, and prints dynamic selector expressions that it skipped. When --write targets an existing bdd-ui.config.json, the generator creates a timestamped backup before writing the merged file.

Write feature files:

Feature: Login

  Scenario: Log in to the application
    Given I log in as "standardUser"
    Then the current URL should contain "/home"

For richer component workflows, the framework also supports custom dropdowns, scrolling, tab navigation, and value assertions for custom controls:

Scenario: Work with custom UI controls
  Given I log in as "standardUser"
  When I open the "Main" tab
  When I scroll to element "ROLL"
  When I choose "Ireland" from "Country"
  Then "Country" should have value "Ireland"
  Then the "Main" tab should be active

The framework can also read dropdown contents and compare them with expected values:

Scenario: Verify country dropdown values
  Given I log in as "standardUser"
  When I open the "Main" tab
  Then the dropdown "Country" should contain exactly:
    | Ireland |
    | France  |
    | Germany |

Use selector aliases from bdd-ui.config.json whenever a consumer app has stable data-test-id hooks:

{
  "selectors": {
    "country-dropdown": "[data-test-id=\"country-dropdown\"]",
    "main-tab": "[data-test-id=\"main-tab\"]",
    "roll-field": "[data-test-id=\"ROLL\"]"
  }
}

Then feature files can stay readable while still targeting custom wrappers:

When I choose "Ireland" from "country-dropdown"
When I scroll to element "roll-field"
Then "country-dropdown" should have value "Ireland"
Then the "main-tab" tab should be active

The dropdown-content assertion steps use the same alias resolution and also support zero-based indexed dropdowns when the same field appears more than once.

The recommended consumer layout mirrors the API automation project:

resources/
  1-payload/
  2-actual/
  3-expected/
  4-config/
  5-input/
  features/

Keep the structure flat inside each feature-name folder:

resources/features/
  login.feature
  extract-visible-grid.feature
  qte-acceptance-criteria.feature

resources/5-input/
  qte-acceptance-criteria/
    qte-ac-core-valid.json
    qte-ac-premium-valid.json
  qte-global-field-synchronization/
    qte-global-sync.json

resources/3-expected/
  extract-visible-grid/
    qte-grid-list.json
  qte-acceptance-criteria/
    qte-created.json
    qte-success.json

resources/2-actual/
  extract-visible-grid/
    qte-grid-list.json
  qte-acceptance-criteria/
    qte-created.json

Use 5-input for UI scenario data such as form JSON. The filename passed in the step is resolved inside the current feature-name folder, so the step should use the plain file name:

When I fill the form from "qte-ac-core-valid.json"

That path resolves under:

resources/5-input/<feature-name>/qte-ac-core-valid.json

For plain field fills and JSON-driven form fills, the framework now fails fast when a control does not retain the value that was just entered. That means steps such as:

When I fill "Username" with "test.user"
When I fill the form from "qte-ac-core-valid.json"

do not stop at the interaction itself. After filling an input-style control, the runtime reads the value back and raises a clear mismatch error if the field still reports something else.

When a field intentionally transforms or expands the entered value, configure fieldVerification in bdd-ui.config.json to loosen or redirect the readback check:

{
  "fieldVerification": {
    "Notional": {
      "mode": "normalized"
    },
    "Counterparty": {
      "mode": "contains"
    },
    "Premium BPS": {
      "mode": "pattern",
      "expectedPattern": "^\\d+\\.\\d{2}$"
    },
    "Trade Date": {
      "mode": "formatted",
      "expectedPattern": "^\\d{2}/\\d{2}/\\d{4}$"
    },
    "Internal Notes": {
      "mode": "none"
    }
  }
}

Fields not listed in fieldVerification use exact verification by default.

Locator strategy

The framework is not limited to getByText or getByLabel. Generic steps resolve targets through a layered lookup strategy so the same Gherkin vocabulary can work across native elements and custom component wrappers.

For a target such as "Save", "country-dropdown", or "primary-cta", the runtime can use:

  • selector aliases from bdd-ui.config.json
  • accessible labels
  • exact text
  • placeholders
  • role-based lookup for buttons, links, radios, and tabs
  • common attributes such as data-test-id, data-testid, name, aria-label, col-id, and row-id
  • id and class
  • raw CSS selectors

Class-based lookup is supported in two forms:

  • pass the class token, for example "primary-cta"
  • pass the explicit CSS selector, for example ".primary-cta"

Internally the framework can match selectors such as:

.primary-cta
[class~="primary-cta"]

That means an element like this can still be targeted by class:

<button class="btn primary-cta large">Save</button>

If multiple elements match, the plain step uses the first match by default. Use indexed steps when the same label/class/text appears more than once:

When I click ".primary-cta" at index 1

Recommended team guidance:

  • prefer data-test-id / data-testid for stable automation hooks
  • map those hooks through selectors in bdd-ui.config.json
  • use class selectors only as a fallback when no stable test hook exists
  • use indexed steps when a target appears more than once

The same distinction also applies to waits:

  • use When I wait for text "..." when you truly mean visible text
  • use When I wait for element "..." when you want alias/config-aware element resolution

Viewport and screenshots

The framework now uses a controlled viewport by default:

{
  "viewport": {
    "width": 1440,
    "height": 900
  }
}

If the consumer project does not set a viewport, 1440x900 is used automatically. Consumer projects can override it in bdd-ui.config.json when they need a different standard resolution.

Screenshot comparison settings also live in config:

{
  "screenshots": {
    "expectedDir": "resources/3-expected/screenshots",
    "actualDir": "resources/2-actual/screenshots",
    "diffDir": "resources/2-actual/screenshots-diff",
    "mode": "compare",
    "threshold": 0.1,
    "maxDiffPixels": 0
  }
}

Those roots are designed for nested relative screenshot paths such as:

home/dashboard/default
qte/quick-entry/form
home/blotter/trade-grid

The runtime writes actual and diff artifacts under matching subfolders, rejects unsafe path traversal such as .., and scrolls element targets into view before element screenshot capture. Alias-based masking is also supported through the same selectors map used by the rest of the framework.

Screenshot comparison steps:

Then the screen should match screenshot "dashboard/home-default"
Then element "qte-form" should match screenshot "qte-acceptance-criteria/qte-form-default"
Then element "tile" at index 1 should match screenshot "dashboard/tiles/second-tile"
Then element "qte-grid-list" should match screenshot "extract-visible-grid/qte-grid-list" masking "price-ticker,clock"

For example:

Then element "qte-form" should match screenshot "qte-acceptance-criteria/qte-form-default"

expects the baseline image at:

resources/3-expected/screenshots/qte-acceptance-criteria/qte-form-default.png

Response comparison design

The clean design for backend response comparison is to bundle the Genesis comparator JAR inside the published @genesislcap/bdd-ui-automation package and call it from reusable UI steps. That keeps the runtime self-contained for consumer projects: the UI suite needs the npm package and Java, but it does not need Gradle or a pre-populated local Maven cache at execution time.

The intended comparison flow is:

  1. capture the backend response during a user action
  2. write the captured JSON to resources/2-actual/<feature-name>/<file>
  3. compare it with resources/3-expected/<feature-name>/<file>
  4. delete the actual file on pass and keep it on failure

The planned Gherkin vocabulary is:

When I submit the form and capture response matching "EVENT_RFQ_TRADE_INSERT"
When I click "save-button" and capture response matching "EVENT_RFQ_TRADE_INSERT"
When I click "save-button" at index 1 and capture response matching "EVENT_RFQ_TRADE_INSERT"

Then I compare response with expected result "qte-create-ack.json"
Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY"
Then I compare response with expected result "qte-create-ack.json" with Primary Key "TRADE_ID"
Then I compare response with expected result "qte-create-ack.json" and ignore "RFQ_ID,TIMESTAMP"
Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY" with Primary Key "ID" for specific fields "STATUS,ID"
Then I compare response with expected result "qte-create-ack.json" and fail on extra "true"

The bundled comparator CLI options that shape this design are:

  • --expected <path>
  • --actual <path>
  • --output <text|json>
  • --parent-object <nameOrPath>
  • --primary-key <field[,field2]>
  • --ignore <field[,field2]>
  • --fields <field[,field2]>
  • --threshold-config <path>
  • --health-check
  • --fail-on-extra <true|false>

The comparator reports these exit codes:

  • 0 pass
  • 1 comparison failed
  • 2 extra-only differences when --fail-on-extra true
  • 3 invalid CLI usage
  • 4 input missing or unreadable
  • 5 internal comparator error

docs/step-reference.md and docs/configuration.md describe the same contract in more detail so consumer teams can align their feature files and project structure before the runtime integration lands.

Framework development

Framework developers should add reusable steps in src/steps/, shared Cucumber setup in src/support/, and internal Playwright helpers in src/runtime/.

Read:

  • docs/structure.md
  • docs/development.md
  • docs/configuration.md
  • docs/step-reference.md

License

Note: this project provides front-end dependencies and uses licensed components listed in the next section; thus, licenses for those components are required during development. Contact Genesis Global for more details.

Licensed components

Genesis low-code platform