import { describe, it, expect } from 'vitest'; import { transferOwnership } from '@/lib/services/yachts.service'; import { makeClient, makePort, makeYacht, makeAuditMeta } from '../helpers/factories'; import { db } from '@/lib/db'; import { yachtOwnershipHistory, yachts } from '@/lib/db/schema'; import { eq } from 'drizzle-orm'; describe('transferOwnership', () => { it('closes prior history row and opens a new one atomically', async () => { const port = await makePort(); const clientA = await makeClient({ portId: port.id }); const clientB = await makeClient({ portId: port.id }); const yacht = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientA.id }); await transferOwnership( yacht.id, port.id, { newOwner: { type: 'client', id: clientB.id }, effectiveDate: new Date(), transferReason: 'sale', }, makeAuditMeta(), ); const history = await db .select() .from(yachtOwnershipHistory) .where(eq(yachtOwnershipHistory.yachtId, yacht.id)); expect(history).toHaveLength(2); const [prior, current] = history.sort((a, b) => a.startDate.getTime() - b.startDate.getTime()); expect(prior!.endDate).not.toBeNull(); expect(current!.endDate).toBeNull(); expect(current!.ownerId).toBe(clientB.id); const updatedYacht = await db.query.yachts.findFirst({ where: eq(yachts.id, yacht.id) }); expect(updatedYacht!.currentOwnerId).toBe(clientB.id); }); it('rejects when newOwner = currentOwner (no-op)', async () => { const port = await makePort(); const client = await makeClient({ portId: port.id }); const yacht = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: client.id }); await expect( transferOwnership( yacht.id, port.id, { newOwner: { type: 'client', id: client.id }, effectiveDate: new Date() }, makeAuditMeta(), ), ).rejects.toThrow(/same owner/i); }); it('partial unique index prevents concurrent double-open ownership rows', async () => { // Prior to the atomic close-then-open, a naive impl would insert a new open row // without closing the old one. Verify this would be blocked at the DB level. const port = await makePort(); const clientA = await makeClient({ portId: port.id }); const clientB = await makeClient({ portId: port.id }); const yacht = await makeYacht({ portId: port.id, ownerType: 'client', ownerId: clientA.id }); await expect( db.insert(yachtOwnershipHistory).values({ yachtId: yacht.id, ownerType: 'client', ownerId: clientB.id, startDate: new Date(), endDate: null, createdBy: 'test', }), ).rejects.toThrow(/duplicate key/i); }); });