@edifice.io/communities-tests 1.0.0-develop-pedago.20250725171105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/it/scenarios/api-community-oauth.spec.ts +106 -0
- package/it/scenarios/api-community-role-check.spec.ts +868 -0
- package/it/scenarios/api-community.spec.ts +89 -0
- package/it/scenarios/api-invitations-search-sort.spec.ts +858 -0
- package/it/scenarios/api-invitations.spec.ts +582 -0
- package/it/scenarios/api-membership.spec.ts +411 -0
- package/it/scenarios/api-permission-check.spec.ts +424 -0
- package/it/scenarios/api-resources-search-sort.spec.ts +600 -0
- package/it/scenarios/api-resources.spec.ts +183 -0
- package/it/scenarios/utils/_community-api.utils.ts +317 -0
- package/it/scenarios/utils/_community-tests.utils.ts +83 -0
- package/it/scenarios/utils/_invitation-api.utils.ts +453 -0
- package/it/scenarios/utils/_membership-api.utils.ts +184 -0
- package/it/scenarios/utils/_resource-api.utils.ts +292 -0
- package/it/scenarios/utils/_resource-ent.utils.ts +415 -0
- package/it/scenarios/utils/_resource-tests.utils.ts +396 -0
- package/it/scenarios/utils/_role.utils.ts +33 -0
- package/loadtest/index.ts +6 -0
- package/package.json +48 -0
- package/vite.config.ts +23 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import { chai, describe } from "https://jslib.k6.io/k6chaijs/4.3.4.0/index.js";
|
|
3
|
+
import { fail, check } from "k6";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
authenticateWeb,
|
|
7
|
+
getUsersOfSchool,
|
|
8
|
+
createAndSetRole,
|
|
9
|
+
linkRoleToUsers,
|
|
10
|
+
initStructure,
|
|
11
|
+
getRandomUserWithProfile,
|
|
12
|
+
getRolesOfStructure,
|
|
13
|
+
Structure,
|
|
14
|
+
logout,
|
|
15
|
+
UserInfo,
|
|
16
|
+
} from "../../node_modules/edifice-k6-commons/dist/index.js";
|
|
17
|
+
|
|
18
|
+
// Import community API utils
|
|
19
|
+
import {
|
|
20
|
+
createCommunityOrFail,
|
|
21
|
+
deleteCommunity,
|
|
22
|
+
getSecretCode,
|
|
23
|
+
CreateCommunityParams,
|
|
24
|
+
} from "./utils/_community-api.utils.ts";
|
|
25
|
+
|
|
26
|
+
// Import invitation API utils
|
|
27
|
+
import {
|
|
28
|
+
createInvitations,
|
|
29
|
+
listCommunityInvitations,
|
|
30
|
+
listMyInvitations,
|
|
31
|
+
updateInvitationStatus,
|
|
32
|
+
deleteInvitation,
|
|
33
|
+
findInvitationById,
|
|
34
|
+
CreateInvitationParams,
|
|
35
|
+
Invitation,
|
|
36
|
+
InvitationStatus,
|
|
37
|
+
MembershipRole,
|
|
38
|
+
deleteInvitationsBatch,
|
|
39
|
+
joinCommunity,
|
|
40
|
+
updateRequestStatus,
|
|
41
|
+
updateInvitationSeeLater,
|
|
42
|
+
} from "./utils/_invitation-api.utils.ts";
|
|
43
|
+
|
|
44
|
+
// Import membership API utils for verification
|
|
45
|
+
import {
|
|
46
|
+
listCommunityMembers,
|
|
47
|
+
findMembershipByUserId,
|
|
48
|
+
} from "./utils/_membership-api.utils.ts";
|
|
49
|
+
|
|
50
|
+
chai.config.logFailures = true;
|
|
51
|
+
|
|
52
|
+
export const options = {
|
|
53
|
+
setupTimeout: "1h",
|
|
54
|
+
maxRedirects: 0,
|
|
55
|
+
thresholds: {
|
|
56
|
+
checks: ["rate == 1.00"],
|
|
57
|
+
},
|
|
58
|
+
scenarios: {
|
|
59
|
+
invitationsTest: {
|
|
60
|
+
exec: "testInvitationsApi",
|
|
61
|
+
executor: "per-vu-iterations",
|
|
62
|
+
vus: 1,
|
|
63
|
+
maxDuration: "1m",
|
|
64
|
+
gracefulStop: "5s",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const timestamp = new Date().toISOString();
|
|
70
|
+
const schoolName = `IT Community Invitations`;
|
|
71
|
+
|
|
72
|
+
export function setup(): Structure {
|
|
73
|
+
let structure: Structure = {} as Structure;
|
|
74
|
+
describe("[CommunityInvitations] Initialize data", () => {
|
|
75
|
+
authenticateWeb(__ENV.ADMC_LOGIN, __ENV.ADMC_PASSWORD);
|
|
76
|
+
structure = initStructure(schoolName, "tiny");
|
|
77
|
+
const role = createAndSetRole("Communities");
|
|
78
|
+
const groups = getRolesOfStructure(structure.id);
|
|
79
|
+
linkRoleToUsers(
|
|
80
|
+
structure,
|
|
81
|
+
role,
|
|
82
|
+
groups.map((g: any) => g.name),
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
return structure;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function testInvitationsApi(structure: Structure) {
|
|
89
|
+
// Community data
|
|
90
|
+
const communityData: CreateCommunityParams = {
|
|
91
|
+
title: `InvitationTest - Community ${timestamp}`,
|
|
92
|
+
type: "FREE",
|
|
93
|
+
schoolYearStart: 2025,
|
|
94
|
+
schoolYearEnd: 2026,
|
|
95
|
+
discussionEnabled: true,
|
|
96
|
+
welcomeNote: "Test community for invitation API tests",
|
|
97
|
+
invitations: {
|
|
98
|
+
users: [],
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
let communityId: number;
|
|
103
|
+
let invitationId: number;
|
|
104
|
+
let adminUser: UserInfo;
|
|
105
|
+
let memberUser: UserInfo;
|
|
106
|
+
let member2User: UserInfo;
|
|
107
|
+
let member3User: UserInfo;
|
|
108
|
+
|
|
109
|
+
describe("[Community Invitations API Test with Authentication]", () => {
|
|
110
|
+
// Step 1: Admin logs in via Web
|
|
111
|
+
authenticateWeb(__ENV.ADMC_LOGIN, __ENV.ADMC_PASSWORD);
|
|
112
|
+
|
|
113
|
+
// Get users from school
|
|
114
|
+
const users = getUsersOfSchool(structure);
|
|
115
|
+
adminUser = getRandomUserWithProfile(users, "Teacher");
|
|
116
|
+
memberUser = getRandomUserWithProfile(users, "Student", [adminUser]);
|
|
117
|
+
member2User = getRandomUserWithProfile(users, "Student", [
|
|
118
|
+
adminUser,
|
|
119
|
+
memberUser,
|
|
120
|
+
]);
|
|
121
|
+
member3User = getRandomUserWithProfile(users, "Student", [
|
|
122
|
+
adminUser,
|
|
123
|
+
memberUser,
|
|
124
|
+
member2User,
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
logout();
|
|
128
|
+
|
|
129
|
+
// Step 2: Admin authenticates
|
|
130
|
+
const adminAuthenticated = authenticateWeb(adminUser.login, "password");
|
|
131
|
+
if (!adminAuthenticated) {
|
|
132
|
+
fail("Admin authentication failed");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Step 3: Admin creates a community
|
|
136
|
+
describe("Create community for invitation tests", () => {
|
|
137
|
+
// Use the utility function to create a community
|
|
138
|
+
communityId = Number(createCommunityOrFail(communityData));
|
|
139
|
+
console.log(`Created community with ID: ${communityId}`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Step 4: Admin invites member to community
|
|
143
|
+
describe("Create invitation for member", () => {
|
|
144
|
+
// Use the invitation API utility to create an invitation
|
|
145
|
+
const invitationData: CreateInvitationParams = {
|
|
146
|
+
users: [{ userId: memberUser.id, role: MembershipRole.MEMBER }],
|
|
147
|
+
message: "You are invited to join our test community",
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const invitations = createInvitations(communityId, invitationData);
|
|
151
|
+
|
|
152
|
+
check(invitations, {
|
|
153
|
+
"invitation created successfully": (r) => r !== null && r.length > 0,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
invitationId = invitations![0].id;
|
|
157
|
+
console.log(`Created invitation with ID: ${invitationId}`);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// 5.1: Get specific invitation from community invitations list
|
|
161
|
+
describe("Find invitation in community invitations list", () => {
|
|
162
|
+
const invitations = listCommunityInvitations(communityId);
|
|
163
|
+
const invitation = findInvitationById(invitationId, invitations);
|
|
164
|
+
|
|
165
|
+
check(invitation, {
|
|
166
|
+
"invitation found in community list": (r) => r !== null,
|
|
167
|
+
"invitation has correct ID": (r) => r !== null && r.id === invitationId,
|
|
168
|
+
"invitation has correct status": (r) =>
|
|
169
|
+
r !== null && r.status === InvitationStatus.PENDING,
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// 5.2: List invitations for a community
|
|
174
|
+
describe("List invitations for community", () => {
|
|
175
|
+
const invitations = listCommunityInvitations(communityId);
|
|
176
|
+
|
|
177
|
+
check(invitations, {
|
|
178
|
+
"list invitations successful": (r) => r !== null,
|
|
179
|
+
"invitations list contains data": (r) => r !== null && r.length > 0,
|
|
180
|
+
"created invitation is in the list": (r) => {
|
|
181
|
+
return (
|
|
182
|
+
r !== null && r.some((inv: Invitation) => inv.id === invitationId)
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Step 6: Member authenticates
|
|
189
|
+
logout();
|
|
190
|
+
const memberAuthenticated = authenticateWeb(memberUser.login, "password");
|
|
191
|
+
if (!memberAuthenticated) {
|
|
192
|
+
fail("Member authentication failed");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Step 7: Member lists their invitations
|
|
196
|
+
describe("Member lists received invitations", () => {
|
|
197
|
+
const myInvitations = listMyInvitations();
|
|
198
|
+
const invitation = findInvitationById(invitationId, myInvitations);
|
|
199
|
+
|
|
200
|
+
check(myInvitations, {
|
|
201
|
+
"member can see invitations": (r) => r !== null,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
check(invitation, {
|
|
205
|
+
"invitation is in the member's list": (r) => r !== null,
|
|
206
|
+
"invitation has correct status": (r) =>
|
|
207
|
+
r !== null && r.status === InvitationStatus.PENDING,
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Step 8: Member accepts invitation
|
|
212
|
+
describe("Member accepts invitation", () => {
|
|
213
|
+
const updatedInvitation = updateInvitationStatus(
|
|
214
|
+
invitationId,
|
|
215
|
+
InvitationStatus.ACCEPTED,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
check(updatedInvitation, {
|
|
219
|
+
"invitation accepted successfully": (r) => r !== null,
|
|
220
|
+
"status changed to ACCEPTED": (r) =>
|
|
221
|
+
r !== null && r.status === InvitationStatus.ACCEPTED,
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Step 9: Admin logs back in to check invitation status
|
|
226
|
+
logout();
|
|
227
|
+
authenticateWeb(adminUser.login, "password");
|
|
228
|
+
|
|
229
|
+
describe("Admin verifies invitation was accepted", () => {
|
|
230
|
+
const invitations = listCommunityInvitations(communityId);
|
|
231
|
+
const invitation = findInvitationById(invitationId, invitations);
|
|
232
|
+
|
|
233
|
+
check(invitation, {
|
|
234
|
+
"invitation found in list": (r) => r !== null,
|
|
235
|
+
"invitation status is ACCEPTED": (r) =>
|
|
236
|
+
r !== null && r.status === InvitationStatus.ACCEPTED,
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Test deletion of an invitation
|
|
241
|
+
describe("Admin tries to delete an invitation", () => {
|
|
242
|
+
// First create a new invitation for deletion test
|
|
243
|
+
const newInvitationData: CreateInvitationParams = {
|
|
244
|
+
users: [{ userId: member2User.id, role: MembershipRole.MEMBER }],
|
|
245
|
+
message: "This invitation will be deleted",
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const newInvitations = createInvitations(communityId, newInvitationData);
|
|
249
|
+
const newInvitationId = newInvitations![0].id;
|
|
250
|
+
|
|
251
|
+
// Now delete the invitation
|
|
252
|
+
const deleted = deleteInvitation(communityId, newInvitationId);
|
|
253
|
+
|
|
254
|
+
check(deleted, {
|
|
255
|
+
"invitation deleted successfully": (r) => r === true,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Verify the invitation is actually deleted by looking for it in the list
|
|
259
|
+
const updatedInvitations = listCommunityInvitations(communityId);
|
|
260
|
+
const deletedInvitation = findInvitationById(
|
|
261
|
+
newInvitationId,
|
|
262
|
+
updatedInvitations,
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
check(deletedInvitation, {
|
|
266
|
+
"invitation no longer exists in list": (r) => r === null,
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Test deletion of a PENDING invitation
|
|
271
|
+
describe("Admin deletes a PENDING invitation", () => {
|
|
272
|
+
// First create a new invitation for deletion test using a different user
|
|
273
|
+
const newInvitationData: CreateInvitationParams = {
|
|
274
|
+
users: [{ userId: member3User.id, role: MembershipRole.MEMBER }],
|
|
275
|
+
message: "This invitation will be deleted",
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const newInvitations = createInvitations(communityId, newInvitationData);
|
|
279
|
+
const newInvitationId = newInvitations![0].id;
|
|
280
|
+
|
|
281
|
+
// Verify the new invitation is indeed in PENDING status before attempting deletion
|
|
282
|
+
const pendingInvitation = findInvitationById(
|
|
283
|
+
newInvitationId,
|
|
284
|
+
listCommunityInvitations(communityId),
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
check(pendingInvitation, {
|
|
288
|
+
"invitation is in PENDING status before deletion": (r) =>
|
|
289
|
+
r !== null && r.status === InvitationStatus.PENDING,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Skip deletion if invitation is not in PENDING status
|
|
293
|
+
if (pendingInvitation?.status !== InvitationStatus.PENDING) {
|
|
294
|
+
console.error(
|
|
295
|
+
`Cannot proceed with deletion: invitation ${newInvitationId} status is ${pendingInvitation?.status}`,
|
|
296
|
+
);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Now delete the invitation
|
|
301
|
+
const deleted = deleteInvitation(communityId, newInvitationId);
|
|
302
|
+
|
|
303
|
+
check(deleted, {
|
|
304
|
+
"invitation deleted successfully": (r) => r === true,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Verify the invitation is actually deleted
|
|
308
|
+
const updatedInvitations = listCommunityInvitations(communityId);
|
|
309
|
+
const deletedInvitation = findInvitationById(
|
|
310
|
+
newInvitationId,
|
|
311
|
+
updatedInvitations,
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
check(deletedInvitation, {
|
|
315
|
+
"invitation no longer exists in list": (r) => r === null,
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Test batch deletion of invitations
|
|
320
|
+
describe("Admin deletes multiple invitations in batch", () => {
|
|
321
|
+
// Create multiple invitations for batch deletion test
|
|
322
|
+
const batchInvitationData: CreateInvitationParams = {
|
|
323
|
+
users: [
|
|
324
|
+
{ userId: member2User.id, role: MembershipRole.MEMBER },
|
|
325
|
+
{ userId: member3User.id, role: MembershipRole.MEMBER },
|
|
326
|
+
],
|
|
327
|
+
message: "These invitations will be deleted in batch",
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
const batchInvitations = createInvitations(
|
|
331
|
+
communityId,
|
|
332
|
+
batchInvitationData,
|
|
333
|
+
);
|
|
334
|
+
const batchInvitationIds = batchInvitations!.map((inv) => inv.id);
|
|
335
|
+
|
|
336
|
+
// Verify all invitations are in PENDING status
|
|
337
|
+
const pendingInvitations = listCommunityInvitations(communityId);
|
|
338
|
+
check(pendingInvitations, {
|
|
339
|
+
"all new invitations are in PENDING status": (r) => {
|
|
340
|
+
if (!r) return false;
|
|
341
|
+
const foundInvitations = batchInvitationIds.map((id) =>
|
|
342
|
+
findInvitationById(id, r),
|
|
343
|
+
);
|
|
344
|
+
return foundInvitations.every(
|
|
345
|
+
(inv) => inv !== null && inv.status === InvitationStatus.PENDING,
|
|
346
|
+
);
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Now delete the invitations in batch
|
|
351
|
+
const batchDeleted = deleteInvitationsBatch(
|
|
352
|
+
communityId,
|
|
353
|
+
batchInvitationIds,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
check(batchDeleted, {
|
|
357
|
+
"batch deletion successful": (r) => r === true,
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Verify all invitations are deleted
|
|
361
|
+
const remainingInvitations = listCommunityInvitations(communityId);
|
|
362
|
+
check(remainingInvitations, {
|
|
363
|
+
"all batch-deleted invitations are gone": (r) => {
|
|
364
|
+
if (!r) return false;
|
|
365
|
+
return batchInvitationIds.every(
|
|
366
|
+
(id) => findInvitationById(id, r) === null,
|
|
367
|
+
);
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// NEW SECTION: Testing the join request workflow with admin approval/rejection
|
|
373
|
+
describe("Secret code join requests and admin approval/rejection", () => {
|
|
374
|
+
// Get the secret code for the community
|
|
375
|
+
const secretCode = getSecretCode(communityId) || "";
|
|
376
|
+
check(secretCode, {
|
|
377
|
+
"Secret code retrieved successfully": (code) =>
|
|
378
|
+
code !== null && code !== "",
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
let acceptedUserId: number | null = null;
|
|
382
|
+
let rejectedUserId: number | null = null;
|
|
383
|
+
let acceptRequestId: number;
|
|
384
|
+
let rejectRequestId: number;
|
|
385
|
+
|
|
386
|
+
// Member 2 creates a join request (to be approved)
|
|
387
|
+
logout();
|
|
388
|
+
authenticateWeb(member2User.login, "password");
|
|
389
|
+
|
|
390
|
+
const joinRequest1 = joinCommunity(secretCode);
|
|
391
|
+
check(joinRequest1, {
|
|
392
|
+
"Member2 join request created successfully": (r) => r !== null,
|
|
393
|
+
"Member2 request has REQUEST status": (r) =>
|
|
394
|
+
r !== null && r.status === InvitationStatus.REQUEST,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
if (joinRequest1 && joinRequest1.receiver) {
|
|
398
|
+
acceptedUserId = Number(joinRequest1.receiver.id);
|
|
399
|
+
acceptRequestId = joinRequest1.id;
|
|
400
|
+
console.log(`Member2 created join request ${acceptRequestId}`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Member 3 creates a join request (to be rejected)
|
|
404
|
+
logout();
|
|
405
|
+
authenticateWeb(member3User.login, "password");
|
|
406
|
+
|
|
407
|
+
const joinRequest2 = joinCommunity(secretCode);
|
|
408
|
+
check(joinRequest2, {
|
|
409
|
+
"Member3 join request created successfully": (r) => r !== null,
|
|
410
|
+
"Member3 request has REQUEST status": (r) =>
|
|
411
|
+
r !== null && r.status === InvitationStatus.REQUEST,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
if (joinRequest2 && joinRequest2.receiver) {
|
|
415
|
+
rejectedUserId = Number(joinRequest2.receiver.id!);
|
|
416
|
+
rejectRequestId = joinRequest2.id!;
|
|
417
|
+
console.log(`Member3 created join request ${rejectRequestId}`);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Admin approves first request and rejects second request
|
|
421
|
+
logout();
|
|
422
|
+
authenticateWeb(adminUser.login, "password");
|
|
423
|
+
|
|
424
|
+
// Admin verifies join requests appear in the community's invitations list
|
|
425
|
+
const pendingRequests = listCommunityInvitations(communityId);
|
|
426
|
+
const foundRequest1 = findInvitationById(
|
|
427
|
+
acceptRequestId!,
|
|
428
|
+
pendingRequests,
|
|
429
|
+
);
|
|
430
|
+
const foundRequest2 = findInvitationById(
|
|
431
|
+
rejectRequestId!,
|
|
432
|
+
pendingRequests,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
check(foundRequest1, {
|
|
436
|
+
"Member2 join request found in invitations list": (r) => r !== null,
|
|
437
|
+
"Member2 join request has REQUEST status": (r) =>
|
|
438
|
+
r !== null && r.status === InvitationStatus.REQUEST,
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
check(foundRequest2, {
|
|
442
|
+
"Member3 join request found in invitations list": (r) => r !== null,
|
|
443
|
+
"Member3 join request has REQUEST status": (r) =>
|
|
444
|
+
r !== null && r.status === InvitationStatus.REQUEST,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Admin approves the first request
|
|
448
|
+
const approvedRequest = updateRequestStatus(
|
|
449
|
+
communityId,
|
|
450
|
+
acceptRequestId!,
|
|
451
|
+
InvitationStatus.REQUEST_ACCEPTED,
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
check(approvedRequest, {
|
|
455
|
+
"Join request approved successfully": (r) => r !== null,
|
|
456
|
+
"Status changed to REQUEST_ACCEPTED": (r) =>
|
|
457
|
+
r !== null && r.status === InvitationStatus.REQUEST_ACCEPTED,
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Admin rejects the second request
|
|
461
|
+
const rejectedRequest = updateRequestStatus(
|
|
462
|
+
communityId,
|
|
463
|
+
rejectRequestId!,
|
|
464
|
+
InvitationStatus.REQUEST_REJECTED,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
check(rejectedRequest, {
|
|
468
|
+
"Join request rejected successfully": (r) => r !== null,
|
|
469
|
+
"Status changed to REQUEST_REJECTED": (r) =>
|
|
470
|
+
r !== null && r.status === InvitationStatus.REQUEST_REJECTED,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Verify that Member2 is now a member
|
|
474
|
+
const memberships = listCommunityMembers(communityId);
|
|
475
|
+
const member2Membership = acceptedUserId
|
|
476
|
+
? findMembershipByUserId(memberships, acceptedUserId)
|
|
477
|
+
: null;
|
|
478
|
+
|
|
479
|
+
check(member2Membership, {
|
|
480
|
+
"Approved user is now a member": (m) => m !== null,
|
|
481
|
+
"Member has correct role": (m) =>
|
|
482
|
+
m !== null && m.role === MembershipRole.MEMBER,
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Verify that Member3 is NOT a member
|
|
486
|
+
const member3Membership = rejectedUserId
|
|
487
|
+
? findMembershipByUserId(memberships, rejectedUserId)
|
|
488
|
+
: null;
|
|
489
|
+
|
|
490
|
+
check(member3Membership, {
|
|
491
|
+
"Rejected user is not a member": (m) => m === null,
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// Test see-later flag functionality
|
|
496
|
+
describe("Member tests see-later flag functionality", () => {
|
|
497
|
+
// First, login as admin
|
|
498
|
+
logout();
|
|
499
|
+
authenticateWeb(adminUser.login, "password");
|
|
500
|
+
|
|
501
|
+
// Create a new invitation to test see-later flag
|
|
502
|
+
const seeLaterInvitationData: CreateInvitationParams = {
|
|
503
|
+
users: [{ userId: member3User.id, role: MembershipRole.MEMBER }],
|
|
504
|
+
message: "This invitation will be marked as see later",
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
const seeLaterInvitations = createInvitations(communityId, seeLaterInvitationData);
|
|
508
|
+
|
|
509
|
+
check(seeLaterInvitations, {
|
|
510
|
+
"See-later test invitation created successfully": (r) => r !== null && r.length > 0,
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
if (!seeLaterInvitations || seeLaterInvitations.length === 0) {
|
|
514
|
+
console.error("Failed to create see-later test invitation");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const seeLaterInvitationId = seeLaterInvitations[0].id;
|
|
519
|
+
console.log(`Created invitation with ID: ${seeLaterInvitationId} for see-later test`);
|
|
520
|
+
|
|
521
|
+
// Member logs in
|
|
522
|
+
logout();
|
|
523
|
+
authenticateWeb(member3User.login, "password");
|
|
524
|
+
|
|
525
|
+
// Check that the invitation exists in the member's list
|
|
526
|
+
const initialInvitations = listMyInvitations();
|
|
527
|
+
const initialInvitation = findInvitationById(seeLaterInvitationId, initialInvitations);
|
|
528
|
+
|
|
529
|
+
check(initialInvitation, {
|
|
530
|
+
"See-later invitation found in member's list": (r) => r !== null,
|
|
531
|
+
"See-later flag is initially false": (r) => r !== null && r.seeLater === false,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// Update the see-later flag to true
|
|
535
|
+
const updatedInvitation = updateInvitationSeeLater(seeLaterInvitationId, true);
|
|
536
|
+
|
|
537
|
+
check(updatedInvitation, {
|
|
538
|
+
"See-later flag updated successfully": (r) => r !== null,
|
|
539
|
+
"See-later flag set to true": (r) => r !== null && r.seeLater === true,
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// Verify the see-later flag is persisted when listing invitations again
|
|
543
|
+
const filteredInvitations = listMyInvitations({ seeLater: true });
|
|
544
|
+
|
|
545
|
+
check(filteredInvitations, {
|
|
546
|
+
"Can filter invitations by see-later flag": (r) => r !== null && r.items.length > 0,
|
|
547
|
+
"Filtered list contains our marked invitation": (r) =>
|
|
548
|
+
r !== null && r.items.some((inv: Invitation) => inv.id === seeLaterInvitationId),
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Change see-later flag back to false
|
|
552
|
+
const updatedAgainInvitation = updateInvitationSeeLater(seeLaterInvitationId, false);
|
|
553
|
+
|
|
554
|
+
check(updatedAgainInvitation, {
|
|
555
|
+
"See-later flag turned off successfully": (r) => r !== null,
|
|
556
|
+
"See-later flag set back to false": (r) => r !== null && r.seeLater === false,
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Verify filtering with seeLater=false
|
|
560
|
+
const nonSeeLaterInvitations = listMyInvitations({ seeLater: false });
|
|
561
|
+
|
|
562
|
+
check(nonSeeLaterInvitations, {
|
|
563
|
+
"Can filter invitations by see-later=false": (r) => r !== null,
|
|
564
|
+
"Filtered list contains our unmarked invitation": (r) =>
|
|
565
|
+
r !== null && r.items.some((inv: Invitation) => inv.id === seeLaterInvitationId),
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// Final Step: Cleanup - Delete the community
|
|
570
|
+
describe("Cleanup - Delete test community", () => {
|
|
571
|
+
// Assurez-vous que l'admin est connecté pour supprimer la communauté
|
|
572
|
+
logout();
|
|
573
|
+
authenticateWeb(adminUser.login, "password");
|
|
574
|
+
|
|
575
|
+
const deleted = deleteCommunity(communityId);
|
|
576
|
+
|
|
577
|
+
check(deleted, {
|
|
578
|
+
"community deleted successfully": (r) => r === true,
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
}
|