
> rentaldrivego@1.0.0 test:api
> npm run test --workspace @rentaldrivego/api


> @rentaldrivego/api@1.0.0 pretest
> npm run build --workspace @rentaldrivego/types


> @rentaldrivego/types@1.0.0 build
> tsc


> @rentaldrivego/api@1.0.0 test
> vitest run

[33mThe CJS build of Vite's Node API is deprecated. See https://vite.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.[39m

 RUN  v1.6.1 /Volumes/ExternalApps/Documents/car_management_system/apps/api

 ❯ src/modules/site/site.service.boundary.test.ts  (5 tests | 3 failed) 14ms
   ❯ src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > calculates booking totals from base rate, free-day promo, pricing rules, insurance and additional drivers
     → Cannot read properties of undefined (reading 'catch')
   ❯ src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > rejects payment initialization for already-paid reservations before provider calls
     → expected AppError: Booking access token is required { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)
   ❯ src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > blocks payment when the primary or additional driver license requires review
     → expected AppError: Booking access token is required { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)
 ✓ src/modules/marketplace/marketplace.test.ts  (16 tests) 17ms
 ✓ src/modules/vehicles/vehicle.pricing.service.test.ts  (7 tests) 8ms
 ✓ src/modules/payments/payment.service.test.ts  (7 tests) 8ms
 ✓ src/modules/subscriptions/subscription.service.edge.test.ts  (7 tests) 8ms
 ✓ src/modules/reservations/reservation.test.ts  (14 tests) 11ms
 ✓ src/modules/vehicles/vehicle.test.ts  (15 tests) 10ms
 ❯ src/modules/site/site.test.ts  (13 tests | 5 failed) 20ms
   ❯ src/modules/site/site.test.ts > createBooking > creates a booking and returns reservation with requiresManualApproval flag
     → [vitest] No "createReservationPublicAccess" export is defined on the "./site.repo" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

   ❯ src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when reservation is already paid
     → expected AppError: Booking access token is required { …(3) } to match object { error: 'already_paid' }
(3 matching properties omitted from actual)
   ❯ src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when license review is required
     → expected AppError: Booking access token is required { …(3) } to match object { error: 'license_review_required' }
(3 matching properties omitted from actual)
   ❯ src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when PayPal is not configured
     → expected AppError: Booking access token is required { …(3) } to match object { error: 'provider_not_configured' }
(3 matching properties omitted from actual)
   ❯ src/modules/site/site.test.ts > initPayment — payment guard paths > returns checkoutUrl when PayPal is configured
     → Booking access token is required
 ✓ src/modules/menu/menu.service.test.ts  (2 tests) 4ms
 ❯ src/modules/menu/menu.service.boundary.test.ts  (7 tests | 4 failed) 13ms
   ❯ src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects external links that are not HTTPS before any write
     → expected AppError: External links must use HTTPS. { …(3) } to match object { statusCode: 400, …(1) }
(3 matching properties omitted from actual)
   ❯ src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects duplicate routes under the same parent with a conflict error
     → expected AppError: Parent menu item was not found. { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)
   ❯ src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > protects required menu items from non-super-admin disable attempts
     → expected AppError: Required system items can only … { …(3) } to match object { statusCode: 403, code: 'forbidden' }
(3 matching properties omitted from actual)
   ❯ src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects company assignments when any company is cancelled or missing
     → expected AppError: Menu items can only be assigned… { …(3) } to match object { statusCode: 400, …(1) }
(3 matching properties omitted from actual)
 ✓ src/services/containerService.test.ts  (4 tests) 8ms
 ✓ src/middleware/requireAdminAuth.test.ts  (9 tests) 7ms
 ✓ src/modules/customers/customer.test.ts  (12 tests) 38ms
 ✓ src/modules/reservations/reservation.lifecycle.service.test.ts  (5 tests) 6ms
 ✓ src/modules/reviews/review.service.test.ts  (5 tests) 8ms
 ✓ src/modules/auth/auth.company.service.test.ts  (6 tests) 6ms
 ✓ src/modules/customers/customer.edge.test.ts  (6 tests) 6ms
 ✓ src/modules/analytics/analytics.service.test.ts  (4 tests) 5ms
 ✓ src/modules/auth/auth.employee.service.edge.test.ts  (8 tests) 8ms
 ❯ src/tests/api/auth-middleware.api.test.ts  (8 tests | 2 failed) 55ms
   ❯ src/tests/api/auth-middleware.api.test.ts > auth middleware API boundaries > rejects employee-protected routes when a renter token is used
     → expected { error: 'invalid_token', …(2) } to deeply equal { error: 'invalid_token', …(2) }
   ❯ src/tests/api/auth-middleware.api.test.ts > auth middleware API boundaries > allows valid admin tokens through protected admin read routes
     → expected 403 to be 200 // Object.is equality
 ❯ src/tests/api/public-validation.api.test.ts  (8 tests | 1 failed) 58ms
   ❯ src/tests/api/public-validation.api.test.ts > public validation API contracts > defaults site payment currency to MAD for valid public payment requests
     → expected 400 to be 200 // Object.is equality
 ✓ src/tests/api/auth-boundaries.api.test.ts  (7 tests) 60ms
 ✓ src/tests/api/operations.api.test.ts  (10 tests) 73ms
 ✓ src/modules/companies/company.service.edge.test.ts  (7 tests) 8ms
 ✓ src/tests/api/customer-notification-analytics.api.test.ts  (7 tests) 79ms
 ✓ src/tests/api/operations-validation.api.test.ts  (6 tests) 60ms
 ✓ src/tests/api/company-configuration.api.test.ts  (7 tests) 90ms
 ✓ src/modules/customers/customer.service.boundary.test.ts  (6 tests) 6ms
 ✓ src/middleware/requireApiKey.test.ts  (6 tests) 10ms
 ✓ src/modules/reservations/reservation.inspection.service.test.ts  (5 tests) 8ms
 ✓ src/modules/companies/company.test.ts  (10 tests) 7ms
 ✓ src/services/notificationService.test.ts  (3 tests) 5ms
 ✓ src/services/financialReportService.test.ts  (4 tests) 9ms
 ✓ src/modules/marketplace/marketplace.repo.edge.test.ts  (6 tests) 6ms
 ✓ src/middleware/requireCompanyAuth.test.ts  (6 tests) 9ms
 ❯ src/tests/api/employee-marketplace-notification.api.test.ts  (0 test)
 ✓ src/services/paypalService.test.ts  (4 tests) 12ms
 ✓ src/modules/vehicles/vehicle.service.edge.test.ts  (5 tests) 6ms
 ✓ src/modules/subscriptions/subscription.repo.edge.test.ts  (6 tests) 8ms
 ✓ src/services/vehicleAvailabilityService.test.ts  (5 tests) 6ms
stderr | src/services/notificationLocalizationService.boundary.test.ts > notificationLocalizationService formatting and fallback boundaries > throws a clear error when neither requested nor fallback templates exist
[Notifications] Missing fr template for missing.template/EMAIL; falling back to en.

 ✓ src/services/notificationLocalizationService.boundary.test.ts  (8 tests) 15ms
 ✓ src/modules/site/site.repo.edge.test.ts  (5 tests) 5ms
 ✓ src/modules/marketplace/marketplace.service.edge.test.ts  (5 tests) 5ms
 ✓ src/middleware/requireRenterAuth.test.ts  (6 tests) 8ms
 ✓ src/services/pricingRuleService.test.ts  (3 tests) 5ms
 ✓ src/modules/subscriptions/subscription.entitlement.test.ts  (5 tests) 13ms
 ❯ src/tests/api/feedback-offer-boundaries.api.test.ts  (0 test)
 ✓ src/modules/vehicles/vehicle.schemas.test.ts  (7 tests) 7ms
 ❯ src/tests/api/subscription-team-boundaries.api.test.ts  (0 test)
 ❯ src/tests/api/admin-billing.api.test.ts  (6 tests | 5 failed) 73ms
   ❯ src/tests/api/admin-billing.api.test.ts > admin billing API contracts > coerces list filters and requires finance access
     → expected 403 to be 200 // Object.is equality
   ❯ src/tests/api/admin-billing.api.test.ts > admin billing API contracts > rejects oversized billing pagination before service execution
     → expected 403 to be 400 // Object.is equality
   ❯ src/tests/api/admin-billing.api.test.ts > admin billing API contracts > streams invoice PDFs with content headers from the service boundary
     → expected 403 to be 200 // Object.is equality
   ❯ src/tests/api/admin-billing.api.test.ts > admin billing API contracts > passes parsed account updates with admin identity and request ip
     → expected 403 to be 200 // Object.is equality
   ❯ src/tests/api/admin-billing.api.test.ts > admin billing API contracts > rejects malformed draft invoice payloads before invoice creation
     → expected 403 to be 400 // Object.is equality
 ✓ src/modules/auth/auth.company.repo.test.ts  (1 test) 6ms
 ✓ src/modules/vehicles/vehicle.repo.edge.test.ts  (5 tests) 7ms
 ✓ src/tests/api/vehicle-pricing.api.test.ts  (5 tests) 68ms
 ✓ src/modules/notifications/notification.repo.edge.test.ts  (6 tests) 10ms
 ✓ src/modules/offers/offer.repo.edge.test.ts  (5 tests) 7ms
 ✓ src/modules/notifications/notification.service.test.ts  (4 tests) 5ms
 ✓ src/modules/companies/company.repo.edge.test.ts  (6 tests) 6ms
 ✓ src/services/amanpayService.test.ts  (4 tests) 14ms
 ✓ src/modules/companies/company.presenter.test.ts  (14 tests) 4ms
 ✓ src/modules/auth/auth.schemas.test.ts  (3 tests) 5ms
 ❯ src/tests/api/admin-menu-boundaries.api.test.ts  (5 tests | 5 failed) 76ms
   ❯ src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > rejects menu item creation with blank labels before service execution
     → expected 403 to be 400 // Object.is equality
   ❯ src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > passes normalized menu item creation payload with admin actor
     → expected 403 to be 201 // Object.is equality
   ❯ src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > rejects invalid menu status bodies before mutation
     → expected 403 to be 400 // Object.is equality
   ❯ src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > requires admin privileges for menu mutations while support can preview
     → expected 403 to be 200 // Object.is equality
   ❯ src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > coerces audit-log pagination defaults and caps oversized limits
     → expected 403 to be 200 // Object.is equality
 ✓ src/modules/reservations/reservation.repo.edge.test.ts  (4 tests) 4ms
 ✓ src/modules/complaints/complaint.service.test.ts  (5 tests) 5ms
 ✓ src/modules/offers/offer.service.test.ts  (5 tests) 4ms
 ✓ src/modules/auth/auth.role-specific-schemas.test.ts  (5 tests) 5ms
 ✓ src/modules/reservations/reservation.presenter.boundary.test.ts  (6 tests) 4ms
 ❯ src/http/errors/errorMiddleware.test.ts  (10 tests | 1 failed) 10ms
   ❯ src/http/errors/errorMiddleware.test.ts > errorMiddleware > falls back to a 500 internal error response
     → expected "spy" to be called with arguments: [ { error: 'internal_error', …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "error": "internal_error",
-     "message": "boom",
+     "message": "Internal server error",
+     "requestId": undefined,
      "statusCode": 500,
    },
  ]


Number of calls: 1

 ✓ src/modules/reservations/reservation.document.service.test.ts  (3 tests) 2ms
 ✓ src/modules/auth/auth.presenter.test.ts  (4 tests) 3ms
 ✓ src/modules/reservations/reservation.photo.service.test.ts  (4 tests) 4ms
 ✓ src/modules/auth/auth.renter.service.test.ts  (5 tests) 5ms
 ✓ src/modules/operations.schemas.test.ts  (2 tests) 6ms
 ✓ src/services/notificationLocalizationService.test.ts  (3 tests) 5ms
stderr | src/services/notificationLocalizationService.test.ts > notificationLocalizationService > falls back to English when a localized template is missing
[Notifications] Missing ar template for booking.confirmed/EMAIL; falling back to en.

 ❯ src/tests/api/payments.api.test.ts  (5 tests | 2 failed) 94ms
   ❯ src/tests/api/payments.api.test.ts > payments API contract > accepts valid AmanPay webhooks and delegates the exact payload
     → expected "spy" to be called with arguments: [ { transaction_id: 'txn_1', …(1) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "status": "PAID",
      "transaction_id": "txn_1",
    },
+   "{\"transaction_id\":\"txn_1\",\"status\":\"PAID\"}",
  ]


Number of calls: 1

   ❯ src/tests/api/payments.api.test.ts > payments API contract > accepts verified PayPal webhooks and delegates handling
     → expected "spy" to be called with arguments: [ { …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "event_type": "PAYMENT.CAPTURE.COMPLETED",
      "resource": Object {
        "id": "capture_1",
      },
    },
+   "{\"event_type\":\"PAYMENT.CAPTURE.COMPLETED\",\"resource\":{\"id\":\"capture_1\"}}",
  ]


Number of calls: 1

 ❯ src/modules/site/site.schemas.test.ts  (4 tests | 1 failed) 12ms
   ❯ src/modules/site/site.schemas.test.ts > site.schemas > rejects malformed availability and payment payloads at the schema layer
     → [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "accessToken"
    ],
    "message": "Required"
  }
]
 ✓ src/services/insuranceService.test.ts  (2 tests) 4ms
 ✓ src/tests/api/site-webhook-boundaries.api.test.ts  (5 tests) 116ms
 ✓ src/modules/companies/company.schemas.edge.test.ts  (3 tests) 8ms
 ✓ src/services/additionalDriverService.test.ts  (3 tests) 5ms
 ✓ src/middleware/rateLimiter.test.ts  (3 tests) 11ms
 ✓ src/modules/payments/payment.repo.edge.test.ts  (5 tests) 7ms
 ✓ src/modules/reservations/reservation.schemas.edge.test.ts  (3 tests) 7ms
 ✓ src/lib/storage.test.ts  (4 tests) 4ms
 ❯ src/tests/api/subscriptions.api.test.ts  (5 tests | 1 failed) 65ms
   ❯ src/tests/api/subscriptions.api.test.ts > subscriptions public API > accepts verified PayPal webhooks and delegates handling to the subscription service
     → expected "spy" to be called with arguments: [ { …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "event_type": "PAYMENT.CAPTURE.COMPLETED",
      "resource": Object {
        "id": "capture_1",
      },
    },
+   "{\"event_type\":\"PAYMENT.CAPTURE.COMPLETED\",\"resource\":{\"id\":\"capture_1\"}}",
  ]


Number of calls: 1

 ✓ src/modules/complaints/complaint.repo.edge.test.ts  (4 tests) 4ms
 ❯ src/lib/emailTranslations.test.ts  (5 tests | 1 failed) 8ms
   ❯ src/lib/emailTranslations.test.ts > emailTranslations > formats dates with the locale-specific formatter
     → expected '2 فبراير 2026' to contain '٢٠٢٦'
 ✓ src/middleware/requireSubscription.test.ts  (4 tests) 5ms
 ✓ src/services/licenseValidationService.test.ts  (4 tests) 6ms
 ✓ src/modules/reviews/review.repo.edge.test.ts  (4 tests) 7ms
 ✓ src/modules/admin/admin.repo.edge.test.ts  (3 tests) 8ms
 ✓ src/modules/subscriptions/subscription.schemas.edge.test.ts  (4 tests) 3ms
 ❯ src/services/platformContentService.test.ts  (2 tests | 2 failed) 14ms
   ❯ src/services/platformContentService.test.ts > platformContentService > returns cloned default homepage content when the file does not exist or cannot be parsed
     → process.chdir() is not supported in workers
     → process.chdir() is not supported in workers
   ❯ src/services/platformContentService.test.ts > platformContentService > saves only the marketplace homepage field while preserving unrelated platform content fields
     → process.chdir() is not supported in workers
     → process.chdir() is not supported in workers
 ✓ src/modules/auth/auth.employee.service.test.ts  (2 tests) 659ms
 ✓ src/services/teamService.test.ts  (1 test) 3ms
 ✓ src/middleware/requireTenant.test.ts  (3 tests) 3ms
 ✓ src/modules/auth/auth.employee.repo.edge.test.ts  (5 tests) 7ms
 ✓ src/tests/api/api-foundation.api.test.ts  (6 tests) 79ms
 ✓ src/swagger/openapi.boundary.test.ts  (3 tests) 4ms
 ✓ src/modules/customers/customer.schemas.contract.test.ts  (5 tests) 5ms
 ❯ src/services/invoicePdfService.test.ts  (2 tests | 1 failed) 11ms
   ❯ src/services/invoicePdfService.test.ts > invoicePdfService > builds stable legacy invoice numbers from the creation year and id suffix
     → expected 'INV-2026-SHORT' to be 'INV-2027-SHORT' // Object.is equality
 ✓ src/modules/customers/customer.repo.boundary.test.ts  (3 tests) 10ms
 ✓ src/middleware/authHelpers.test.ts  (5 tests) 4ms
 ✓ src/modules/admin/admin.menu.schemas.test.ts  (4 tests) 5ms
 ✓ src/modules/admin/admin.billing.schemas.test.ts  (4 tests) 5ms
 ✓ src/modules/marketplace/marketplace.schemas.test.ts  (4 tests) 8ms
 ❯ src/tests/e2e/vehicle-pricing-boundaries.e2e.test.ts  (1 test | 1 failed) 50ms
   ❯ src/tests/e2e/vehicle-pricing-boundaries.e2e.test.ts > vehicle pricing e2e boundaries > rejects anonymous and malformed pricing requests without invoking pricing services
     → expected 401 to be 400 // Object.is equality
 ✓ src/modules/reservations/reservation.additional-driver.service.test.ts  (2 tests) 3ms
 ✓ src/tests/e2e/operations-validation-smoke.e2e.test.ts  (1 test) 53ms
 ✓ src/tests/e2e/public-validation-smoke.e2e.test.ts  (1 test) 109ms
 ✓ src/modules/subscriptions/subscription.policy.test.ts  (4 tests) 5ms
 ✓ src/modules/site/site.presenter.test.ts  (2 tests) 3ms
 ✓ src/middleware/requireRole.test.ts  (3 tests) 4ms
 ❯ src/http/upload/upload.test.ts  (4 tests | 3 failed) 7ms
   ❯ src/http/upload/upload.test.ts > upload assertions > accepts a single image file and narrows the route input
     → expected [Function] to not throw an error but 'ValidationError: Unsupported or spoof…' was thrown
   ❯ src/http/upload/upload.test.ts > upload assertions > rejects non-image single file uploads
     → expected [Function] to throw error including 'Only image uploads are supported' but got 'Unsupported or spoofed image file'
   ❯ src/http/upload/upload.test.ts > upload assertions > accepts multiple image files and rejects empty or mixed batches
     → expected [Function] to not throw an error but 'ValidationError: Unsupported or spoof…' was thrown
 ✓ src/modules/team/team.service.test.ts  (2 tests) 3ms
 ✓ src/modules/team/team.schemas.edge.test.ts  (3 tests) 3ms
 ✓ src/modules/payments/payment.schemas.edge.test.ts  (2 tests) 4ms
 ✓ src/modules/customers/customer.presenter.test.ts  (2 tests) 3ms
 ✓ src/modules/offers/offer.schemas.edge.test.ts  (4 tests) 6ms
 ✓ src/tests/e2e/customer-boundaries.e2e.test.ts  (1 test) 61ms
 ✓ src/http/respond/respond.test.ts  (3 tests) 5ms
 ✓ src/modules/notifications/notification.schemas.edge.test.ts  (3 tests) 5ms
 ✓ src/modules/admin/admin.service.test.ts  (1 test) 3ms
 ✓ src/modules/complaints/complaint.schemas.edge.test.ts  (5 tests) 6ms
 ✓ src/modules/reservations/reservation.pricing.service.test.ts  (3 tests) 2ms
 ❯ src/tests/e2e/admin-billing-boundaries.e2e.test.ts  (1 test | 1 failed) 36ms
   ❯ src/tests/e2e/admin-billing-boundaries.e2e.test.ts > admin billing e2e boundaries > rejects anonymous billing access and malformed invoice creation without touching services
     → expected 401 to be 400 // Object.is equality
 ✓ src/tests/e2e/subscriptions-public.e2e.test.ts  (1 test) 64ms
 ✓ src/modules/reservations/reservation.presenter.test.ts  (1 test) 1ms
 ✓ src/modules/vehicles/vehicle.presenter.edge.test.ts  (2 tests) 2ms
 ✓ src/http/validate/validate.test.ts  (3 tests) 7ms
 ❯ src/tests/e2e/admin-menu-boundaries.e2e.test.ts  (0 test)
 ✓ src/modules/auth/auth.employee.repo.test.ts  (2 tests) 2ms
 ✓ src/tests/e2e/api-smoke.e2e.test.ts  (1 test) 58ms
 ✓ src/modules/admin/admin.presenter.test.ts  (3 tests) 2ms
 ✓ src/tests/e2e/site-webhook-boundaries.e2e.test.ts  (1 test) 44ms
 ✓ src/modules/reviews/review.schemas.edge.test.ts  (4 tests) 4ms
 ✓ src/tests/e2e/storage-boundaries.e2e.test.ts  (1 test) 33ms
 ✓ src/modules/marketplace/marketplace.presenter.test.ts  (1 test) 2ms
 ✓ src/lib/isDatabaseUnavailable.test.ts  (3 tests) 2ms
 ✓ src/modules/analytics/analytics.schemas.edge.test.ts  (3 tests) 6ms
 ✓ src/modules/admin/admin.repo.test.ts  (1 test) 3ms
 ✓ src/tests/e2e/payments-webhook-public.e2e.test.ts  (1 test) 29ms
 ✓ src/tests/e2e/protected-auth-boundaries.e2e.test.ts  (1 test) 35ms
 ✓ src/tests/e2e/operations-auth-boundaries.e2e.test.ts  (1 test) 43ms
 ✓ src/tests/e2e/feedback-offer-boundaries.e2e.test.ts  (1 test) 34ms
 ✓ src/tests/e2e/employee-marketplace-boundaries.e2e.test.ts  (2 tests) 40ms
 ✓ src/tests/e2e/auth-public-disabled.e2e.test.ts  (1 test) 27ms
 ✓ src/tests/e2e/subscription-team-boundaries.e2e.test.ts  (1 test) 23ms
 ✓ src/tests/e2e/company-configuration-boundaries.e2e.test.ts  (1 test) 17ms

⎯⎯⎯⎯⎯⎯ Failed Suites 4 ⎯⎯⎯⎯⎯⎯⎯

 FAIL  src/tests/api/employee-marketplace-notification.api.test.ts [ src/tests/api/employee-marketplace-notification.api.test.ts ]
 FAIL  src/tests/api/feedback-offer-boundaries.api.test.ts [ src/tests/api/feedback-offer-boundaries.api.test.ts ]
 FAIL  src/tests/api/subscription-team-boundaries.api.test.ts [ src/tests/api/subscription-team-boundaries.api.test.ts ]
Error: [vitest] No "requireCompanyDocumentAuth" export is defined on the "../../middleware/requireCompanyAuth" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock("../../middleware/requireCompanyAuth", async (importOriginal) => {
  const actual = await importOriginal()
  return {
    ...actual,
    // your mocked methods
  }
})

 ❯ src/modules/customers/customer.routes.ts:14:34
     12| const router = Router()
     13| 
     14| router.get('/:id/license-image', requireCompanyDocumentAuth, requireTe…
       |                                  ^
     15|   try {
     16|     const { id } = parseParams(idParamSchema, req)
 ❯ src/app.ts:21:32

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/45]⎯

 FAIL  src/tests/e2e/admin-menu-boundaries.e2e.test.ts [ src/tests/e2e/admin-menu-boundaries.e2e.test.ts ]
Error: [vitest] No "requireFreshAdmin2FA" export is defined on the "../../middleware/requireAdminAuth" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock("../../middleware/requireAdminAuth", async (importOriginal) => {
  const actual = await importOriginal()
  return {
    ...actual,
    // your mocked methods
  }
})

 ❯ src/modules/admin/admin.routes.ts:99:70
     97| })
     98| 
     99| router.post('/auth/2fa/recovery-codes/regenerate', requireAdminAuth, r…
       |                                                                      ^
    100|   try {
    101|     ok(res, await service.regenerateRecoveryCodes(req.admin.id))
 ❯ src/app.ts:18:32

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/45]⎯

⎯⎯⎯⎯⎯⎯ Failed Tests 39 ⎯⎯⎯⎯⎯⎯⎯

 FAIL  src/lib/emailTranslations.test.ts > emailTranslations > formats dates with the locale-specific formatter
AssertionError: expected '2 فبراير 2026' to contain '٢٠٢٦'

- Expected
+ Received

- ٢٠٢٦
+ 2 فبراير 2026

 ❯ src/lib/emailTranslations.test.ts:67:68
     65|     expect(formatDate(new Date('2026-02-03T00:00:00.000Z'), 'en')).toC…
     66|     expect(formatDate(new Date('2026-02-03T00:00:00.000Z'), 'fr')).toC…
     67|     expect(formatDate(new Date('2026-02-03T00:00:00.000Z'), 'ar')).toC…
       |                                                                    ^
     68|   })
     69| })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/45]⎯

 FAIL  src/services/invoicePdfService.test.ts > invoicePdfService > builds stable legacy invoice numbers from the creation year and id suffix
AssertionError: expected 'INV-2026-SHORT' to be 'INV-2027-SHORT' // Object.is equality

- Expected
+ Received

- INV-2027-SHORT
+ INV-2026-SHORT

 ❯ src/services/invoicePdfService.test.ts:23:79
     21|   it('builds stable legacy invoice numbers from the creation year and …
     22|     expect(buildInvoiceNumber('invoice_abcdef', new Date('2026-06-09T1…
     23|     expect(buildInvoiceNumber('short', new Date('2027-01-01T00:00:00.0…
       |                                                                               ^
     24|   })
     25| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/45]⎯

 FAIL  src/services/platformContentService.test.ts > platformContentService > returns cloned default homepage content when the file does not exist or cannot be parsed
 FAIL  src/services/platformContentService.test.ts > platformContentService > saves only the marketplace homepage field while preserving unrelated platform content fields
TypeError: process.chdir() is not supported in workers
 ❯ src/services/platformContentService.test.ts:19:13
     17|     tempDir = await mkdtemp(path.join(os.tmpdir(), 'rdg-platform-conte…
     18|     await import('fs/promises').then((fs) => fs.mkdir(path.join(tempDi…
     19|     process.chdir(path.join(tempDir, 'apps/api'))
       |             ^
     20|   })
     21| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_WORKER_UNSUPPORTED_OPERATION' }
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/45]⎯

 FAIL  src/services/platformContentService.test.ts > platformContentService > returns cloned default homepage content when the file does not exist or cannot be parsed
 FAIL  src/services/platformContentService.test.ts > platformContentService > saves only the marketplace homepage field while preserving unrelated platform content fields
TypeError: process.chdir() is not supported in workers
 ❯ src/services/platformContentService.test.ts:23:13
     21| 
     22|   afterEach(async () => {
     23|     process.chdir(originalCwd)
       |             ^
     24|     await rm(tempDir, { recursive: true, force: true })
     25|     vi.resetModules()

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_WORKER_UNSUPPORTED_OPERATION' }
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/45]⎯

 FAIL  src/http/errors/errorMiddleware.test.ts > errorMiddleware > falls back to a 500 internal error response
AssertionError: expected "spy" to be called with arguments: [ { error: 'internal_error', …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "error": "internal_error",
-     "message": "boom",
+     "message": "Internal server error",
+     "requestId": undefined,
      "statusCode": 500,
    },
  ]


Number of calls: 1

 ❯ src/http/errors/errorMiddleware.test.ts:95:22
     93| 
     94|     expect(res.status).toHaveBeenCalledWith(500)
     95|     expect(res.json).toHaveBeenCalledWith({ error: 'internal_error', m…
       |                      ^
     96| 
     97|     spy.mockRestore()

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/45]⎯

 FAIL  src/http/upload/upload.test.ts > upload assertions > accepts a single image file and narrows the route input
AssertionError: expected [Function] to not throw an error but 'ValidationError: Unsupported or spoof…' was thrown

- Expected: 
undefined

+ Received: 
"ValidationError: Unsupported or spoofed image file"

 ❯ src/http/upload/upload.test.ts:21:47
     19| describe('upload assertions', () => {
     20|   it('accepts a single image file and narrows the route input', () => {
     21|     expect(() => assertImageFile(file())).not.toThrow()
       |                                               ^
     22|   })
     23| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/45]⎯

 FAIL  src/http/upload/upload.test.ts > upload assertions > rejects non-image single file uploads
AssertionError: expected [Function] to throw error including 'Only image uploads are supported' but got 'Unsupported or spoofed image file'

- Expected
+ Received

- Only image uploads are supported
+ Unsupported or spoofed image file

 ❯ src/http/upload/upload.test.ts:30:103
     28| 
     29|   it('rejects non-image single file uploads', () => {
     30|     expect(() => assertImageFile(file({ mimetype: 'application/pdf', o…
       |                                                                                                       ^
     31|   })
     32| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/45]⎯

 FAIL  src/http/upload/upload.test.ts > upload assertions > accepts multiple image files and rejects empty or mixed batches
AssertionError: expected [Function] to not throw an error but 'ValidationError: Unsupported or spoof…' was thrown

- Expected: 
undefined

+ Received: 
"ValidationError: Unsupported or spoofed image file"

 ❯ src/http/upload/upload.test.ts:34:102
     32| 
     33|   it('accepts multiple image files and rejects empty or mixed batches'…
     34|     expect(() => assertImageFiles([file({ originalname: 'front.png', m…
       |                                                                                                      ^
     35|     expect(() => assertImageFiles([], 'inspection photos')).toThrow('A…
     36|     expect(() => assertImageFiles([

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/45]⎯

 FAIL  src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects external links that are not HTTPS before any write
AssertionError: expected AppError: External links must use HTTPS. { …(3) } to match object { statusCode: 400, …(1) }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "validation_error",
    "statusCode": 400,
  }

 ❯ src/modules/menu/menu.service.boundary.test.ts:45:5
     43| 
     44|   it('rejects external links that are not HTTPS before any write', asy…
     45|     await expect(createMenuItem({
       |     ^
     46|       label: 'Docs',
     47|       itemType: 'EXTERNAL_LINK',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/45]⎯

 FAIL  src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects duplicate routes under the same parent with a conflict error
AssertionError: expected AppError: Parent menu item was not found. { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "duplicate_menu_route",
-   "statusCode": 409,
+   "statusCode": 400,
  }

 ❯ src/modules/menu/menu.service.boundary.test.ts:58:5
     56|     vi.mocked(prisma.menuItem.findFirst).mockResolvedValue({ id: 'item…
     57| 
     58|     await expect(createMenuItem({
       |     ^
     59|       label: 'Fleet',
     60|       itemType: 'INTERNAL_PAGE',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/45]⎯

 FAIL  src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > protects required menu items from non-super-admin disable attempts
AssertionError: expected AppError: Required system items can only … { …(3) } to match object { statusCode: 403, code: 'forbidden' }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "forbidden",
    "statusCode": 403,
  }

 ❯ src/modules/menu/menu.service.boundary.test.ts:121:5
    119|     vi.mocked(prisma.menuItem.findUniqueOrThrow).mockResolvedValue({ i…
    120| 
    121|     await expect(setMenuItemStatus('item_core', false, admin)).rejects…
       |     ^
    122| 
    123|     expect(prisma.menuItem.update).not.toHaveBeenCalled()

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/45]⎯

 FAIL  src/modules/menu/menu.service.boundary.test.ts > menu.service mutation boundaries > rejects company assignments when any company is cancelled or missing
AssertionError: expected AppError: Menu items can only be assigned… { …(3) } to match object { statusCode: 400, …(1) }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "validation_error",
    "statusCode": 400,
  }

 ❯ src/modules/menu/menu.service.boundary.test.ts:149:5
    147|     vi.mocked(prisma.company.findMany).mockResolvedValue([{ id: 'compa…
    148| 
    149|     await expect(assignMenuItemToCompanies('item_1', [
       |     ^
    150|       { companyId: 'company_1' },
    151|       { companyId: 'company_cancelled' },

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/45]⎯

 FAIL  src/modules/site/site.schemas.test.ts > site.schemas > rejects malformed availability and payment payloads at the schema layer
ZodError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "accessToken"
    ],
    "message": "Required"
  }
]
 ❯ Object.get error [as error] ../../node_modules/zod/v3/types.js:39:31
 ❯ ZodObject.parse ../../node_modules/zod/v3/types.js:114:22
 ❯ src/modules/site/site.schemas.test.ts:53:22
     51|     expect(() => availabilitySchema.parse({ vehicleId: 'not-cuid', sta…
     52|     expect(() => paySchema.parse({ provider: 'STRIPE', successUrl: 'ht…
     53|     expect(paySchema.parse({ provider: 'PAYPAL', successUrl: 'https://…
       |                      ^
     54|   })
     55| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { issues: [ { code: 'invalid_type', expected: 'string', received: 'undefined', path: [ 'accessToken' ], message: 'Required' } ], addIssue: 'Function<anonymous>', addIssues: 'Function<anonymous>', errors: [ { code: 'invalid_type', expected: 'string', received: 'undefined', path: [ 'accessToken' ], message: 'Required' } ], format: 'Function<format>', isEmpty: false, flatten: 'Function<flatten>', formErrors: { formErrors: [], fieldErrors: { accessToken: [ 'Required' ] } } }
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/45]⎯

 FAIL  src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > calculates booking totals from base rate, free-day promo, pricing rules, insurance and additional drivers
TypeError: Cannot read properties of undefined (reading 'catch')
 ❯ Module.createBooking src/modules/site/site.service.ts:223:45
    221|   }
    222|   if (body.licenseExpiry) {
    223|     await validateAndFlagLicense(customer.id).catch(() => null)
       |                                             ^
    224|   }
    225| 
 ❯ src/modules/site/site.service.boundary.test.ts:107:20

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/45]⎯

 FAIL  src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > rejects payment initialization for already-paid reservations before provider calls
AssertionError: expected AppError: Booking access token is required { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "already_paid",
-   "statusCode": 409,
+   "statusCode": 403,
  }

 ❯ src/modules/site/site.service.boundary.test.ts:131:5
    129|     vi.mocked(repo.findReservationForPayment).mockResolvedValue({ paym…
    130| 
    131|     await expect(service.initPayment('atlas', 'reservation_1', {
       |     ^
    132|       provider: 'AMANPAY',
    133|       successUrl: 'https://example.test/success',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/45]⎯

 FAIL  src/modules/site/site.service.boundary.test.ts > site.service public booking/payment boundaries > blocks payment when the primary or additional driver license requires review
AssertionError: expected AppError: Booking access token is required { …(3) } to match object { statusCode: 409, …(1) }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "code": "license_review_required",
-   "statusCode": 409,
+   "statusCode": 403,
  }

 ❯ src/modules/site/site.service.boundary.test.ts:150:5
    148|     } as never)
    149| 
    150|     await expect(service.initPayment('atlas', 'reservation_1', {
       |     ^
    151|       provider: 'PAYPAL',
    152|       successUrl: 'https://example.test/success',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/45]⎯

 FAIL  src/modules/site/site.test.ts > createBooking > creates a booking and returns reservation with requiresManualApproval flag
Error: [vitest] No "createReservationPublicAccess" export is defined on the "./site.repo" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock("./site.repo", async (importOriginal) => {
  const actual = await importOriginal()
  return {
    ...actual,
    // your mocked methods
  }
})

 ❯ Module.createBooking src/modules/site/site.service.ts:227:14
    225| 
    226|   const publicAccess = generatePublicAccessToken()
    227|   await repo.createReservationPublicAccess(
       |              ^
    228|     reservation.id,
    229|     publicAccess.tokenHash,
 ❯ src/modules/site/site.test.ts:175:20

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/45]⎯

 FAIL  src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when reservation is already paid
AssertionError: expected AppError: Booking access token is required { …(3) } to match object { error: 'already_paid' }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "error": "already_paid",
+   "error": "booking_token_required",
  }

 ❯ src/modules/site/site.test.ts:211:5
    209|     vi.mocked(validateLicense).mockReturnValue({ status: 'VALID', requ…
    210| 
    211|     await expect(initPayment(SLUG, 'r-1', payBody)).rejects.toMatchObj…
       |     ^
    212|   })
    213| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/45]⎯

 FAIL  src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when license review is required
AssertionError: expected AppError: Booking access token is required { …(3) } to match object { error: 'license_review_required' }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "error": "license_review_required",
+   "error": "booking_token_required",
  }

 ❯ src/modules/site/site.test.ts:224:5
    222|     vi.mocked(validateLicense).mockReturnValue({ status: 'VALID', requ…
    223| 
    224|     await expect(initPayment(SLUG, 'r-1', payBody)).rejects.toMatchObj…
       |     ^
    225|   })
    226| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/45]⎯

 FAIL  src/modules/site/site.test.ts > initPayment — payment guard paths > throws AppError when PayPal is not configured
AssertionError: expected AppError: Booking access token is required { …(3) } to match object { error: 'provider_not_configured' }
(3 matching properties omitted from actual)

- Expected
+ Received

  Object {
-   "error": "provider_not_configured",
+   "error": "booking_token_required",
  }

 ❯ src/modules/site/site.test.ts:238:5
    236|     vi.mocked(paypalSvc.isConfigured).mockReturnValue(false)
    237| 
    238|     await expect(initPayment(SLUG, 'r-1', payBody)).rejects.toMatchObj…
       |     ^
    239|   })
    240| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/45]⎯

 FAIL  src/modules/site/site.test.ts > initPayment — payment guard paths > returns checkoutUrl when PayPal is configured
AppError: Booking access token is required
 ❯ assertPublicBookingAccess src/modules/site/site.service.ts:244:21
    242| 
    243| async function assertPublicBookingAccess(reservationId: string, token:…
    244|   if (!token) throw new AppError('Booking access token is required', 4…
       |                     ^
    245|   const access = await repo.findReservationPublicAccess(reservationId,…
    246|   if (!access) throw new AppError('Booking not found', 404, 'not_found…
 ❯ Module.initPayment src/modules/site/site.service.ts:260:9
 ❯ src/modules/site/site.test.ts:254:20

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { statusCode: 403, error: 'booking_token_required', data: undefined }
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/45]⎯

 FAIL  src/tests/api/admin-billing.api.test.ts > admin billing API contracts > coerces list filters and requires finance access
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/admin-billing.api.test.ts:56:24
     54|       .set('Authorization', 'Bearer admin-token')
     55| 
     56|     expect(res.status).toBe(200)
       |                        ^
     57|     expect(adminService.getBilling).toHaveBeenCalledWith({
     58|       q: 'atlas',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/45]⎯

 FAIL  src/tests/api/admin-billing.api.test.ts > admin billing API contracts > rejects oversized billing pagination before service execution
AssertionError: expected 403 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 403

 ❯ src/tests/api/admin-billing.api.test.ts:71:24
     69|       .set('Authorization', 'Bearer admin-token')
     70| 
     71|     expect(res.status).toBe(400)
       |                        ^
     72|     expect(adminService.getBilling).not.toHaveBeenCalled()
     73|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/45]⎯

 FAIL  src/tests/api/admin-billing.api.test.ts > admin billing API contracts > streams invoice PDFs with content headers from the service boundary
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/admin-billing.api.test.ts:85:24
     83|       .set('Authorization', 'Bearer admin-token')
     84| 
     85|     expect(res.status).toBe(200)
       |                        ^
     86|     expect(res.header['content-type']).toContain('application/pdf')
     87|     expect(res.header['content-disposition']).toContain('INV-2026-0000…

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/45]⎯

 FAIL  src/tests/api/admin-billing.api.test.ts > admin billing API contracts > passes parsed account updates with admin identity and request ip
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/admin-billing.api.test.ts:99:24
     97|       .send({ billingEmail: 'billing@example.test', invoiceTerms: 'NET…
     98| 
     99|     expect(res.status).toBe(200)
       |                        ^
    100|     expect(adminService.updateBillingAccount).toHaveBeenCalledWith(
    101|       'billing_account_1',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[27/45]⎯

 FAIL  src/tests/api/admin-billing.api.test.ts > admin billing API contracts > rejects malformed draft invoice payloads before invoice creation
AssertionError: expected 403 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 403

 ❯ src/tests/api/admin-billing.api.test.ts:114:24
    112|       .send({ invoiceType: 'MANUAL', lineItems: [] })
    113| 
    114|     expect(res.status).toBe(400)
       |                        ^
    115|     expect(adminService.createBillingInvoice).not.toHaveBeenCalled()
    116|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[28/45]⎯

 FAIL  src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > rejects menu item creation with blank labels before service execution
AssertionError: expected 403 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 403

 ❯ src/tests/api/admin-menu-boundaries.api.test.ts:51:24
     49|       .send({ label: '   ', itemType: 'INTERNAL_PAGE', routeOrUrl: '/f…
     50| 
     51|     expect(res.status).toBe(400)
       |                        ^
     52|     expect(menuService.createMenuItem).not.toHaveBeenCalled()
     53|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[29/45]⎯

 FAIL  src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > passes normalized menu item creation payload with admin actor
AssertionError: expected 403 to be 201 // Object.is equality

- Expected
+ Received

- 201
+ 403

 ❯ src/tests/api/admin-menu-boundaries.api.test.ts:63:24
     61|       .send({ label: ' Fleet ', itemType: 'INTERNAL_PAGE', routeOrUrl:…
     62| 
     63|     expect(res.status).toBe(201)
       |                        ^
     64|     expect(menuService.createMenuItem).toHaveBeenCalledWith(
     65|       expect.objectContaining({ label: 'Fleet', itemType: 'INTERNAL_PA…

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[30/45]⎯

 FAIL  src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > rejects invalid menu status bodies before mutation
AssertionError: expected 403 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 403

 ❯ src/tests/api/admin-menu-boundaries.api.test.ts:76:24
     74|       .send({ isActive: 'false' })
     75| 
     76|     expect(res.status).toBe(400)
       |                        ^
     77|     expect(menuService.setMenuItemStatus).not.toHaveBeenCalled()
     78|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[31/45]⎯

 FAIL  src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > requires admin privileges for menu mutations while support can preview
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/admin-menu-boundaries.api.test.ts:94:31
     92|       .set('Authorization', 'Bearer admin-token')
     93|       .send({ companyId: 'company_1', role: 'MANAGER' })
     94|     expect(previewRes.status).toBe(200)
       |                               ^
     95|     expect(menuService.previewCompanyMenu).toHaveBeenCalledWith({ comp…
     96|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[32/45]⎯

 FAIL  src/tests/api/admin-menu-boundaries.api.test.ts > admin menu API contracts > coerces audit-log pagination defaults and caps oversized limits
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/admin-menu-boundaries.api.test.ts:104:31
    102|       .get('/api/v1/admin/menu-audit-logs')
    103|       .set('Authorization', 'Bearer admin-token')
    104|     expect(defaultRes.status).toBe(200)
       |                               ^
    105|     expect(menuService.listMenuAuditLogs).toHaveBeenCalledWith({ page:…
    106| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[33/45]⎯

 FAIL  src/tests/api/auth-middleware.api.test.ts > auth middleware API boundaries > rejects employee-protected routes when a renter token is used
AssertionError: expected { error: 'invalid_token', …(2) } to deeply equal { error: 'invalid_token', …(2) }

- Expected
+ Received

  Object {
    "error": "invalid_token",
-   "message": "Invalid token type for this endpoint",
+   "message": "Invalid or expired session token",
    "statusCode": 401,
  }

 ❯ src/tests/api/auth-middleware.api.test.ts:72:22
     70| 
     71|     expect(res.status).toBe(401)
     72|     expect(res.body).toEqual({ error: 'invalid_token', message: 'Inval…
       |                      ^
     73|     expect(prisma.employee.findUnique).not.toHaveBeenCalled()
     74|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[34/45]⎯

 FAIL  src/tests/api/auth-middleware.api.test.ts > auth middleware API boundaries > allows valid admin tokens through protected admin read routes
AssertionError: expected 403 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 403

 ❯ src/tests/api/auth-middleware.api.test.ts:146:24
    144|     const res = await request(app).get('/api/v1/admin/companies').set(…
    145| 
    146|     expect(res.status).toBe(200)
       |                        ^
    147|     expect(res.body).toEqual({ data: { data: [{ id: 'company_1' }], pa…
    148|     expect(adminService.listCompanies).toHaveBeenCalledWith({ page: 1,…

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[35/45]⎯

 FAIL  src/tests/api/payments.api.test.ts > payments API contract > accepts valid AmanPay webhooks and delegates the exact payload
AssertionError: expected "spy" to be called with arguments: [ { transaction_id: 'txn_1', …(1) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "status": "PAID",
      "transaction_id": "txn_1",
    },
+   "{\"transaction_id\":\"txn_1\",\"status\":\"PAID\"}",
  ]


Number of calls: 1

 ❯ src/tests/api/payments.api.test.ts:68:42
     66|     expect(res.status).toBe(200)
     67|     expect(res.body).toEqual({ received: true })
     68|     expect(service.handleAmanpayWebhook).toHaveBeenCalledWith(payload)
       |                                          ^
     69|   })
     70| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[36/45]⎯

 FAIL  src/tests/api/payments.api.test.ts > payments API contract > accepts verified PayPal webhooks and delegates handling
AssertionError: expected "spy" to be called with arguments: [ { …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "event_type": "PAYMENT.CAPTURE.COMPLETED",
      "resource": Object {
        "id": "capture_1",
      },
    },
+   "{\"event_type\":\"PAYMENT.CAPTURE.COMPLETED\",\"resource\":{\"id\":\"capture_1\"}}",
  ]


Number of calls: 1

 ❯ src/tests/api/payments.api.test.ts:96:41
     94|     expect(res.status).toBe(200)
     95|     expect(res.body).toEqual({ received: true })
     96|     expect(service.handlePaypalWebhook).toHaveBeenCalledWith(payload)
       |                                         ^
     97|   })
     98| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[37/45]⎯

 FAIL  src/tests/api/public-validation.api.test.ts > public validation API contracts > defaults site payment currency to MAD for valid public payment requests
AssertionError: expected 400 to be 200 // Object.is equality

- Expected
+ Received

- 200
+ 400

 ❯ src/tests/api/public-validation.api.test.ts:111:24
    109|     })
    110| 
    111|     expect(res.status).toBe(200)
       |                        ^
    112|     expect(siteService.initPayment).toHaveBeenCalledWith('atlas-cars',…
    113|       provider: 'PAYPAL',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[38/45]⎯

 FAIL  src/tests/api/subscriptions.api.test.ts > subscriptions public API > accepts verified PayPal webhooks and delegates handling to the subscription service
AssertionError: expected "spy" to be called with arguments: [ { …(2) } ]

Received: 

  1st spy call:

  Array [
    Object {
      "event_type": "PAYMENT.CAPTURE.COMPLETED",
      "resource": Object {
        "id": "capture_1",
      },
    },
+   "{\"event_type\":\"PAYMENT.CAPTURE.COMPLETED\",\"resource\":{\"id\":\"capture_1\"}}",
  ]


Number of calls: 1

 ❯ src/tests/api/subscriptions.api.test.ts:103:41
    101|     expect(res.status).toBe(200)
    102|     expect(res.body).toEqual({ received: true })
    103|     expect(service.handlePaypalWebhook).toHaveBeenCalledWith(payload)
       |                                         ^
    104|   })
    105| })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[39/45]⎯

 FAIL  src/tests/e2e/admin-billing-boundaries.e2e.test.ts > admin billing e2e boundaries > rejects anonymous billing access and malformed invoice creation without touching services
AssertionError: expected 401 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 401

 ❯ src/tests/e2e/admin-billing-boundaries.e2e.test.ts:37:30
     35|       .send({ invoiceType: 'MADE_UP', lineItems: [{ quantity: 0, unitA…
     36| 
     37|     expect(malformed.status).toBe(400)
       |                              ^
     38|     expect(adminService.createBillingInvoice).not.toHaveBeenCalled()
     39|   })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[40/45]⎯

 FAIL  src/tests/e2e/vehicle-pricing-boundaries.e2e.test.ts > vehicle pricing e2e boundaries > rejects anonymous and malformed pricing requests without invoking pricing services
AssertionError: expected 401 to be 400 // Object.is equality

- Expected
+ Received

- 400
+ 401

 ❯ src/tests/e2e/vehicle-pricing-boundaries.e2e.test.ts:53:36
     51|       .send({ pricingMode: 'AUTOMATIC', baseDailyRate: -50 })
     52| 
     53|     expect(malformedConfig.status).toBe(400)
       |                                    ^
     54|     expect(vehicleService.updateVehiclePricing).not.toHaveBeenCalled()
     55| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[41/45]⎯

 Test Files  21 failed | 127 passed (148)
      Tests  39 failed | 601 passed (640)
   Start at  23:32:27
   Duration  6.99s (transform 2.58s, setup 8ms, collect 30.38s, tests 3.22s, environment 16ms, prepare 10.35s)

npm error Lifecycle script `test` failed with error:
npm error code 1
npm error path /Volumes/ExternalApps/Documents/car_management_system/apps/api
npm error workspace @rentaldrivego/api@1.0.0
npm error location /Volumes/ExternalApps/Documents/car_management_system/apps/api
npm error command failed
npm error command sh -c vitest run
