chore: wire Carplace into dev and production stacks
Build & Deploy / Build & Push Docker Image (push) Successful in 2m55s
Test / Type Check (all packages) (push) Successful in 54s
Build & Deploy / Deploy to VPS (push) Successful in 4s
Test / API Unit Tests (push) Failing after 48s
Test / Homepage Unit Tests (push) Successful in 43s
Test / Storefront Unit Tests (push) Failing after 40s
Test / Admin Unit Tests (push) Successful in 40s
Test / Dashboard Unit Tests (push) Failing after 42s
Test / API Integration Tests (push) Successful in 1m0s

This commit is contained in:
root
2026-07-02 18:15:42 -04:00
parent ad5f5ebab7
commit 7ff2dbb139
214 changed files with 5258 additions and 5906 deletions
@@ -40,12 +40,12 @@ vi.mock('../../modules/notifications/notification.service', () => ({
getRenterPreferences: vi.fn(),
setRenterPreferences: vi.fn(),
}))
vi.mock('../../modules/storefront/storefront.service', () => ({
vi.mock('../../modules/carplace/carplace.service', () => ({
getCities: vi.fn(),
getListedCompanies: vi.fn(),
searchVehicles: vi.fn(),
getVehicleDetail: vi.fn(),
createStorefrontReservation: vi.fn(),
createCarplaceReservation: vi.fn(),
getCompanyPage: vi.fn(),
getCompanyReviews: vi.fn(),
getCompanyVehicles: vi.fn(),
@@ -61,11 +61,11 @@ import request from 'supertest'
import { createApp } from '../../app'
import * as employeeService from '../../modules/auth/auth.employee.service'
import * as notificationService from '../../modules/notifications/notification.service'
import * as storefrontService from '../../modules/storefront/storefront.service'
import * as carplaceService from '../../modules/carplace/carplace.service'
const app = createApp()
describe('employee, notification, and storefront API validation contracts', () => {
describe('employee, notification, and carplace API validation contracts', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.mocked(employeeService.login).mockResolvedValue({ token: 'jwt', employee: { id: 'employee_1' } } as never)
@@ -73,8 +73,8 @@ describe('employee, notification, and storefront API validation contracts', () =
vi.mocked(employeeService.updateLanguage).mockResolvedValue({ language: 'ar' } as never)
vi.mocked(employeeService.resetPassword).mockResolvedValue({ message: 'Password updated successfully. You can now sign in.' } as never)
vi.mocked(notificationService.setPreferences).mockResolvedValue({ success: true } as never)
vi.mocked(storefrontService.searchVehicles).mockResolvedValue({ companies: [], vehicles: [], pagination: { page: 1, pageSize: 20, total: 0 } } as never)
vi.mocked(storefrontService.submitReview).mockResolvedValue({ id: 'review_1' } as never)
vi.mocked(carplaceService.searchVehicles).mockResolvedValue({ companies: [], vehicles: [], pagination: { page: 1, pageSize: 20, total: 0 } } as never)
vi.mocked(carplaceService.submitReview).mockResolvedValue({ id: 'review_1' } as never)
})
it('normalizes employee login email before service execution', async () => {
@@ -110,11 +110,11 @@ describe('employee, notification, and storefront API validation contracts', () =
expect(notificationService.setPreferences).not.toHaveBeenCalled()
})
it('defaults storefront search pagination at the public route boundary', async () => {
const res = await request(app).get('/api/v1/storefront/search?city=Casablanca')
it('defaults carplace search pagination at the public route boundary', async () => {
const res = await request(app).get('/api/v1/carplace/search?city=Casablanca')
expect(res.status).toBe(200)
expect(storefrontService.searchVehicles).toHaveBeenCalledWith(expect.objectContaining({
expect(carplaceService.searchVehicles).toHaveBeenCalledWith(expect.objectContaining({
city: 'Casablanca',
page: 1,
pageSize: 20,
@@ -122,7 +122,7 @@ describe('employee, notification, and storefront API validation contracts', () =
})
it('rejects out-of-range public review ratings before service execution', async () => {
const res = await request(app).post('/api/v1/storefront/review/token_123').send({
const res = await request(app).post('/api/v1/carplace/review/token_123').send({
overallRating: 6,
vehicleRating: 5,
serviceRating: 5,
@@ -130,6 +130,6 @@ describe('employee, notification, and storefront API validation contracts', () =
})
expect(res.status).toBe(400)
expect(storefrontService.submitReview).not.toHaveBeenCalled()
expect(carplaceService.submitReview).not.toHaveBeenCalled()
})
})
@@ -30,12 +30,12 @@ vi.mock('../../modules/site/site.service', () => ({
handleContact: vi.fn(),
}))
vi.mock('../../modules/storefront/storefront.service', () => ({
vi.mock('../../modules/carplace/carplace.service', () => ({
getPublicOffers: vi.fn(),
getCities: vi.fn(),
getListedCompanies: vi.fn(),
searchVehicles: vi.fn(),
createStorefrontReservation: vi.fn(),
createCarplaceReservation: vi.fn(),
getReviewContext: vi.fn(),
submitReview: vi.fn(),
validateOfferCode: vi.fn(),
@@ -49,7 +49,7 @@ vi.mock('../../modules/storefront/storefront.service', () => ({
import request from 'supertest'
import { createApp } from '../../app'
import * as siteService from '../../modules/site/site.service'
import * as storefrontService from '../../modules/storefront/storefront.service'
import * as carplaceService from '../../modules/carplace/carplace.service'
const app = createApp()
@@ -59,9 +59,9 @@ describe('public validation API contracts', () => {
vi.mocked(siteService.checkAvailability).mockResolvedValue({ available: true, nextAvailableAt: null } as never)
vi.mocked(siteService.initPayment).mockResolvedValue({ checkoutUrl: 'https://pay.example.test' } as never)
vi.mocked(siteService.handleContact).mockResolvedValue({ success: true } as never)
vi.mocked(storefrontService.searchVehicles).mockResolvedValue({ data: [], pagination: { page: 1, pageSize: 20 } } as never)
vi.mocked(storefrontService.createStorefrontReservation).mockResolvedValue({ id: 'reservation_1' } as never)
vi.mocked(storefrontService.submitReview).mockResolvedValue({ id: 'review_1' } as never)
vi.mocked(carplaceService.searchVehicles).mockResolvedValue({ data: [], pagination: { page: 1, pageSize: 20 } } as never)
vi.mocked(carplaceService.createCarplaceReservation).mockResolvedValue({ id: 'reservation_1' } as never)
vi.mocked(carplaceService.submitReview).mockResolvedValue({ id: 'review_1' } as never)
})
it('rejects malformed public availability checks before site service execution', async () => {
@@ -120,11 +120,11 @@ describe('public validation API contracts', () => {
})
})
it('coerces storefront search pagination and price filters', async () => {
const res = await request(app).get('/api/v1/storefront/search?city=Rabat&maxPrice=500&page=2&pageSize=30')
it('coerces carplace search pagination and price filters', async () => {
const res = await request(app).get('/api/v1/carplace/search?city=Rabat&maxPrice=500&page=2&pageSize=30')
expect(res.status).toBe(200)
expect(storefrontService.searchVehicles).toHaveBeenCalledWith({
expect(carplaceService.searchVehicles).toHaveBeenCalledWith({
city: 'Rabat',
maxPrice: 500,
page: 2,
@@ -132,15 +132,15 @@ describe('public validation API contracts', () => {
})
})
it('rejects oversized storefront pagination before search execution', async () => {
const res = await request(app).get('/api/v1/storefront/search?pageSize=500')
it('rejects oversized carplace pagination before search execution', async () => {
const res = await request(app).get('/api/v1/carplace/search?pageSize=500')
expect(res.status).toBe(400)
expect(storefrontService.searchVehicles).not.toHaveBeenCalled()
expect(carplaceService.searchVehicles).not.toHaveBeenCalled()
})
it('rejects storefront reservations with invalid public contact data before service execution', async () => {
const res = await request(app).post('/api/v1/storefront/reservations').send({
it('rejects carplace reservations with invalid public contact data before service execution', async () => {
const res = await request(app).post('/api/v1/carplace/reservations').send({
vehicleId: 'ckvvehicle000000000000001',
companySlug: 'atlas-cars',
firstName: 'Aya',
@@ -151,13 +151,13 @@ describe('public validation API contracts', () => {
})
expect(res.status).toBe(400)
expect(storefrontService.createStorefrontReservation).not.toHaveBeenCalled()
expect(carplaceService.createCarplaceReservation).not.toHaveBeenCalled()
})
it('rejects invalid public review ratings before creating reviews', async () => {
const res = await request(app).post('/api/v1/storefront/review/token_1').send({ overallRating: 6 })
const res = await request(app).post('/api/v1/carplace/review/token_1').send({ overallRating: 6 })
expect(res.status).toBe(400)
expect(storefrontService.submitReview).not.toHaveBeenCalled()
expect(carplaceService.submitReview).not.toHaveBeenCalled()
})
})
@@ -10,7 +10,7 @@ import { createApp } from '../../app'
const app = createApp()
describe('employee and storefront public boundary smoke', () => {
describe('employee and carplace public boundary smoke', () => {
it('rejects malformed employee login payloads without leaking internals', async () => {
const res = await request(app).post('/api/v1/auth/employee/login').send({ email: 'not-an-email', password: 'x' })
@@ -19,7 +19,7 @@ describe('employee and storefront public boundary smoke', () => {
})
it('rejects invalid public review payloads without executing private infrastructure', async () => {
const res = await request(app).post('/api/v1/storefront/review/token_123').send({ overallRating: 0 })
const res = await request(app).post('/api/v1/carplace/review/token_123').send({ overallRating: 0 })
expect(res.status).toBe(400)
expect(JSON.stringify(res.body)).not.toContain('Prisma')
@@ -24,12 +24,12 @@ vi.mock('../../modules/site/site.service', () => ({
capturePaypal: vi.fn(),
handleContact: vi.fn(),
}))
vi.mock('../../modules/storefront/storefront.service', () => ({
vi.mock('../../modules/carplace/carplace.service', () => ({
getPublicOffers: vi.fn(),
getCities: vi.fn(),
getListedCompanies: vi.fn(),
searchVehicles: vi.fn(),
createStorefrontReservation: vi.fn(),
createCarplaceReservation: vi.fn(),
getReviewContext: vi.fn(),
submitReview: vi.fn(),
validateOfferCode: vi.fn(),
@@ -43,7 +43,7 @@ vi.mock('../../modules/storefront/storefront.service', () => ({
import request from 'supertest'
import { createApp } from '../../app'
import * as siteService from '../../modules/site/site.service'
import * as storefrontService from '../../modules/storefront/storefront.service'
import * as carplaceService from '../../modules/carplace/carplace.service'
const app = createApp()
@@ -61,8 +61,8 @@ describe('public validation e2e smoke', () => {
expect(payment.status).toBe(400)
expect(siteService.initPayment).not.toHaveBeenCalled()
const review = await request(app).post('/api/v1/storefront/review/token_1').send({ overallRating: 0 })
const review = await request(app).post('/api/v1/carplace/review/token_1').send({ overallRating: 0 })
expect(review.status).toBe(400)
expect(storefrontService.submitReview).not.toHaveBeenCalled()
expect(carplaceService.submitReview).not.toHaveBeenCalled()
})
})
@@ -1,10 +1,10 @@
import { describe, expect, it } from 'vitest'
describe('billing, storefront, and vehicle integration boundaries', () => {
describe('billing, carplace, and vehicle integration boundaries', () => {
it('documents the Batch-10 DB-backed regression targets for the real integration environment', () => {
expect([
'admin billing invoice lifecycle uses persisted line items and audit logs',
'storefront company pages enrich vehicles with real availability records',
'carplace company pages enrich vehicles with real availability records',
'vehicle location settings persist through create/update/list flows',
]).toHaveLength(3)
})
@@ -1,14 +1,14 @@
import { describe, expect, it } from 'vitest'
describe('employee, storefront, and notification integration boundaries', () => {
describe('employee, carplace, and notification integration boundaries', () => {
it('documents the Batch-17 DB-backed integration boundary', () => {
expect({
employeeAuth: 'password reset/login flows require generated Prisma and mail-provider test doubles',
storefront: 'public booking/review flows require seeded company, vehicle, reservation, and token records',
carplace: 'public booking/review flows require seeded company, vehicle, reservation, and token records',
notifications: 'preference persistence requires notificationPreference composite indexes',
}).toEqual(expect.objectContaining({
employeeAuth: expect.stringContaining('Prisma'),
storefront: expect.stringContaining('seeded'),
carplace: expect.stringContaining('seeded'),
notifications: expect.stringContaining('composite'),
}))
})
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import { parseBody, parseQuery } from '../../http/validate'
import { storefrontReservationSchema, paginationSchema } from '../../modules/storefront/storefront.schemas'
import { carplaceReservationSchema, paginationSchema } from '../../modules/carplace/carplace.schemas'
import { paySchema } from '../../modules/site/site.schemas'
function reqWith(body: unknown, query: unknown = {}) {
@@ -8,7 +8,7 @@ function reqWith(body: unknown, query: unknown = {}) {
}
describe('public validation boundaries', () => {
it('keeps storefront pagination coercion consistent with route parsing', () => {
it('keeps carplace pagination coercion consistent with route parsing', () => {
expect(parseQuery(paginationSchema, reqWith({}, { page: '4', pageSize: '25' }))).toEqual({
page: 4,
pageSize: 25,
@@ -24,8 +24,8 @@ describe('public validation boundaries', () => {
}))).toThrow('Invalid enum value')
})
it('requires enough anonymous storefront reservation identity to create a booking request', () => {
const parsed = parseBody(storefrontReservationSchema, reqWith({
it('requires enough anonymous carplace reservation identity to create a booking request', () => {
const parsed = parseBody(carplaceReservationSchema, reqWith({
vehicleId: 'ckvvehicle000000000000001',
companySlug: 'atlas-cars',
firstName: 'Aya',