Skip to content

Commit f861893

Browse files
committed
ENG-1723-list-group-members-backend
1 parent 154c7cd commit f861893

4 files changed

Lines changed: 411 additions & 1 deletion

File tree

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import assert from "assert";
2+
import { describe, it, beforeAll, afterAll } from "vitest";
3+
import { createClient } from "@supabase/supabase-js";
4+
import type { Database } from "@repo/database/dbTypes";
5+
import type { DGSupabaseClient } from "@repo/database/lib/client";
6+
import {
7+
fetchOrCreateSpaceDirect,
8+
spaceAnonUserEmail,
9+
} from "@repo/database/lib/contextFunctions";
10+
import { createGroup } from "../../app/utils/supabase/account";
11+
12+
const SUPABASE_URL = process.env.SUPABASE_URL!;
13+
const ANON_KEY = process.env.SUPABASE_PUBLISHABLE_KEY!;
14+
const SERVICE_KEY = process.env.SUPABASE_SECRET_KEY!;
15+
const PASSWORD = "abcdefgh";
16+
17+
const freshClient = (): DGSupabaseClient =>
18+
createClient<Database, "public">(SUPABASE_URL, ANON_KEY);
19+
20+
const serviceClient = () =>
21+
createClient<Database, "public">(SUPABASE_URL, SERVICE_KEY);
22+
23+
const signedInClient = async (spaceId: number): Promise<DGSupabaseClient> => {
24+
const client = freshClient();
25+
const { error } = await client.auth.signInWithPassword({
26+
email: spaceAnonUserEmail("Roam", spaceId),
27+
password: PASSWORD,
28+
});
29+
if (error) throw new Error(`Sign-in failed: ${error.message}`);
30+
return client;
31+
};
32+
33+
describe("list group members flow", { tags: ["database"] }, () => {
34+
let spaceId1: number;
35+
let spaceId2: number;
36+
let spaceAccountUuid1: string;
37+
let spaceAccountUuid2: string;
38+
let client1: DGSupabaseClient;
39+
let client2: DGSupabaseClient;
40+
let createdGroupId: string | null = null;
41+
42+
beforeAll(async () => {
43+
const s1 = await fetchOrCreateSpaceDirect({
44+
name: "vitest-s1",
45+
url: "https://roamresearch.com/#/app/vitest-s1",
46+
platform: "Roam",
47+
password: PASSWORD,
48+
});
49+
if (!s1.data)
50+
throw new Error(`Failed to create space 1: ${s1.error?.message}`);
51+
spaceId1 = s1.data.id;
52+
client1 = await signedInClient(spaceId1);
53+
assert(client1);
54+
const accountReq1 = await client1
55+
.from("PlatformAccount")
56+
.select("id,dg_account")
57+
.eq(
58+
"account_local_id",
59+
`roam-${spaceId1}-anon@database.discoursegraphs.com`,
60+
)
61+
.maybeSingle();
62+
assert(!accountReq1.error);
63+
assert(accountReq1.data);
64+
assert(accountReq1.data.dg_account);
65+
spaceAccountUuid1 = accountReq1.data.dg_account;
66+
const s2 = await fetchOrCreateSpaceDirect({
67+
name: "vitest-s2",
68+
url: "https://roamresearch.com/#/app/vitest-s2",
69+
platform: "Roam",
70+
password: PASSWORD,
71+
});
72+
if (!s2.data)
73+
throw new Error(`Failed to create space 2: ${s2.error?.message}`);
74+
spaceId2 = s2.data.id;
75+
client2 = await signedInClient(spaceId2);
76+
assert(client2);
77+
const accountReq2 = await client2
78+
.from("PlatformAccount")
79+
.select("id,dg_account")
80+
.eq(
81+
"account_local_id",
82+
`roam-${spaceId2}-anon@database.discoursegraphs.com`,
83+
)
84+
.maybeSingle();
85+
assert(!accountReq2.error);
86+
assert(accountReq2.data);
87+
assert(accountReq2.data.dg_account);
88+
spaceAccountUuid2 = accountReq2.data.dg_account;
89+
});
90+
91+
afterAll(async () => {
92+
if (createdGroupId)
93+
await serviceClient().auth.admin.deleteUser(createdGroupId);
94+
if (spaceAccountUuid1)
95+
await serviceClient().auth.admin.deleteUser(spaceAccountUuid1);
96+
if (spaceAccountUuid2)
97+
await serviceClient().auth.admin.deleteUser(spaceAccountUuid2);
98+
if (spaceId1)
99+
await serviceClient().from("Space").delete().eq("id", spaceId1);
100+
if (spaceId2)
101+
await serviceClient().from("Space").delete().eq("id", spaceId2);
102+
});
103+
104+
it("lists group members", async () => {
105+
// Step 1: user1 creates a group
106+
const groupId = await createGroup(client1, "vitest-invite-group");
107+
assert(groupId !== null, "createGroup should return a group ID");
108+
createdGroupId = groupId;
109+
110+
// Step 2: Add another member
111+
const { error: errorAddMember } = await client1
112+
.from("group_membership")
113+
.insert({
114+
member_id: spaceAccountUuid2, // eslint-disable-line @typescript-eslint/naming-convention
115+
group_id: groupId, // eslint-disable-line @typescript-eslint/naming-convention
116+
admin: false,
117+
});
118+
assert(!errorAddMember);
119+
120+
// Step 3: Mutual publish setup
121+
const { error: errorPublishSpace1 } = await client1
122+
.from("SpaceAccess")
123+
.insert({
124+
space_id: spaceId1, // eslint-disable-line @typescript-eslint/naming-convention
125+
account_uid: groupId, // eslint-disable-line @typescript-eslint/naming-convention
126+
permissions: "partial",
127+
});
128+
assert(!errorPublishSpace1);
129+
130+
const { error: errorPublishSpace2 } = await client2
131+
.from("SpaceAccess")
132+
.insert({
133+
space_id: spaceId2, // eslint-disable-line @typescript-eslint/naming-convention
134+
account_uid: groupId, // eslint-disable-line @typescript-eslint/naming-convention
135+
permissions: "partial",
136+
});
137+
assert(!errorPublishSpace2);
138+
139+
const expectedSpaceIds = [spaceId1, spaceId2];
140+
// Step 4: user1 lists group members
141+
const { data: data1, error: error1 } = await client1.rpc(
142+
"spaces_in_group",
143+
{
144+
p_group_id: createdGroupId, // eslint-disable-line @typescript-eslint/naming-convention
145+
},
146+
);
147+
assert(error1 === null, error1 ? error1.message : "");
148+
assert(data1 !== null, "group spaces should not be empty");
149+
assert(data1.length === 2, "There should be two spaces");
150+
const spacesSeenBy1 = new Set(
151+
data1.map((gm) => gm.id).filter((id) => id !== null),
152+
);
153+
assert(
154+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
155+
expectedSpaceIds.every((id) => spacesSeenBy1.has(id)),
156+
"Wrong membership information",
157+
);
158+
// Step 5: user2 lists group members
159+
const { data: data2, error: error2 } = await client2.rpc(
160+
"spaces_in_group",
161+
{
162+
p_group_id: createdGroupId, // eslint-disable-line @typescript-eslint/naming-convention
163+
},
164+
);
165+
assert(error2 === null, error2 ? error2.message : "");
166+
assert(data2 !== null, "group spaces should not be empty");
167+
assert(data2.length === 2, "There should be two spaces");
168+
const spacesSeenBy2 = new Set(
169+
data2.map((gm) => gm.id).filter((id) => id !== null),
170+
);
171+
assert(
172+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
173+
expectedSpaceIds.every((id) => spacesSeenBy2.has(id)),
174+
"Wrong membership information",
175+
);
176+
});
177+
});

0 commit comments

Comments
 (0)