fiddy/apps/web/__tests__/group-ownership.test.ts
2026-02-11 23:45:15 -08:00

150 lines
5.6 KiB
TypeScript

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 { joinGroup, requireActiveGroup } from "../lib/server/groups";
import { setGroupSettings } from "../lib/server/group-settings";
import { transferOwnership } from "../lib/server/group-members";
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("join policy enforcement and join requests", 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;
const inviteCode = uniqueInviteCode("J");
try {
const ownerRes = await client.query(
"insert into users(email, password_hash) values($1,$2) returning id",
[`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",
[`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",
["Join Policy Group", inviteCode, 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]
);
await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "NOT_ACCEPTING" });
await assert.rejects(
() => joinGroup(memberId!, inviteCode),
{ message: "JOIN_NOT_ACCEPTING" }
);
await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "APPROVAL_REQUIRED" });
await assert.rejects(
() => joinGroup(memberId!, inviteCode),
{ message: "JOIN_PENDING" }
);
const pendingRes = await client.query(
"select status from group_join_requests where group_id=$1 and user_id=$2",
[groupId, memberId]
);
assert.equal(pendingRes.rows[0]?.status, "PENDING");
await client.query("delete from group_join_requests where group_id=$1 and user_id=$2", [groupId, memberId]);
await setGroupSettings({ userId: ownerId, groupId, allowMemberTagManage: false, joinPolicy: "AUTO_ACCEPT" });
const group = await joinGroup(memberId!, inviteCode);
assert.equal(Number(group.id), groupId);
const memberRows = await client.query(
"select role from group_members where group_id=$1 and user_id=$2",
[groupId, memberId]
);
assert.equal(memberRows.rows[0]?.role, "MEMBER");
} finally {
await cleanupTestData(client, { userIds: [ownerId, memberId], groupId });
client.release();
}
});
test("ownership transfer updates roles", 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",
[`owner2_${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",
[`member2_${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",
["Ownership Group", uniqueInviteCode("O"), 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]
);
await client.query(
"insert into group_members(group_id, user_id, role) values($1,$2,'MEMBER')",
[groupId, memberId]
);
await transferOwnership({
actorUserId: ownerId,
groupId,
newOwnerUserId: memberId,
requestId: `req_${Date.now()}`
});
const roles = await client.query(
"select user_id, role from group_members where group_id=$1",
[groupId]
);
const roleMap = new Map(roles.rows.map(row => [Number(row.user_id), row.role]));
assert.equal(roleMap.get(ownerId), "GROUP_ADMIN");
assert.equal(roleMap.get(memberId), "GROUP_OWNER");
} finally {
await cleanupTestData(client, { userIds: [ownerId, memberId], groupId });
client.release();
}
});