Skip to content

Testing: tests E2E 99% - #147

Merged
CrisNAC merged 17 commits into
devfrom
testing-leo
May 8, 2026
Merged

CrisNAC merged 17 commits into
devfrom
testing-leo

Conversation

@leoAchu16

@leoAchu16 leoAchu16 commented May 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Tests

  • Agregadas pruebas exhaustivas de extremo a extremo para validar todos los procesos de entrega y gestión de pedidos, incluyendo registro y perfiles de repartidores, búsqueda de entregas disponibles, asignación y respuesta a asignaciones, historial de entregas, actualización de estado y sistema de reseñas de clientes.

@coderabbitai

coderabbitai Bot commented May 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Rate limit exceeded

@leoAchu16 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 minutes and 21 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a51cb290-83f5-47c4-8b5a-0109dc6f42ca

📥 Commits

Reviewing files that changed from the base of the PR and between fc00ab5 and e3ad27a.

📒 Files selected for processing (2)
  • tests/e2e/assignments-complete.test.js
  • tests/e2e/delivery.test.js
📝 Walkthrough

Recorrido

Este PR agrega nueve archivos de pruebas E2E que ejercitan integralmente endpoints relacionados con entregas, asignaciones, reseñas y órdenes. Las pruebas mockean Prisma, JWT y servicios para validar lógica de autenticación, autorización, validación de entrada y comportamiento transaccional sin depender de una base de datos real.

Cambios

Suites de pruebas E2E para entregas y órdenes

Capa / Archivo(s) Resumen
Infraestructura común
tests/e2e/*.test.js (setup repetido)
Setup de Vitest/Supertest, mocks de Prisma (incluyendo $transaction) y middleware JWT que lee req.cookies.userToken e inyecta req.user con roles (SELLER, DELIVERY, CUSTOMER).
Búsqueda y registro de entregas
tests/e2e/delivery.test.js, tests/e2e/delivery-register.test.js
GET /api/deliveries/search valida resultados vacíos, búsqueda case-insensitive por email/teléfono y exclusión de entregas ya vinculadas. POST /api/deliveries/register verifica validación de vehicleType, existencia de usuario, rol correcto y estado inicial INACTIVE.
Vinculación de entregas a tiendas
tests/e2e/delivery.test.js
POST /api/stores/:id/deliveries valida autorización de propietario, campos requeridos, conflictos de restricción única Prisma (P2002) y creación exitosa con delivery_status: "INACTIVE".
Perfil de entregas
tests/e2e/delivery-profile.test.js
PUT /api/deliveries/:id soporta actualización de nombre, teléfono, vehicleType, avatar vía multipart con upsertUserImage, validación de longitud y valores enum.
Estado de entregas
tests/e2e/delivery-status.test.js
PATCH /api/deliveries/:id/status valida presencia de delivery_status, valores permitidos (ACTIVE/INACTIVE), verificación de propiedad y actualización transaccional.
Entregas disponibles para órdenes
tests/e2e/orders-available-deliveries.test.js
GET /api/stores/:storeId/orders/:orderId/deliveries retorna entregas ACTIVE sin asignaciones activas, incluye dirección y valida autorización de tienda más existencia de orden.
Asignaciones: respuesta y flujo
tests/e2e/delivery-assignments-response.test.js
POST /api/assignments/orders/:orderId/delivery-response maneja ACCEPT (actualiza a ACCEPTED, orden a SHIPPED), REJECT con reasignación automática, y error 404 sin entregas disponibles.
Historial de órdenes de asignación
tests/e2e/delivery-assignments-orders-history.test.js
GET /api/assignments/:id/orders retorna historial paginado con filtrado opcional por assignment_status=DELIVERED e incluye metadatos de paginación.
Gestión de entregas por tienda
tests/e2e/deliveries-list-and-disengagement.test.js
GET /api/stores/:id/deliveries lista con stats.avgRating, DELETE desvincula si no hay asignaciones (204), retorna 400 con asignaciones, 403 sin autorización.
Reseñas de entregas
tests/e2e/delivery-reviews.test.js
GET /api/stores/:storeId/deliveries/:deliveryId/reviews retorna reseñas con búsqueda por ID de orden y filtrado por rango (minRating/maxRating); valida rango 1-5.
Reseñas de órdenes y entregas
tests/e2e/orders-delivery-reviews.test.js
GET /api/orders/pending-delivery-reviews retorna órdenes entregadas pendientes para CUSTOMER. POST /api/orders/:orderId/delivery-review crea reseña con validación de calificación 1-5, comentario ≤1000 caracteres, y detección de conflicto P2002.

Estimado de esfuerzo de revisión

🎯 3 (Moderado) | ⏱️ ~25 minutos

PRs posiblemente relacionados

  • CrisNAC/BackendMarketplace#140: Los tests E2E para GET/DELETE /api/stores/:id/deliveries ejercitan directamente la lógica de servicio/controlador implementada en ese PR.
  • CrisNAC/BackendMarketplace#132: Los tests para POST /api/assignments/orders/:orderId/delivery-response apuntan al servicio/controlador de respuesta de asignación implementado en ese PR.
  • CrisNAC/BackendMarketplace#133: Los tests para GET /api/assignments/:id/orders ejercitan directamente el controlador/servicio de historial de órdenes de ese PR.

Revisores sugeridos

  • CrisNAC
  • Lianyang1234

🐰 Nuevas pruebas E2E que verifican cada rincón,
Entregas, órdenes, reseñas sin confusión,
Con mocks y transacciones todo funciona,
La cobertura crece sin contradicción. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive El título es vago y genérico; no comunica información específica sobre los cambios principales del PR. Utiliza un término impreciso ('99%') que no describe qué se agregó o modificó. Reemplazar con un título descriptivo que indique el propósito principal, ej: 'Add comprehensive E2E test suite for delivery and order endpoints' o 'Add E2E tests for delivery and order management features'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch testing-leo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread tests/e2e/delivery-profile.test.js Fixed
Comment thread tests/e2e/delivery-profile.test.js Fixed
Comment thread tests/e2e/delivery-profile.test.js Fixed
Comment thread tests/e2e/delivery-status.test.js Fixed
Comment thread tests/e2e/delivery-status.test.js Fixed
Comment thread tests/e2e/delivery.test.js Fixed
Comment thread tests/e2e/delivery.test.js Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (5)
tests/e2e/orders-available-deliveries.test.js (1)

31-32: ⚡ Quick win

Constantes y mocks declarados pero nunca utilizados.

  • sellerCookie2 (línea 32) se define pero ningún test lo referencia.
  • mockOrderPickup (líneas 61-66) se define pero ningún test lo utiliza; hay un escenario de orden sin dirección (fk_address: null) que queda sin cobertura.
  • mockDeliveryInactive (líneas 80-84) se define pero no se usa en ningún test (ver comentario anterior).

Eliminar las constantes no utilizadas o cubrir los escenarios que representan.

Also applies to: 61-66, 80-84

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/orders-available-deliveries.test.js` around lines 31 - 32, Remove
the unused constants or add tests that exercise them: either delete
sellerCookie2, mockOrderPickup, and mockDeliveryInactive if they’re unnecessary,
or use them in new/updated tests in
tests/e2e/orders-available-deliveries.test.js — specifically add a test that
authenticates with sellerCookie2 to cover a second-seller scenario, add a test
that inserts/requests an order with fk_address: null using mockOrderPickup to
cover pickup-addressless orders, and add a test that uses mockDeliveryInactive
to verify inactive deliveries are excluded; update any setup/teardown helpers
used by the existing GET /orders/available-deliveries flow so these mocks are
applied.
tests/e2e/orders-delivery-reviews.test.js (1)

206-230: ⚡ Quick win

El error P2002 se mockea como objeto plano en lugar de una instancia de Error, inconsistente con delivery.test.js

En delivery.test.js (líneas 265-267) se construye correctamente el error de Prisma como:

const prismaError = new Error("...");
prismaError.code = "P2002";

Acá se usa un objeto plano { code: "P2002", meta: {...} }. Si el middleware de manejo de errores accede a .message, .stack, o verifica instanceof Error, la simulación no representará fielmente un error real de Prisma.

♻️ Usar instancia de Error consistente con el resto del PR
-    prisma.deliveryReviews.create.mockRejectedValue({
-      code: "P2002",
-      meta: { target: ["fk_order"] },
-    });
+    const prismaError = new Error("Unique constraint failed on the fields: (`fk_order`)");
+    prismaError.code = "P2002";
+    prismaError.meta = { target: ["fk_order"] };
+    prisma.deliveryReviews.create.mockRejectedValue(prismaError);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/orders-delivery-reviews.test.js` around lines 206 - 230, The test
mocks prisma.deliveryReviews.create rejecting with a plain object instead of an
Error instance; change the mockRejectedValue to throw an Error instance (e.g.,
const prismaError = new Error("..."); prismaError.code = "P2002";
prismaError.meta = { target: ["fk_order"] };) and use that with
prisma.deliveryReviews.create.mockRejectedValue(prismaError) so the error
behaves consistently with delivery.test.js and any middleware checks like
.message or instanceof Error.
tests/e2e/delivery-register.test.js (2)

34-46: ⚡ Quick win

Falta un test para el caso sin autenticación (401)

El mock JWT en las líneas 19-30 ya implementa el retorno de 401 cuando no hay cookie (if (!req.cookies?.userToken)), pero ningún test ejercita ese camino. Agregar este caso completa la cobertura del middleware.

✅ Caso de prueba sugerido
+  it("retorna 401 cuando no hay autenticación", async () => {
+    const res = await request(app)
+      .post("/api/deliveries/register")
+      .send({ vehicleType: "CAR" });
+
+    expect(res.status).toBe(401);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-register.test.js` around lines 34 - 46, Add a new test in
the describe("POST /api/deliveries/register") suite to exercise the
unauthenticated path: send a POST to "/api/deliveries/register" without setting
the authCookie (so the JWT mock branch if (!req.cookies?.userToken) is
triggered) and assert that the response status is 401 and the body contains the
expected error code/message for unauthorized access; place the test next to the
existing 400 case so the middleware branch covered by the JWT mock (lines around
the mock) is exercised.

6-17: ⚡ Quick win

El mock de $transaction no contempla la forma de callback, a diferencia del resto de los archivos del PR

Todos los demás archivos de este PR (delivery-assignments-orders-history.test.js, delivery-assignments-response.test.js, orders-delivery-reviews.test.js) manejan ambas formas de $transaction. Este archivo solo maneja el array form: si el servicio usa prisma.$transaction(async (tx) => {...}), pasar la función a Promise.all lanza un TypeError porque las funciones no son iterables.

♻️ Alinear con el patrón del resto del PR
-    $transaction: vi.fn((operations) => Promise.all(operations)),
+    $transaction: vi.fn((callbackOrArray) => {
+      if (typeof callbackOrArray === "function") {
+        return callbackOrArray({
+          users: prisma.users,
+          deliveries: prisma.deliveries,
+        });
+      }
+      return Promise.all(callbackOrArray);
+    }),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-register.test.js` around lines 6 - 17, El mock de
$transaction en el bloque vi.mock solo soporta arreglo y falla si el código
llama prisma.$transaction(fn); cambia la implementación de $transaction (en el
mock dentro de delivery-register.test.js) para detectar si el argumento es una
función y, en ese caso, invocarla pasándole el objeto de mock de prisma (o un
proxy con las mismas propiedades usadas en tests) y devolver su resultado (o
Promise.resolve si devuelve síncrono); si el argumento no es función, seguir
usando Promise.all(operations) como ahora. Asegúrate de que la referencia al
objeto mock (ej. prisma, models como users/deliveries) se use al invocar la
función para mantener paridad con los otros tests que ya manejan ambas formas.
tests/e2e/delivery-profile.test.js (1)

27-35: ⚡ Quick win

adminToken se crea pero nunca se usa; falta cobertura para acceso no autenticado

adminToken (línea 35) se genera pero ningún test lo consume. El comportamiento esperado para el rol ADMIN ante PUT /api/deliveries/:id queda sin validar.

Además, no hay ningún caso que verifique la respuesta ante una request sin cookie/token (esperaría un 401), lo cual es un camino de error relevante para la autenticación.

✅ Tests sugeridos a agregar
it("Retorna 401 cuando no hay token de autenticación", async () => {
  const res = await request(app)
    .put("/api/deliveries/1")
    .send({ name: "Sin Auth" });

  expect(res.status).toBe(401);
});

it("Retorna 403 cuando el rol es ADMIN", async () => {
  const res = await request(app)
    .put("/api/deliveries/1")
    .set("Cookie", authCookie(adminToken))
    .send({ name: "Intento Admin" });

  expect(res.status).toBe(403);
});

Also applies to: 172-179

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-profile.test.js` around lines 27 - 35, Add tests covering
unauthenticated and ADMIN-role access for the PUT /api/deliveries/:id endpoint:
keep the existing adminToken in beforeAll and add one test that issues
request(app).put("/api/deliveries/1").send(...) with no Cookie and asserts a 401
response, and another test that issues
request(app).put("/api/deliveries/1").set("Cookie",
authCookie(adminToken)).send(...) and asserts a 403 response; locate where tests
reference request, app, authCookie, and adminToken in delivery-profile.test.js
and add these two it(...) cases near the existing delivery/seller tests so
adminToken is used and unauthenticated behavior is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/e2e/deliveries-list-and-disengagement.test.js`:
- Around line 118-141: The tests in deliveries-list-and-disengagement.test.js
assert error text against res.body.message but the global errorHandler formats
errors as { error: { code, message } }; update the two failing assertions in the
DELETE tests ("DELETE - retorna 400 si tiene assignments activos
(PENDING/ACCEPTED)" and "DELETE - 404 si el delivery no pertenece a la tienda")
to check res.body.error.message instead of res.body.message so they match the
middleware output (leave the status assertions as-is).

In `@tests/e2e/delivery-assignments-orders-history.test.js`:
- Around line 147-164: The test uses mockAssignments (and then builds
filteredAssignments) but all items in mockAssignments already have
assignment_status "DELIVERED", so the test never verifies exclusion of
non-matching items; update the fixture mockAssignments to include at least one
item with a different assignment_status (e.g., "PENDING"), keep
prisma.deliveryAssignments.findMany.mockResolvedValue(filteredAssignments) to
return only the matching items, and adjust the assertions in the test
(expect(res.body.content).toHaveLength(... ) and the delivered-every check) to
reflect the actual filtered count so the test will fail if the server does not
filter by assignment_status; reference variables: mockAssignments,
filteredAssignments, prisma.deliveryAssignments.findMany, and the test case
it("retorna 200 con pedidos filtrados por estado DELIVERED"...).

In `@tests/e2e/delivery-profile.test.js`:
- Line 17: El mock de $transaction está pasando objetos anónimos en lugar de las
mismas referencias a prisma.users.update y prisma.deliveries.update, por lo que
las aserciones top-level son falsas positivas; fix: create shared mock
references (e.g. mockTxUsers and mockTxDeliveries) and return those same
references from the vi.mock factory for $transaction so tx.users.update /
tx.deliveries.update call the same spies as
prisma.users.update/prisma.deliveries.update, and because vi.mock factories are
hoisted define those spies with vi.hoisted(...) so they are available inside the
factory; update the "Body vacío" test to use these shared mocks when asserting
not.toHaveBeenCalled().
- Around line 22-24: The tests use vi.resetAllMocks() which removes the runtime
mock implementation of upsertUserImage (defined via
vi.fn().mockResolvedValue(...)) causing false positives; replace
vi.resetAllMocks() with vi.clearAllMocks() so mocks keep their factory
implementations, or if you must reset implementations, reassign the
upsertUserImage mock inside the beforeEach (recreate
vi.mock/vi.fn(...).mockResolvedValue(...)) so the upsertUserImage used by the
code under test always returns the expected URL; update the hooks around the
delivery-profile.test.js cases (and the other occurrences noted) to use
vi.clearAllMocks() or reconfigure upsertUserImage in beforeEach accordingly.

In `@tests/e2e/orders-available-deliveries.test.js`:
- Around line 138-141: The current test only asserts that
res.body.available_deliveries is an array, which is insufficient; update the
assertions in tests/e2e/orders-available-deliveries.test.js to validate the
actual filtering behavior by asserting the array is empty
(expect(res.body.available_deliveries.length).toBe(0)) or by asserting none of
the items have status 'PENDING' or 'ACCEPTED' (e.g.,
expect(res.body.available_deliveries.every(d =>
!['PENDING','ACCEPTED'].includes(d.status))).toBe(true)); replace or augment the
existing expect(Array.isArray(...)) check so the test will fail if the service
does not filter out PENDING/ACCEPTED deliveries.
- Around line 143-162: The test "retorna 200 cuando filtra correctamente
deliveries ACTIVE y estan disponibles" currently only returns ACTIVE mocks and
uses a fragile id check; update prisma.deliveries.findMany to include
mockDeliveryInactive alongside mockDeliveryActive1 and mockDeliveryActive2, then
assert that the response excludes the inactive delivery (e.g., verify no item in
res.body.available_deliveries has id_delivery ===
mockDeliveryInactive.id_delivery or has status === 'INACTIVE') and replace the
id-based toBeLessThanOrEqual(2) assertion with an assertion that every returned
delivery has status 'ACTIVE' (or equivalent domain property) to validate the
filtering logic implemented by the service.

---

Nitpick comments:
In `@tests/e2e/delivery-profile.test.js`:
- Around line 27-35: Add tests covering unauthenticated and ADMIN-role access
for the PUT /api/deliveries/:id endpoint: keep the existing adminToken in
beforeAll and add one test that issues
request(app).put("/api/deliveries/1").send(...) with no Cookie and asserts a 401
response, and another test that issues
request(app).put("/api/deliveries/1").set("Cookie",
authCookie(adminToken)).send(...) and asserts a 403 response; locate where tests
reference request, app, authCookie, and adminToken in delivery-profile.test.js
and add these two it(...) cases near the existing delivery/seller tests so
adminToken is used and unauthenticated behavior is covered.

In `@tests/e2e/delivery-register.test.js`:
- Around line 34-46: Add a new test in the describe("POST
/api/deliveries/register") suite to exercise the unauthenticated path: send a
POST to "/api/deliveries/register" without setting the authCookie (so the JWT
mock branch if (!req.cookies?.userToken) is triggered) and assert that the
response status is 401 and the body contains the expected error code/message for
unauthorized access; place the test next to the existing 400 case so the
middleware branch covered by the JWT mock (lines around the mock) is exercised.
- Around line 6-17: El mock de $transaction en el bloque vi.mock solo soporta
arreglo y falla si el código llama prisma.$transaction(fn); cambia la
implementación de $transaction (en el mock dentro de delivery-register.test.js)
para detectar si el argumento es una función y, en ese caso, invocarla pasándole
el objeto de mock de prisma (o un proxy con las mismas propiedades usadas en
tests) y devolver su resultado (o Promise.resolve si devuelve síncrono); si el
argumento no es función, seguir usando Promise.all(operations) como ahora.
Asegúrate de que la referencia al objeto mock (ej. prisma, models como
users/deliveries) se use al invocar la función para mantener paridad con los
otros tests que ya manejan ambas formas.

In `@tests/e2e/orders-available-deliveries.test.js`:
- Around line 31-32: Remove the unused constants or add tests that exercise
them: either delete sellerCookie2, mockOrderPickup, and mockDeliveryInactive if
they’re unnecessary, or use them in new/updated tests in
tests/e2e/orders-available-deliveries.test.js — specifically add a test that
authenticates with sellerCookie2 to cover a second-seller scenario, add a test
that inserts/requests an order with fk_address: null using mockOrderPickup to
cover pickup-addressless orders, and add a test that uses mockDeliveryInactive
to verify inactive deliveries are excluded; update any setup/teardown helpers
used by the existing GET /orders/available-deliveries flow so these mocks are
applied.

In `@tests/e2e/orders-delivery-reviews.test.js`:
- Around line 206-230: The test mocks prisma.deliveryReviews.create rejecting
with a plain object instead of an Error instance; change the mockRejectedValue
to throw an Error instance (e.g., const prismaError = new Error("...");
prismaError.code = "P2002"; prismaError.meta = { target: ["fk_order"] };) and
use that with prisma.deliveryReviews.create.mockRejectedValue(prismaError) so
the error behaves consistently with delivery.test.js and any middleware checks
like .message or instanceof Error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51ae9c85-a7a5-4510-84ce-062fb9b44a7a

📥 Commits

Reviewing files that changed from the base of the PR and between d8d77b7 and fc00ab5.

📒 Files selected for processing (10)
  • tests/e2e/deliveries-list-and-disengagement.test.js
  • tests/e2e/delivery-assignments-orders-history.test.js
  • tests/e2e/delivery-assignments-response.test.js
  • tests/e2e/delivery-profile.test.js
  • tests/e2e/delivery-register.test.js
  • tests/e2e/delivery-reviews.test.js
  • tests/e2e/delivery-status.test.js
  • tests/e2e/delivery.test.js
  • tests/e2e/orders-available-deliveries.test.js
  • tests/e2e/orders-delivery-reviews.test.js

Comment on lines +118 to +141
it("DELETE - retorna 400 si tiene assignments activos (PENDING/ACCEPTED)", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue({ id_delivery: 10, delivery_assignments: [{ id_delivery_assignment: 1 }] });

const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(400);
expect(res.body.message).toMatch(/entregas activas/i);
});

it("DELETE - 403 si el requester no es dueño del comercio", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStoreOtherOwner);

const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(403);
});

it("DELETE - 404 si el delivery no pertenece a la tienda", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue(null);

const res = await request(app).delete("/api/stores/1/deliveries/999").set("Cookie", sellerCookie);
expect(res.status).toBe(404);
expect(res.body.message).toMatch(/delivery no encontrado/i);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Buscar el handler o controller del DELETE /stores/:id/deliveries/:deliveryId
rg -n --type=js -C5 'fk_store.*null|entregas activas|delivery no encontrado' --iglob '!tests/**'

Repository: CrisNAC/BackendMarketplace

Length of output: 15382


🏁 Script executed:

rg -n "ValidationError|NotFoundError" --type=js -A2 --iglob '!tests/**' | head -50

Repository: CrisNAC/BackendMarketplace

Length of output: 3795


🏁 Script executed:

# Find error middleware or error handler
rg -n "express.*error|app\.use.*error|Error.*handler" --type=js --iglob '!tests/**' | head -20

Repository: CrisNAC/BackendMarketplace

Length of output: 108


🏁 Script executed:

# Look for response formatting in error handlers
rg -n "res\.status.*json|res\.json.*error|res\.json.*message" --type=js -B2 -A2 --iglob '!tests/**' | grep -A2 -B2 "error\|message" | head -40

Repository: CrisNAC/BackendMarketplace

Length of output: 2420


🏁 Script executed:

# Find the error class definitions
cat src/lib/errors.js

Repository: CrisNAC/BackendMarketplace

Length of output: 1421


🏁 Script executed:

# View the complete errorHandler middleware
cat src/middlewares/errorHandler.js

Repository: CrisNAC/BackendMarketplace

Length of output: 2213


Las aserciones de error del DELETE usan res.body.message pero el middleware devuelve res.body.error.message

El middleware global errorHandler.js formatea todos los AppError (incluyendo ValidationError y NotFoundError) con estructura { error: { code, message } }. Las aserciones en L124 y L140 acceden directamente a res.body.message, lo que causará que fallen porque la propiedad no existe. Deben cambiar a res.body.error.message para coincidir con la respuesta real del servidor.

Cambios requeridos
  it("DELETE - retorna 400 si tiene assignments activos (PENDING/ACCEPTED)", async () => {
    prisma.stores.findUnique.mockResolvedValue(mockStore);
    deliveriesTxMock.findFirst.mockResolvedValue({ id_delivery: 10, delivery_assignments: [{ id_delivery_assignment: 1 }] });

    const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
    expect(res.status).toBe(400);
-   expect(res.body.message).toMatch(/entregas activas/i);
+   expect(res.body.error.message).toMatch(/entregas activas/i);
  });

  it("DELETE - 404 si el delivery no pertenece a la tienda", async () => {
    prisma.stores.findUnique.mockResolvedValue(mockStore);
    deliveriesTxMock.findFirst.mockResolvedValue(null);

    const res = await request(app).delete("/api/stores/1/deliveries/999").set("Cookie", sellerCookie);
    expect(res.status).toBe(404);
-   expect(res.body.message).toMatch(/delivery no encontrado/i);
+   expect(res.body.error.message).toMatch(/delivery no encontrado/i);
  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("DELETE - retorna 400 si tiene assignments activos (PENDING/ACCEPTED)", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue({ id_delivery: 10, delivery_assignments: [{ id_delivery_assignment: 1 }] });
const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(400);
expect(res.body.message).toMatch(/entregas activas/i);
});
it("DELETE - 403 si el requester no es dueño del comercio", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStoreOtherOwner);
const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(403);
});
it("DELETE - 404 si el delivery no pertenece a la tienda", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue(null);
const res = await request(app).delete("/api/stores/1/deliveries/999").set("Cookie", sellerCookie);
expect(res.status).toBe(404);
expect(res.body.message).toMatch(/delivery no encontrado/i);
});
it("DELETE - retorna 400 si tiene assignments activos (PENDING/ACCEPTED)", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue({ id_delivery: 10, delivery_assignments: [{ id_delivery_assignment: 1 }] });
const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(400);
expect(res.body.error.message).toMatch(/entregas activas/i);
});
it("DELETE - 403 si el requester no es dueño del comercio", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStoreOtherOwner);
const res = await request(app).delete("/api/stores/1/deliveries/10").set("Cookie", sellerCookie);
expect(res.status).toBe(403);
});
it("DELETE - 404 si el delivery no pertenece a la tienda", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore);
deliveriesTxMock.findFirst.mockResolvedValue(null);
const res = await request(app).delete("/api/stores/1/deliveries/999").set("Cookie", sellerCookie);
expect(res.status).toBe(404);
expect(res.body.error.message).toMatch(/delivery no encontrado/i);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/deliveries-list-and-disengagement.test.js` around lines 118 - 141,
The tests in deliveries-list-and-disengagement.test.js assert error text against
res.body.message but the global errorHandler formats errors as { error: { code,
message } }; update the two failing assertions in the DELETE tests ("DELETE -
retorna 400 si tiene assignments activos (PENDING/ACCEPTED)" and "DELETE - 404
si el delivery no pertenece a la tienda") to check res.body.error.message
instead of res.body.message so they match the middleware output (leave the
status assertions as-is).

Comment on lines +147 to +164
it("retorna 200 con pedidos filtrados por estado DELIVERED", async () => {
prisma.deliveries.findUnique.mockResolvedValue(mockDelivery);
const filteredAssignments = mockAssignments.filter(
(a) => a.assignment_status === "DELIVERED"
);
prisma.deliveryAssignments.findMany.mockResolvedValue(filteredAssignments);
prisma.deliveryAssignments.count.mockResolvedValue(filteredAssignments.length);

const res = await request(app)
.get("/api/assignments/1/orders?assignment_status=DELIVERED")
.set("Cookie", authCookie)
.expect(200);

expect(res.body.content).toHaveLength(2);
expect(res.body.content.every((a) => a.assignment_status === "DELIVERED")).toBe(
true
);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

El test de filtro por DELIVERED no valida que ítems no coincidentes sean excluidos

Todos los elementos de mockAssignments ya tienen assignment_status: "DELIVERED", por lo que filteredAssignments siempre tiene longitud 2. El test esperaría toHaveLength(2) inclusive si el filtro del servidor estuviera completamente roto.

Para que el test tenga valor real, el fixture debería incluir al menos un elemento con un estado diferente (p.ej. "PENDING") y el mock debería devolver solo los que coincidan.

🛠 Fixture con ítems de estado mixto
 const mockAssignments = [
   {
     id_delivery_assignment: 1,
     assignment_status: "DELIVERED",
     // ...
   },
   {
     id_delivery_assignment: 2,
-    assignment_status: "DELIVERED",
+    assignment_status: "PENDING",  // ítem que NO debería aparecer en el filtro
     // ...
   },
 ];

 it("retorna 200 con pedidos filtrados por estado DELIVERED", async () => {
   prisma.deliveries.findUnique.mockResolvedValue(mockDelivery);
   const filteredAssignments = mockAssignments.filter(
     (a) => a.assignment_status === "DELIVERED"
   );
   prisma.deliveryAssignments.findMany.mockResolvedValue(filteredAssignments);
   prisma.deliveryAssignments.count.mockResolvedValue(filteredAssignments.length);
   // ...
-  expect(res.body.content).toHaveLength(2);
+  expect(res.body.content).toHaveLength(1); // Solo el ítem DELIVERED
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-assignments-orders-history.test.js` around lines 147 -
164, The test uses mockAssignments (and then builds filteredAssignments) but all
items in mockAssignments already have assignment_status "DELIVERED", so the test
never verifies exclusion of non-matching items; update the fixture
mockAssignments to include at least one item with a different assignment_status
(e.g., "PENDING"), keep
prisma.deliveryAssignments.findMany.mockResolvedValue(filteredAssignments) to
return only the matching items, and adjust the assertions in the test
(expect(res.body.content).toHaveLength(... ) and the delivered-every check) to
reflect the actual filtered count so the test will fail if the server does not
filter by assignment_status; reference variables: mockAssignments,
filteredAssignments, prisma.deliveryAssignments.findMany, and the test case
it("retorna 200 con pedidos filtrados por estado DELIVERED"...).

update: vi.fn(),
findUnique: vi.fn(),
},
$transaction: vi.fn((callback) => callback({ users: { update: vi.fn() }, deliveries: { update: vi.fn() } })),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Los mocks de $transaction son instancias anónimas desconectadas de prisma.users.update y prisma.deliveries.update

El callback de $transaction recibe { users: { update: vi.fn() }, deliveries: { update: vi.fn() } } — son instancias anónimas y efímeras, distintas de prisma.users.update y prisma.deliveries.update importadas en el test.

Si el controlador hace:

await prisma.$transaction(async (tx) => {
  await tx.users.update(...);
  await tx.deliveries.update(...);
});

Las llamadas a tx.users.update y tx.deliveries.update van a las instancias anónimas del callback, nunca a prisma.users.update y prisma.deliveries.update.

Las aserciones del test "Body vacío" (líneas 168–169) son vacuamente verdaderas independientemente de lo que haga el servicio: aunque la implementación llame a los updates dentro de la transacción, los mocks top-level nunca se invocan y el not.toHaveBeenCalled() siempre pasa.

🛠️ Corrección propuesta: compartir las mismas referencias de mocks
+const mockTxUsers = { update: vi.fn() };
+const mockTxDeliveries = { update: vi.fn() };
+
 vi.mock("../../src/lib/prisma.js", () => {
   const mockPrisma = {
     deliveries: {
       findUnique: vi.fn(),
-      update: vi.fn(),
+      update: mockTxDeliveries.update,
     },
     users: {
       update: vi.fn(),
+      update: mockTxUsers.update,
       findUnique: vi.fn(),
     },
-    $transaction: vi.fn((callback) => callback({ users: { update: vi.fn() }, deliveries: { update: vi.fn() } })),
+    $transaction: vi.fn((callback) => callback({ users: mockTxUsers, deliveries: mockTxDeliveries })),
   };
   return { prisma: mockPrisma };
 });

Luego en el test de "Body vacío":

-    expect(prisma.users.update).not.toHaveBeenCalled();
-    expect(prisma.deliveries.update).not.toHaveBeenCalled();
+    expect(mockTxUsers.update).not.toHaveBeenCalled();
+    expect(mockTxDeliveries.update).not.toHaveBeenCalled();

Nota: vi.mock hoistea el factory antes que los imports, por lo que las variables mockTxUsers/mockTxDeliveries deben definirse con vi.hoisted(...) para ser accesibles dentro del factory.

Also applies to: 156-170

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-profile.test.js` at line 17, El mock de $transaction está
pasando objetos anónimos en lugar de las mismas referencias a
prisma.users.update y prisma.deliveries.update, por lo que las aserciones
top-level son falsas positivas; fix: create shared mock references (e.g.
mockTxUsers and mockTxDeliveries) and return those same references from the
vi.mock factory for $transaction so tx.users.update / tx.deliveries.update call
the same spies as prisma.users.update/prisma.deliveries.update, and because
vi.mock factories are hoisted define those spies with vi.hoisted(...) so they
are available inside the factory; update the "Body vacío" test to use these
shared mocks when asserting not.toHaveBeenCalled().

Comment on lines +22 to +24
vi.mock("../../src/modules/images/services/user-image.service.js", () => ({
upsertUserImage: vi.fn().mockResolvedValue("https://storage.example.com/avatar.jpg"),
}));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

vi.resetAllMocks() elimina la implementación por defecto de upsertUserImage, generando falsos positivos en el test de avatar

resetAllMocks reemplaza las implementaciones de los mocks con funciones vacías — es una trampa frecuente porque destruye implementaciones que dependen del factory de vi.mock.

upsertUserImage se define como vi.fn().mockResolvedValue("..."). En Vitest 4, mockReset() solo restaura la implementación original pasada a vi.fn(impl). Como vi.fn() no tiene impl original, .mockResolvedValue(...) (agregado en runtime) se pierde.

Después de cada beforeEach, upsertUserImage retorna undefined. El test de líneas 119–139 igual pasa porque:

  1. expect(upsertUserImage).toHaveBeenCalled() → la función fue invocada (aunque devuelva undefined)
  2. expect(res.body.user).toHaveProperty("avatar_url", "https://...") → se satisface gracias al segundo mock de findUnique, no por lo que realmente retornó upsertUserImage

Esto es un falso positivo: el servicio recibe undefined de upsertUserImage pero el test da verde.

🛠️ Corrección propuesta

Opción A — cambiar a vi.clearAllMocks() (solo limpia el historial de llamadas, no destruye implementaciones):

-  beforeEach(() => vi.resetAllMocks());
+  beforeEach(() => vi.clearAllMocks());

Opción B — si se necesita limpiar también las implementaciones en runtime, re-configurar upsertUserImage en beforeEach:

   beforeEach(() => {
     vi.resetAllMocks();
+    const { upsertUserImage } = await import("../../src/modules/images/services/user-image.service.js");
+    upsertUserImage.mockResolvedValue("https://storage.example.com/avatar.jpg");
   });

Dado que la opción B es asíncrona en un hook, la Opción A (vi.clearAllMocks()) es la más simple y directa.

Also applies to: 75-75, 119-139

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/delivery-profile.test.js` around lines 22 - 24, The tests use
vi.resetAllMocks() which removes the runtime mock implementation of
upsertUserImage (defined via vi.fn().mockResolvedValue(...)) causing false
positives; replace vi.resetAllMocks() with vi.clearAllMocks() so mocks keep
their factory implementations, or if you must reset implementations, reassign
the upsertUserImage mock inside the beforeEach (recreate
vi.mock/vi.fn(...).mockResolvedValue(...)) so the upsertUserImage used by the
code under test always returns the expected URL; update the hooks around the
delivery-profile.test.js cases (and the other occurrences noted) to use
vi.clearAllMocks() or reconfigure upsertUserImage in beforeEach accordingly.

Comment on lines +138 to +141
expect(res.status).toBe(200);
// Si el servicio filtra correctamente, la lista debería estar vacía
expect(Array.isArray(res.body.available_deliveries)).toBe(true);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

La aserción del test de filtrado es trivialmente verdadera y no valida el comportamiento esperado.

El bloque de assertions solo verifica que available_deliveries es un array, lo que siempre será verdadero independientemente de si el servicio filtra o no las asignaciones con estado PENDING/ACCEPTED. El propio comentario en línea dice "la lista debería estar vacía" pero nunca se afirma eso. El test pasará aunque el endpoint devuelva las 2 entregas sin filtrar.

✅ Corrección propuesta: agregar aserción específica sobre el resultado filtrado
     expect(res.status).toBe(200);
-    // Si el servicio filtra correctamente, la lista debería estar vacía
-    expect(Array.isArray(res.body.available_deliveries)).toBe(true);
+    // Ambas entregas tienen asignaciones activas (PENDING/ACCEPTED), por lo que deben ser excluidas
+    expect(res.body.available_deliveries).toHaveLength(0);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expect(res.status).toBe(200);
// Si el servicio filtra correctamente, la lista debería estar vacía
expect(Array.isArray(res.body.available_deliveries)).toBe(true);
});
expect(res.status).toBe(200);
// Ambas entregas tienen asignaciones activas (PENDING/ACCEPTED), por lo que deben ser excluidas
expect(res.body.available_deliveries).toHaveLength(0);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/orders-available-deliveries.test.js` around lines 138 - 141, The
current test only asserts that res.body.available_deliveries is an array, which
is insufficient; update the assertions in
tests/e2e/orders-available-deliveries.test.js to validate the actual filtering
behavior by asserting the array is empty
(expect(res.body.available_deliveries.length).toBe(0)) or by asserting none of
the items have status 'PENDING' or 'ACCEPTED' (e.g.,
expect(res.body.available_deliveries.every(d =>
!['PENDING','ACCEPTED'].includes(d.status))).toBe(true)); replace or augment the
existing expect(Array.isArray(...)) check so the test will fail if the service
does not filter out PENDING/ACCEPTED deliveries.

Comment on lines +143 to +162
// Excluir deliveries INACTIVE
it("retorna 200 cuando filtra correctamente deliveries ACTIVE y estan disponibles", async () => {
prisma.stores.findUnique.mockResolvedValue(mockStore1);
prisma.orders.findFirst.mockResolvedValue(mockOrder);
prisma.deliveryAssignments.findFirst.mockResolvedValue(null);
prisma.deliveryAssignments.findMany.mockResolvedValue([]);
// Se retorna solo deliveries ACTIVE
prisma.deliveries.findMany.mockResolvedValue([mockDeliveryActive1, mockDeliveryActive2]);

const res = await request(app)
.get("/api/stores/1/orders/5/deliveries")
.set("Cookie", sellerCookie1);

expect(res.status).toBe(200);
// Verificar que todos los retornados son ACTIVE
expect(res.body.available_deliveries).toHaveLength(2);
res.body.available_deliveries.forEach((delivery) => {
expect(delivery.id_delivery).toBeLessThanOrEqual(2); // IDs de los ACTIVE
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

El test que describe "Excluir deliveries INACTIVE" no verifica ese comportamiento, y su aserción es frágil.

El mock de deliveries.findMany solo retorna mockDeliveryActive1 y mockDeliveryActive2; nunca se incluye mockDeliveryInactive en el arreglo devuelto. En consecuencia, el test no verifica que el servicio filtra deliveries INACTIVE, sino únicamente que retorna lo que el mock ya provee. Adicionalmente, la aserción en la línea 160 (toBeLessThanOrEqual(2)) está atada a IDs de datos de mock y no refleja ninguna propiedad funcional real del negocio.

✅ Corrección propuesta: incluir entrega INACTIVE en el mock y validar que no aparece en la respuesta
-    // Se retorna solo deliveries ACTIVE
-    prisma.deliveries.findMany.mockResolvedValue([mockDeliveryActive1, mockDeliveryActive2]);
+    // El mock simula que Prisma ya filtra por ACTIVE (como haría la query real con WHERE delivery_status = 'ACTIVE')
+    // pero incluimos el escenario donde el servicio recibe ACTIVE + INACTIVE para asegurar el filtrado
+    prisma.deliveries.findMany.mockResolvedValue([mockDeliveryActive1, mockDeliveryActive2, mockDeliveryInactive]);

     const res = await request(app)
       .get("/api/stores/1/orders/5/deliveries")
       .set("Cookie", sellerCookie1);

     expect(res.status).toBe(200);
-    // Verificar que todos los retornados son ACTIVE
-    expect(res.body.available_deliveries).toHaveLength(2);
-    res.body.available_deliveries.forEach((delivery) => {
-      expect(delivery.id_delivery).toBeLessThanOrEqual(2); // IDs de los ACTIVE
-    });
+    // Solo deben aparecer las entregas ACTIVE, no la INACTIVE
+    expect(res.body.available_deliveries).toHaveLength(2);
+    const returnedIds = res.body.available_deliveries.map((d) => d.id_delivery);
+    expect(returnedIds).not.toContain(mockDeliveryInactive.id_delivery);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/orders-available-deliveries.test.js` around lines 143 - 162, The
test "retorna 200 cuando filtra correctamente deliveries ACTIVE y estan
disponibles" currently only returns ACTIVE mocks and uses a fragile id check;
update prisma.deliveries.findMany to include mockDeliveryInactive alongside
mockDeliveryActive1 and mockDeliveryActive2, then assert that the response
excludes the inactive delivery (e.g., verify no item in
res.body.available_deliveries has id_delivery ===
mockDeliveryInactive.id_delivery or has status === 'INACTIVE') and replace the
id-based toBeLessThanOrEqual(2) assertion with an assertion that every returned
delivery has status 'ACTIVE' (or equivalent domain property) to validate the
filtering logic implemented by the service.

@sonarqubecloud

sonarqubecloud Bot commented May 8, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
15.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@CrisNAC
CrisNAC merged commit 4172726 into dev May 8, 2026
3 of 4 checks passed
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.

3 participants