Skip to content

test: [TESIS-999031] walk every API route to keep the response envelope - #113

Draft
LauAubert wants to merge 2 commits into
masterfrom
TESIS-999031-every-listing-keeps-the-envelope
Draft

LauAubert wants to merge 2 commits into
masterfrom
TESIS-999031-every-listing-keeps-the-envelope

Conversation

@LauAubert

Copy link
Copy Markdown
Member

Ticket de Jira

https://proyectofinalfrlp.atlassian.net/browse/TESIS-999031

ID provisorio: se reemplaza por la clave real al cargar la card en Jira. Card: cards/031.md.


Descripción

ADR-015 lo dejó escrito en sus consecuencias: api_contract_spec.rb fija las formas de respuesta sobre los endpoints que enumera a mano, así que «un endpoint nuevo con otra forma no rompe nada hasta que se lo agrega ahí. Recorrer todas las rutas sería otra card». Esta es esa card: un spec que toma las rutas de la app y no una lista.

Qué verifica, por cada GET de /api/v1:

  • Todo index es una colección: responde 200 con data + meta, y el meta trae exactamente page, per_page y total (TESIS-108: no hay colección sin meta).
  • Los vocabularios fijos (products#categories, orders#provinces) responden data sola, como fija la sección de excepciones del ADR.
  • Cualquier otra ruta GET tiene que estar en la lista de recursos sueltos conocidos (show, me, tenant-config). Una ruta nueva sin clasificar hace fallar el spec hasta que alguien decida qué forma tiene.

Dientes: sacándole el meta al listado de depósitos, falla nombrando la ruta: expected ["warehouses#index", [200, ["data"], nil]] to satisfy ….

Orden de merge: reports#overview (proyecto-api#101, card 007) ya está clasificado como recurso, aunque la ruta llegue en otra rama, para que mergear una antes que la otra no rompa este spec.

  • Agrega spec/requests/api/v1/every_listing_envelope_spec.rb. Las listas de vocabularios y recursos van en un módulo (FormaDeCadaRuta), con el mismo criterio que ContratoDeLaApi.
  • Actualiza la consecuencia correspondiente en ADR-015.

Evidencia visual

N/A


Cómo probar

  1. bundle exec rspec spec/requests/api/v1/every_listing_envelope_spec.rb → 4 ejemplos en verde.
  2. Cambiar WarehousesController#index para que no mande meta → el spec falla nombrando warehouses#index.
  3. Agregar una ruta GET que no sea index → el spec falla hasta sumarla a una lista.

Verificación: bundle exec rspec (1571 ejemplos, 0 fallas), rubocop limpio.


Impacto y consideraciones

¿Introduce breaking changes?
No. Sólo tests y documentación.

¿Requiere nuevas variables de entorno?
No

¿Afecta la arquitectura o genera un nuevo patrón?
No. Automatiza una regla que ya existía (ADR-015).

🤖 Generated with Claude Code

LauAubert and others added 2 commits October 2, 2026 02:31
ADR-015 left it written down: the contract spec checks the shape of the
endpoints it lists by hand, so a new endpoint with another shape breaks
nothing until someone adds it there, and walking every route would be
another card.

The new spec takes every GET under /api/v1 from the routes: each index must
answer data plus a meta with page, per_page and total, each fixed vocabulary
must answer data alone, and any other GET route that is not a known bare
resource fails the spec until someone decides its shape. Removing the meta
of a listing now fails naming the route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TomasMartin2004

Copy link
Copy Markdown
Contributor

Revisado. Lo veo bien para implementar.

Es, junto a #114, el PR de esta tanda con mejor relación valor/costo: 101 líneas, todas de spec, y cubre literalmente una de las tareas transversales de QA que siguen abiertas en el tablero. No agrega producto, agrega red de seguridad sobre lo que ya está.

Lo que verifiqué

  • El spec toma las rutas de Rails.application.routes en vez de una lista escrita a mano, que es exactamente la deuda que ADR-015 dejó anotada en sus consecuencias. El ADR queda actualizado en el mismo PR, así que el documento y el código no se separan.
  • it 'finds the listings it walks (so an empty walk cannot pass)' es la parte que más me gusta: sin ese ejemplo, un cambio de ruteo que vacíe listings dejaría el barrido pasando en verde sin probar nada.
  • El ejemplo knows the shape of every other GET route obliga a clasificar cada GET nuevo. Es la única forma de que esto no vuelva a quedar desactualizado.
  • FormaDeCadaRuta::RECURSOS incluye reports#overview, que todavía no existe en master. No rompe nada (una entrada de más en una whitelist no se usa) y evita que el orden de merge con feat: [TESIS-999007] aggregate the real sales and dispatches for the reports screen #101 haga fallar el spec. Bien resuelto.

Lo único que dejaría anotado

sample(path) sólo reemplaza :product_id. Hoy alcanza porque product_mappings#index es el único index anidado, pero un listado nuevo colgado de :order_id va a pedir la ruta con el :order_id literal y va a fallar con un error de ruteo que no dice qué pasó. No lo cambiaría ahora: con sumar una línea al comentario de sample explicando que hay que agregar el id nuevo ahí, queda cubierto para el que venga después.

Antes de mergear

scan_ruby figura en rojo, pero este PR no toca una sola línea de app/: no puede introducir un hallazgo de Brakeman. Falla igual en todas las ramas de esta tanda y master está en verde, así que es la corrida vieja del 02/10. Rebasá sobre master y se vuelve a correr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants