Ir al contenido

Verifica la forma y el timing de una respuesta

Una sección # expect: convierte un bloque de “muéstrame lo que volvió” a “falla el runbook si alguna de estas no es verdad”. Útil para smoke tests commiteados a git y ejecutados como step de CI, o para el chequeo local “¿drifteó staging desde ayer?”.

Dentro de cualquier bloque (HTTP o DB), agrega una sección que empieza con # expect: en su propia línea. Cada línea abajo es una assertion: <field> <operator> <value>.

```http
GET {{BASE_URL}}/health
# expect:
# status == 200
# time < 500ms
# body.status == "ok"
# body.version matches /^v\\d+\\.\\d+\\.\\d+$/
```

Cualquier cosa después de # expect: hasta la fence de cierre (o una línea en blanco seguida de contenido non-#) se parsea como assertions.

Mismos fields que las referencias entre bloques, más dos HTTP-only:

FieldNotas
statusHTTP status numérico
timetotal elapsed (en ms / s)
sizebytes del response body
body.<path>JSON path
headers.<name>response header (case-insensitive)
cookies.<name>valor set-cookie
affectedsolo DB — count de filas INSERT/UPDATE/DELETE
row[N].<col>solo DB — columna de la n-ésima fila del resultado
rows.lengthsolo DB — número de filas retornadas
OperadorSignificadoFunciona en
==igualdad estrictastrings, numbers, booleans, null
!=no igualmismo
< <= > >=comparación numéricanumbers (incl. time, size)
containssubstring o membership de arraystrings, arrays
not containsinverso de containsstrings, arrays
matchesmatch regexstrings (regex entre /.../)
existsel path resuelve (no necesita RHS)cualquier field
not existsinversocualquier field
ischeck de tipo (number, string, array, object, null)cualquier field

time y size aceptan sufijos:

time < 500ms
time < 1.5s
time < 1m
size < 10kb
size < 100mb
SufijoSignificado
msmilisegundos
ssegundos
mminutos (raro)
b / kb / mb / gbbytes (potencias de 1024)

Sin sufijo significa integer crudo (time < 500 es < 500ms por default, ya que time está en ms; size < 100 son bytes).

Las referencias funcionan dentro de # expect: como en cualquier otro lado:

```http alias=cutoff
GET {{BASE_URL}}/last-sync
```
```http
GET {{BASE_URL}}/changes
# expect:
# status == 200
# body.since == {{cutoff.body.timestamp}}
# body.changes.length > 0
```

Útil para chequeos “¿la API estuvo de acuerdo con lo que fetcheamos la última vez?”.

Cuando alguna assertion falla:

  1. La toolbar del bloque se pone roja.
  2. El panel de resultado muestra el expected vs actual side by side:
    ✗ status == 200
    expected: 200
    actual: 503
    ✓ time < 500ms (143ms)
    ✗ body.status == "ok"
    expected: "ok"
    actual: "degraded"
  3. Los bloques downstream no ejecutan en un Run-all — httui hace short-circuit en la primera falla.
  4. El count de pass/fail de la status bar se actualiza: 2 passed · 1 failed.

Presiona Cmd+Shift+Enter (o haz clic en Run all en la status bar) para ejecutar cada bloque de arriba abajo. El summary muestra total pass/fail a través de todas las secciones # expect:.

Para CI, el binario httui-tui toma el mismo vault y puede ejecutar runbooks específicos:

Ventana de terminal
httui-tui run runbooks/smoke-staging.md --env staging
# exits 0 si todos los expects pasan, non-zero si alguno falló

Pipea a tu step de CI como cualquier otro comando de test.

Coméntala con un # extra:

# expect:
# status == 200
## time < 500ms ← skipped (flaky en cold cache)
# body.status == "ok"

El doble-## es la convención de httui de “ignora esta línea de expect”. Mejor que borrar porque la intención se preserva.

Puedes tener más de una — se agregan:

GET {{BASE_URL}}/users
# expect:
# status == 200
GET {{BASE_URL}}/users/admin
# expect:
# status == 200
# body.role == "admin"

Cada # expect: aplica al bloque más reciente. Útil cuando el bloque tiene sub-pasos lógicos que quieres verificar separadamente.

SíntomaCausaFix
body.X exists check falla en nullexists devuelve false para fields de body nullUsa body.X is null para distinguir
El regex no matcheaOlvidaste escapar / dentro del regexmatches /^v\\d+\\/release$/ (escapa / como \\/)
Time assertion siempre falla en el primer runCold connection / DNS lookupEl primer run baseline es más lento; considera time < <p99-de-runs-típicos>
Header assertion case-mismatchLos HTTP headers son case-insensitive — httui normalizaheaders.content-type y headers.Content-Type son lo mismo