import { describe, it, expect } from 'vitest'; import { createPending, activate, endReservation } from '@/lib/services/berth-reservations.service'; import { makeBerth, makeClient, makePort, makeYacht, makeAuditMeta } from '../helpers/factories'; import { ConflictError } from '@/lib/errors'; describe('reservation exclusivity', () => { it('two concurrent activates on same berth: one succeeds, one throws ConflictError', async () => { const port = await makePort(); const berth = await makeBerth({ portId: port.id }); const clientA = await makeClient({ portId: port.id }); const clientB = await makeClient({ portId: port.id }); const yachtA = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientA.id, }); const yachtB = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientB.id, }); const resA = await createPending( port.id, { berthId: berth.id, clientId: clientA.id, yachtId: yachtA.id, startDate: new Date(), }, makeAuditMeta({ portId: port.id }), ); const resB = await createPending( port.id, { berthId: berth.id, clientId: clientB.id, yachtId: yachtB.id, startDate: new Date(), }, makeAuditMeta({ portId: port.id }), ); const results = await Promise.allSettled([ activate(resA.id, port.id, {}, makeAuditMeta({ portId: port.id })), activate(resB.id, port.id, {}, makeAuditMeta({ portId: port.id })), ]); const successes = results.filter((r) => r.status === 'fulfilled'); const failures = results.filter((r) => r.status === 'rejected'); expect(successes).toHaveLength(1); expect(failures).toHaveLength(1); expect((failures[0] as PromiseRejectedResult).reason).toBeInstanceOf(ConflictError); }); it('activating a second reservation after first is ended succeeds', async () => { const port = await makePort(); const berth = await makeBerth({ portId: port.id }); const clientA = await makeClient({ portId: port.id }); const clientB = await makeClient({ portId: port.id }); const yachtA = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientA.id, }); const yachtB = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientB.id, }); const resA = await createPending( port.id, { berthId: berth.id, clientId: clientA.id, yachtId: yachtA.id, startDate: new Date() }, makeAuditMeta({ portId: port.id }), ); await activate(resA.id, port.id, {}, makeAuditMeta({ portId: port.id })); await endReservation( resA.id, port.id, { endDate: new Date() }, makeAuditMeta({ portId: port.id }), ); const resB = await createPending( port.id, { berthId: berth.id, clientId: clientB.id, yachtId: yachtB.id, startDate: new Date() }, makeAuditMeta({ portId: port.id }), ); await expect( activate(resB.id, port.id, {}, makeAuditMeta({ portId: port.id })), ).resolves.toBeDefined(); }); });