diff --git a/shared/modules/economy/economy.integration.test.ts b/shared/modules/economy/economy.integration.test.ts index 28c6572..4baac92 100644 --- a/shared/modules/economy/economy.integration.test.ts +++ b/shared/modules/economy/economy.integration.test.ts @@ -8,6 +8,10 @@ import { economyService } from "./economy.service"; const SENDER_ID = "999000000000000001"; const RECEIVER_ID = "999000000000000002"; +// This test requires a real database connection. +// It is excluded from `bun test` by default (*.integration.test.ts pattern) +// and only runs in CI with `--integration` flag, which provides PostgreSQL. + async function cleanupTestUsers() { // transactions.userId has onDelete: 'cascade', so deleting users removes their transactions await DrizzleClient.delete(users).where(eq(users.id, BigInt(SENDER_ID))); @@ -77,16 +81,26 @@ describe("Economy Integration Tests", () => { expect(receiverTxs[0]!.type).toBe("TRANSFER_IN"); }); - it("should reject a transfer when sender has insufficient funds", async () => { + it("should reject transfer with insufficient funds and leave balances unchanged", async () => { await expect( economyService.transfer(SENDER_ID, RECEIVER_ID, 2000n) ).rejects.toThrow("Insufficient funds"); - // Verify balances are unchanged + // Verify balances unchanged const sender = await DrizzleClient.query.users.findFirst({ where: eq(users.id, BigInt(SENDER_ID)), }); + const receiver = await DrizzleClient.query.users.findFirst({ + where: eq(users.id, BigInt(RECEIVER_ID)), + }); expect(sender!.balance).toBe(1000n); + expect(receiver!.balance).toBe(500n); + + // Verify no transaction records were created + const senderTxs = await DrizzleClient.query.transactions.findMany({ + where: eq(transactions.userId, BigInt(SENDER_ID)), + }); + expect(senderTxs.length).toBe(0); }); it("should reject a self-transfer", async () => { @@ -122,30 +136,5 @@ describe("Economy Integration Tests", () => { // Receiver: 500 + 100 + 200 - 50 = 750 expect(receiver!.balance).toBe(750n); }); - - it("should roll back the entire transfer if an error occurs mid-transaction", async () => { - // Attempting to transfer more than balance ensures the transaction aborts - // after the sender check but before any SQL update is committed - const senderBefore = await DrizzleClient.query.users.findFirst({ - where: eq(users.id, BigInt(SENDER_ID)), - }); - - await expect( - economyService.transfer(SENDER_ID, RECEIVER_ID, 9999n) - ).rejects.toThrow("Insufficient funds"); - - const senderAfter = await DrizzleClient.query.users.findFirst({ - where: eq(users.id, BigInt(SENDER_ID)), - }); - - // Balance must be unchanged — no partial debit - expect(senderAfter!.balance).toBe(senderBefore!.balance); - - // No transaction records should have been written - const senderTxs = await DrizzleClient.query.transactions.findMany({ - where: eq(transactions.userId, BigInt(SENDER_ID)), - }); - expect(senderTxs.length).toBe(0); - }); }); });