import { test } from "node:test"; import assert from "node:assert/strict"; import path from "node:path"; import { fileURLToPath } from "node:url"; import dotenv from "dotenv"; import getPool from "../lib/server/db"; import { acceptInviteLink, createInviteLink } from "../lib/server/group-invites"; import { cleanupTestData, uniqueInviteCode } from "./test-helpers"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const envLoaded = dotenv.config({ path: path.resolve(__dirname, "../../../.env") }); const hasDb = Boolean(process.env.DATABASE_URL); test("invite link auto-accept adds member", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); let ownerId: number | null = null; let memberId: number | null = null; let groupId: number | null = null; try { const ownerRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`invite_owner_${Date.now()}@example.com`, "hash"] ); ownerId = Number(ownerRes.rows[0].id); const memberRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`invite_member_${Date.now()}@example.com`, "hash"] ); memberId = Number(memberRes.rows[0].id); const groupRes = await client.query( "insert into groups(name, invite_code, created_by) values($1,$2,$3) returning id", ["Invite Group", uniqueInviteCode("I"), ownerId] ); groupId = Number(groupRes.rows[0].id); await client.query( "insert into group_members(group_id, user_id, role) values($1,$2,'GROUP_OWNER')", [groupId, ownerId] ); const link = await createInviteLink({ userId: ownerId, groupId, policy: "AUTO_ACCEPT", singleUse: false, expiresAt: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000), requestId: "test-request" }); const result = await acceptInviteLink({ userId: memberId!, token: link.token, requestId: "test-accept" }); assert.equal(result.status, "JOINED"); const { rowCount } = await client.query( "select 1 from group_members where group_id=$1 and user_id=$2", [groupId, memberId] ); assert.equal(rowCount, 1); } finally { await cleanupTestData(client, { userIds: [ownerId, memberId], groupId }); client.release(); } }); test("invite link rejects expired link", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); let ownerId: number | null = null; let memberId: number | null = null; let groupId: number | null = null; try { const ownerRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`invite_owner_${Date.now()}@example.com`, "hash"] ); ownerId = Number(ownerRes.rows[0].id); const memberRes = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [`invite_member_${Date.now()}@example.com`, "hash"] ); memberId = Number(memberRes.rows[0].id); const groupRes = await client.query( "insert into groups(name, invite_code, created_by) values($1,$2,$3) returning id", ["Invite Group", uniqueInviteCode("E"), ownerId] ); groupId = Number(groupRes.rows[0].id); await client.query( "insert into group_members(group_id, user_id, role) values($1,$2,'GROUP_OWNER')", [groupId, ownerId] ); const link = await createInviteLink({ userId: ownerId, groupId, policy: "AUTO_ACCEPT", singleUse: false, expiresAt: new Date(Date.now() - 60 * 1000), requestId: "test-request" }); await assert.rejects( () => acceptInviteLink({ userId: memberId!, token: link.token, requestId: "test-accept" }), { message: "INVITE_EXPIRED" } ); } finally { await cleanupTestData(client, { userIds: [ownerId, memberId], groupId }); client.release(); } });