Data Tables y Doc Strings
Data Tables y Doc Strings
Algunos steps necesitan pasar más que un par de strings: tablas de registros, JSON, queries SQL, HTML. Gherkin ofrece Data Tables y Doc Strings para eso.
Data Tables
Una tabla pegada debajo de un step se pasa al step definition como objeto de tipo DataTable.
Given los siguientes productos en el catálogo:
| sku | name | price | stock |
| P-100 | Mouse | 25 | 100 |
| P-101 | Keyboard | 80 | 50 |
| P-102 | Webcam | 120 | 20 |
La tabla es parte del step “Given los siguientes productos en el catálogo:”. El step definition la recibe como segundo argumento.
Cucumber-JS
import { Given, DataTable } from '@cucumber/cucumber'
Given('los siguientes productos en el catálogo:', function (table: DataTable) {
// table.hashes() devuelve un array de objetos:
// [{ sku: 'P-100', name: 'Mouse', price: '25', stock: '100' }, ...]
const products = table.hashes()
for (const row of products) {
this.catalog.add({
sku: row.sku,
name: row.name,
price: Number(row.price),
stock: Number(row.stock),
})
}
})
Métodos útiles de DataTable:
| Método | Devuelve |
|---|---|
table.hashes() | Array de objetos (primera fila = headers) |
table.rows() | Array de arrays (sin headers) |
table.raw() | Array de arrays (con headers, todo as-is) |
table.rowsHash() | Objeto donde col 0 = key, col 1 = value (vertical) |
behave
from behave import given
@given('los siguientes productos en el catálogo')
def step_seed_products(context):
for row in context.table:
context.catalog.add(
sku=row['sku'],
name=row['name'],
price=float(row['price']),
stock=int(row['stock']),
)
context.table es iterable; cada row se accede como dict.
Patrones comunes con Data Tables
1. Tabla horizontal (lista de registros)
Given los siguientes usuarios:
| email | role | status |
| [email protected] | user | active |
| [email protected] | admin | active |
| [email protected] | user | inactive |
Given('los siguientes usuarios:', function (table: DataTable) {
for (const row of table.hashes()) {
this.users.create(row)
}
})
Útil para sembrar múltiples registros.
2. Tabla vertical (un objeto con varios campos)
When envío la solicitud de cliente con:
| field | value |
| first_name | Ana |
| last_name | García |
| email | [email protected] |
| phone | +54 9 11 1234 5678 |
When('envío la solicitud de cliente con:', function (table: DataTable) {
const data = table.rowsHash()
// { first_name: 'Ana', last_name: 'García', email: '...', phone: '...' }
this.response = await this.api.post('/clients', data)
})
Útil para formularios con muchos campos.
3. Tabla de aserciones
Then el reporte de ventas contiene:
| category | total |
| electronics | 1250 |
| books | 340 |
| clothing | 800 |
Then('el reporte de ventas contiene:', function (table: DataTable) {
const expected = table.hashes()
for (const row of expected) {
const actual = this.report.findCategory(row.category)
assert.equal(actual.total, Number(row.total))
}
})
Útil para validar múltiples valores en una sola aserción legible.
Doc Strings — texto multilínea
Para pasar texto largo (JSON, SQL, HTML, prosa) usá triple comilla doble:
When envío POST /clients con body:
"""
{
"first_name": "Ana",
"last_name": "García",
"email": "[email protected]",
"address": {
"street": "Av. Corrientes 1234",
"city": "Buenos Aires",
"country": "AR"
}
}
"""
Cucumber-JS
When('envío POST {string} con body:', function (path: string, body: string) {
this.response = await this.api.post(path, JSON.parse(body))
})
El parámetro body recibe el string completo del Doc String.
behave
@when('envío POST "{path}" con body')
def step_post_with_body(context, path):
body = json.loads(context.text)
context.response = context.api.post(path, body=body)
context.text contiene el Doc String.
Content type hints en Doc Strings
Cucumber 7+ permite anotar el content type:
When envío POST /clients con body:
"""json
{
"name": "Ana"
}
"""
When ejecuto la query:
"""sql
SELECT id, email FROM users WHERE status = 'active'
"""
El content type aparece en reportes con syntax highlighting. No cambia comportamiento, solo documentación.
Cuándo Data Table vs Doc String
| Usar Data Table cuando… | Usar Doc String cuando… |
|---|---|
| Estructura es tabular (filas/cols) | El payload es libre (JSON, XML, SQL) |
| Múltiples registros del mismo tipo | Un solo objeto/blob |
| Querés que la spec sea legible | El formato exacto importa (raw JSON) |
| Necesitás iterar | Necesitás parsear como un todo |
Anti-patrón 1: tablas con tipos mezclados
- Given el siguiente usuario:
- | field | value |
- | email | [email protected] |
- | profile | {"age": 30, "hobbies": ["reading"]} ⚠ JSON dentro de celda
Mejor partir: una tabla para campos planos y un Doc String para el JSON anidado, o usar dos steps:
+ Given el siguiente usuario:
+ | field | value |
+ | email | [email protected] |
+ And con el perfil:
+ """json
+ { "age": 30, "hobbies": ["reading"] }
+ """
Anti-patrón 2: Doc Strings muy largos
When envío:
- """
- (300 líneas de JSON o XML)
- """
Si el payload es grande, guardalo en un fixture y referencialo:
When envío POST /import con el archivo "fixtures/big-payload.json"
El step lee el archivo:
When('envío POST {string} con el archivo {string}', async function (path: string, fixturePath: string) {
const content = await fs.readFile(fixturePath, 'utf-8')
this.response = await this.api.post(path, JSON.parse(content))
})
Anti-patrón 3: tablas como reemplazo de Outline
- Given los siguientes scenarios:
- | input | expected |
- | "abc" | weak |
- | "Abc1" | medium |
- Then todos pasan
Eso es un Outline:
+ Scenario Outline: Validación de password strength
+ Given input "<input>"
+ Then strength es "<expected>"
+ Examples:
+ | input | expected |
+ | abc | weak |
+ | Abc1 | medium |
Data Tables son input para un step. Outlines son plantillas para scenarios completos.
Ejemplo completo con ambas estructuras
Feature: Importar pedidos desde archivo
Scenario: Importar pedido con productos múltiples
Given el siguiente cliente:
| field | value |
| id | C-001 |
| email | [email protected] |
And los siguientes productos disponibles:
| sku | price |
| P-100 | 25 |
| P-101 | 80 |
When envío POST /orders con body:
"""json
{
"customer_id": "C-001",
"lines": [
{ "sku": "P-100", "quantity": 2 },
{ "sku": "P-101", "quantity": 1 }
]
}
"""
Then la respuesta tiene status 201
And el cuerpo contiene:
| field | value |
| order_id | |
| total | 130 |
| status | new |
Tres estructuras combinadas:
- Tabla vertical para el cliente
- Tabla horizontal para los productos
- Doc String JSON para el body
- Tabla vertical para aserciones del response
Resumen
- Data Tables: estructura tabular como input/aserción
- Horizontal: lista de registros (
table.hashes()) - Vertical: un objeto (
table.rowsHash())
- Horizontal: lista de registros (
- Doc Strings: texto multilínea (
""")- Útil para JSON, SQL, XML, HTML, prosa
- Soporta content type hints
- No confundir Data Table con
Scenario Outline(input vs plantilla)
En el siguiente capítulo profundizamos en step definitions en TypeScript.