Tu primer escenario

Por: Artiko
gherkincucumber-jsprimer-escenariohello-world

Tu primer escenario

Hora de ver Gherkin en acción. Vamos a:

  1. Crear un proyecto vacío con TypeScript
  2. Instalar Cucumber-JS
  3. Escribir un feature
  4. Implementar step definitions
  5. Ejecutar y ver el resultado

Setup del proyecto

mkdir gherkin-tour && cd gherkin-tour
npm init -y
npm install --save-dev @cucumber/cucumber typescript ts-node @types/node

Estructura mínima:

gherkin-tour/
├── features/
│   ├── calculator.feature
│   └── step_definitions/
│       └── calculator.steps.ts
├── cucumber.cjs
├── tsconfig.json
└── package.json

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  }
}

cucumber.cjs

module.exports = {
  default: {
    requireModule: ['ts-node/register'],
    require: ['features/step_definitions/**/*.ts'],
    paths: ['features/**/*.feature'],
    format: ['progress-bar', 'html:cucumber-report.html']
  }
}

El feature: features/calculator.feature

Feature: Calculadora básica

  Como usuario de la calculadora, quiero sumar y restar números
  para hacer aritmética simple.

  Scenario: Sumar dos números positivos
    Given una calculadora vacía
    When sumo 2 y 3
    Then el resultado es 5

  Scenario: Restar dos números
    Given una calculadora vacía
    When resto 10 menos 7
    Then el resultado es 3

Las step definitions: features/step_definitions/calculator.steps.ts

import { Given, When, Then } from '@cucumber/cucumber'
import { strict as assert } from 'node:assert'

class Calculator {
  private result = 0
  reset() { this.result = 0 }
  add(a: number, b: number) { this.result = a + b }
  subtract(a: number, b: number) { this.result = a - b }
  getResult() { return this.result }
}

let calc: Calculator

Given('una calculadora vacía', function () {
  calc = new Calculator()
})

When('sumo {int} y {int}', function (a: number, b: number) {
  calc.add(a, b)
})

When('resto {int} menos {int}', function (a: number, b: number) {
  calc.subtract(a, b)
})

Then('el resultado es {int}', function (expected: number) {
  assert.equal(calc.getResult(), expected)
})

Ejecutar

Agregá al package.json:

{
  "scripts": {
    "test": "cucumber-js"
  }
}

Y ejecutá:

npm test

Salida esperada:

..........

2 scenarios (2 passed)
6 steps (6 passed)
0m00.123s

Report: cucumber-report.html

Tu primer escenario Gherkin está ejecutándose como test automatizado.

Cómo se conectan feature y steps

flowchart LR
    F[".feature"] -->|cucumber parsea| Steps[Lista de steps]
    Steps -->|cada step matchea| Pattern[Pattern en step definition]
    Pattern --> Code[Función TypeScript ejecuta]
    Code --> Assert{¿Pasa el assert?}
    Assert -->|sí| Next[Siguiente step]
    Assert -->|no| Fail[Fail del scenario]

Parámetros: {int}, {string}, {float}

Cucumber soporta cucumber-expressions para extraer valores:

When('sumo {int} y {int}', (a: number, b: number) => { ... })
When('agrego {string} al carrito', (sku: string) => { ... })
When('aplico descuento del {float}%', (pct: number) => { ... })

Y placeholders custom (lo veremos más adelante).

¿Y si falta una step definition?

Si el .feature tiene un step sin matching definition:

1) Scenario: Sumar dos números positivos
   ✗ Given una calculadora vacía
   ⚠ When sumo 2 y 3  (undefined)
       Implement with the following snippet:

       When('sumo {int} y {int}', function (int, int2) {
         return 'pending';
       });

Cucumber te da el código snippet listo para copiar. Workflow típico:

  1. Escribir el .feature
  2. Correr → ver los snippets faltantes
  3. Copiar y rellenar los snippets en step definitions
  4. Correr → debería pasar

Esto se llama outside-in development o specification first.

Versión Python (behave)

Para los que prefieren Python:

pip install behave

Estructura:

gherkin-tour-py/
├── features/
│   ├── calculator.feature
│   └── steps/
│       └── calculator.py

Mismo .feature. Step definitions en features/steps/calculator.py:

from behave import given, when, then

class Calculator:
    def __init__(self):
        self.result = 0
    def add(self, a, b):
        self.result = a + b
    def subtract(self, a, b):
        self.result = a - b

@given('una calculadora vacía')
def step_empty_calculator(context):
    context.calc = Calculator()

@when('sumo {a:d} y {b:d}')
def step_add(context, a, b):
    context.calc.add(a, b)

@when('resto {a:d} menos {b:d}')
def step_subtract(context, a, b):
    context.calc.subtract(a, b)

@then('el resultado es {expected:d}')
def step_result(context, expected):
    assert context.calc.result == expected, f"esperado {expected}, obtuve {context.calc.result}"

Ejecutar:

behave

Salida:

Feature: Calculadora básica   # features/calculator.feature:1
  Scenario: Sumar dos números positivos  # features/calculator.feature:6
    Given una calculadora vacía          # features/steps/calculator.py:10
    When sumo 2 y 3                      # features/steps/calculator.py:14
    Then el resultado es 5               # features/steps/calculator.py:22

  Scenario: Restar dos números           # features/calculator.feature:11
    Given una calculadora vacía          # features/steps/calculator.py:10
    When resto 10 menos 7                # features/steps/calculator.py:18
    Then el resultado es 3               # features/steps/calculator.py:22

1 feature passed, 0 failed, 0 skipped
2 scenarios passed, 0 failed, 0 skipped
6 steps passed, 0 failed, 0 skipped

Notá la diferencia clave entre los dos parsers:

Diferencias resumidas TS vs Python

AspectoCucumber-JS (TS)behave (Python)
AnotaciónGiven(...), When(...)@given(...), @when(...)
Capturas{int}, {string}{name:d}, {name}
Estado compartidoVariables module-scope o Worldcontext parameter
HooksBefore, After decoratorsbefore_scenario, after_scenario en environment.py
Comando ejecucióncucumber-jsbehave

Los conceptos son idénticos. Cambia la sintaxis.

¿Qué hicimos?

  1. ✅ Setup mínimo de un proyecto Cucumber (TS y Python)
  2. ✅ Primer feature con dos scenarios
  3. ✅ Step definitions que mapean a código
  4. ✅ Tests pasando

Esto es Gherkin “Hello World”. El resto del tutorial agrega Backgrounds, Scenario Outlines, tags, data tables, hooks, antipatrones e integración CI.

En el siguiente capítulo vemos cómo reutilizar precondiciones con Background.