test: add unit and integration test suites
- Extract evaluateCondition + rule types into src/lib/rules.ts for testability - 48 unit tests for evaluateCondition (all fields/operators) and formatCategory - 21 integration tests for getTransactions filters and getParticipantBalances - Vitest configs for unit (vitest.config.ts) and integration (vitest.integration.config.ts) - setup-test-db.sh creates personal_test DB from production schema via pg_dump - Use vi.doMock + dynamic import pattern to isolate test DB from Prisma singleton
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { describe, it, expect, beforeEach, afterAll } from "vitest";
|
||||
import { createPool, resetDB } from "./helpers";
|
||||
|
||||
const pool = createPool();
|
||||
|
||||
beforeEach(async () => {
|
||||
await resetDB(pool);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await pool.end();
|
||||
});
|
||||
|
||||
// This tests the name-substitution logic applied in /api/participants GET.
|
||||
// The rule: the participant matching the current user's ID gets name "Me";
|
||||
// everyone else keeps their real name.
|
||||
function substituteMe(
|
||||
participants: { id: number; name: string }[],
|
||||
currentUserId: number
|
||||
) {
|
||||
return participants.map((p) =>
|
||||
p.id === currentUserId ? { ...p, name: "Me" } : p
|
||||
);
|
||||
}
|
||||
|
||||
describe("participant Me substitution", () => {
|
||||
it("replaces the current user's name with Me", async () => {
|
||||
const r = await pool.query(
|
||||
`INSERT INTO participants (name) VALUES ('Siddharth') RETURNING id`
|
||||
);
|
||||
const userId = r.rows[0].id;
|
||||
const participants = [
|
||||
{ id: userId, name: "Siddharth" },
|
||||
{ id: userId + 1, name: "Sonu" },
|
||||
];
|
||||
|
||||
const result = substituteMe(participants, userId);
|
||||
expect(result.find((p) => p.id === userId)?.name).toBe("Me");
|
||||
expect(result.find((p) => p.id === userId + 1)?.name).toBe("Sonu");
|
||||
});
|
||||
|
||||
it("leaves all names unchanged when currentUserId does not match", () => {
|
||||
const participants = [
|
||||
{ id: 1, name: "Siddharth" },
|
||||
{ id: 2, name: "Sonu" },
|
||||
];
|
||||
const result = substituteMe(participants, 999);
|
||||
expect(result).toEqual(participants);
|
||||
});
|
||||
|
||||
it("Sonu sees Me for herself and Siddharth for the primary user", async () => {
|
||||
const r1 = await pool.query(
|
||||
`INSERT INTO participants (name) VALUES ('Siddharth') RETURNING id`
|
||||
);
|
||||
const r2 = await pool.query(
|
||||
`INSERT INTO participants (name, email) VALUES ('Sonu', 'sonu@example.com') RETURNING id`
|
||||
);
|
||||
const siddharthId = r1.rows[0].id;
|
||||
const sonuId = r2.rows[0].id;
|
||||
|
||||
const rawParticipants = [
|
||||
{ id: siddharthId, name: "Siddharth" },
|
||||
{ id: sonuId, name: "Sonu" },
|
||||
];
|
||||
|
||||
// Siddharth's view
|
||||
const siddharthView = substituteMe(rawParticipants, siddharthId);
|
||||
expect(siddharthView.find((p) => p.id === siddharthId)?.name).toBe("Me");
|
||||
expect(siddharthView.find((p) => p.id === sonuId)?.name).toBe("Sonu");
|
||||
|
||||
// Sonu's view
|
||||
const sonuView = substituteMe(rawParticipants, sonuId);
|
||||
expect(sonuView.find((p) => p.id === siddharthId)?.name).toBe("Siddharth");
|
||||
expect(sonuView.find((p) => p.id === sonuId)?.name).toBe("Me");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user