@badeball/cypress-cucumber-preprocessor

repository·master·Indexed 23 days ago

https://github.com/badeball/cypress-cucumber-preprocessor

A Cypress preprocessor that enables Cucumber-style Behavior Driven Development (BDD) by parsing Gherkin documents and mapping them to Cypress test steps. It supports multiple bundlers including Esbuild and Webpack, and provides features such as custom parameter types, data tables, doc strings, and a variety of hooks (BeforeAll, AfterAll, Before, After, BeforeStep, AfterStep) with tag filtering and execution ordering. Version 26.0.0.

Tokens
19.7K
Snippets
51
Records
107
Agent score
77%

What's inside @badeball/cypress-cucumber-preprocessor

  1. How Pretty output works

    master

    The Pretty output functionality is not entirely contained within the reporter itself. Because reporters are limited to Mocha's event domain (which is unaware of Cucumber steps), the actual step-printing logic is driven by the code running within setupNodeEvents() { .. }.

    When the @badeball/cypress-cucumber-preprocessor/pretty-reporter is detected, the setupNodeEvents logic takes over the responsibility for generating the pretty output. However, when using cypress-multi-reporters, this detection fails, necessitating the manual pretty.enabled: true configuration mentioned previously.

  2. Use Expressions in Step Definitions

    master

    Step definitions can use either regular expressions or Cucumber Expressions to match Gherkin steps. When using regular expressions, each capture group is passed as an argument to the step definition function. When using Cucumber Expressions, you can use built-in parameter types like {int}.

    Example using a Cucumber Expression:

    Given("I have {int} cukes in my belly", (cukes: number) => {});
  3. Choose between `cypress-cucumber-preprocessor` and `@badeball/cypress-cucumber-preprocessor`

    master

    The package cypress-cucumber-preprocessor is the old, outdated version. The current, maintained version is @badeball/cypress-cucumber-preprocessor.

    Do not mix these two packages in the same project. Always use @badeball/cypress-cucumber-preprocessor for new projects.

  4. Understand the Cypress event handler limitation

    master

    Due to a limitation in Cypress, only a single event handler can exist for each event type. If multiple plugins attempt to register handlers for the same event, one will override the other, leading to unexpected behavior (e.g., screenshots not being added to JSON reports).

    The @badeball/cypress-cucumber-preprocessor plugin subscribes to the following events:

    • before:run
    • after:run
    • before:spec
    • after:spec
    • after:screenshot

    If you use other plugins that also define these handlers (such as allure-cypress, cypress-code-coverage, or cypress-mochawesome-reporter), you may encounter conflicts.

  5. Understand the usage report format

    master

    The usage report is a table that maps step patterns/text to their execution details. It includes:

    • Pattern / Text: The step definition pattern or the specific text used in a scenario.
    • Duration: How long the step took to execute. If a step definition is not used in any scenario, it is marked as UNUSED.
    • Location: The file path and line number where the step definition is defined or where the step is used in a feature file.

    Example output structure:

    ┌───────────────────────────────────────┬──────────┬─────────────────────────────────┐
    │ Pattern / Text                        │ Duration │ Location                        │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ an empty todo list                    │ 760.33ms │ support/steps/steps.ts:6        │
    │   an empty todo list                  │ 820ms    │ features/empty.feature:4        │
    │   an empty todo list                  │ 761ms    │ features/adding-todos.feature:4 │
    │   an empty todo list                  │ 700ms    │ features/empty.feature:4        │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ I add the todo {string}               │ 432.00ms │ support/steps/steps.ts:10       │
    │   I add the todo "buy some cheese"    │ 432ms    │ features/adding-todos.feature:5 │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ I remove the todo {string}            │ UNUSED   │ support/steps/steps.ts:33       │
    └───────────────────────────────────────┴──────────┴─────────────────────────────────┘
    ┌───────────────────────────────────────┬──────────┬─────────────────────────────────┐
    │ Pattern / Text                        │ Duration │ Location                        │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ an empty todo list                    │ 760.33ms │ support/steps/steps.ts:6        │
    │   an empty todo list                  │ 820ms    │ features/empty.feature:4        │
    │   an empty todo list                  │ 761ms    │ features/adding-todos.feature:4 │
    │   an empty todo list                  │ 700ms    │ features/empty.feature:4        │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ I add the todo {string}               │ 432.00ms │ support/steps/steps.ts:10       │
    │   I add the todo "buy some cheese"    │ 432ms    │ features/adding-todos.feature:5 │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ my cursor is ready to create a todo   │ 53.00ms  │ support/steps/steps.ts:27       │
    │   my cursor is ready to create a todo │ 101ms    │ features/empty.feature:10       │
    │   my cursor is ready to create a todo │ 5ms      │ features/adding-todos.feature:8 │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ no todos are listed                   │ 46.00ms  │ support/steps/steps.ts:15       │
    │   no todos are listed                 │ 46ms     │ features/empty.feature:7        │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ the todos are:                        │ 31.00ms  │ support/steps/steps.ts:21       │
    │   the todos are:                      │ 31ms     │ features/adding-todos.feature:6 │
    ├───────────────────────────────────────┼──────────┼─────────────────────────────────┤
    │ I remove the todo {string}            │ UNUSED   │ support/steps/steps.ts:33       │
    └───────────────────────────────────────┴──────────┴─────────────────────────────────┘
  6. Use @only and @skip for smart tagging

    master

    The preprocessor supports two special tags for quick test control:

    • @only: If no tags environment variable is provided, any scenario tagged with @only will be the only one to run (similar to Mocha's .only()).
    • @skip: Scenarios tagged with @skip will always be skipped, even if they match other active tag filters.
  7. How pairing works in cypress-cucumber-preprocessor

    master

    Unlike standard Cucumber where step definitions are globally available, this preprocessor uses a concept called Pairing.

    Pairing dictates which step definitions and hooks are available to a specific feature file. This is controlled entirely by the stepDefinitions configuration. If a step definition file is not matched by the patterns in your stepDefinitions array for a given feature file, it will not be available, and its hooks will not execute for that feature.

    This allows you to create isolated test environments where step definitions and hooks only apply to specific subsets of your feature files.

  8. Replicate `setWorldConstructor` behavior for custom state logic

    master

    While the preprocessor does not implement a native setWorldConstructor, you can replicate its behavior by using a beforeEach hook in your Cypress support file.

    By defining a state object and using Object.assign(this, world) inside a beforeEach function, you can attach custom methods and variables to the Cucumber world context, making them available to all step definitions via this.

    // cypress/support/e2e.ts
    beforeEach(function () {
      const world = {
        variable: 0,
    
        setTo(number) {
          this.variable = number;
        },
    
        incrementBy(number) {
          this.variable += number;
        }
      };
    
      Object.assign(this, world);
    });