Skip to content

Commit 38c342c

Browse files
author
Rajat
committed
Added tests
1 parent f4fae92 commit 38c342c

File tree

8 files changed

+615
-0
lines changed

8 files changed

+615
-0
lines changed

apps/web/graphql/communities/__tests__/delete-community.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
136136
communityId: "dc-disabled-comm",
137137
name: "Disabled Community",
138138
pageId: "disabled-page",
139+
slug: "disabled-page",
139140
enabled: false,
140141
deleted: false,
141142
});
@@ -170,6 +171,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
170171
communityId: "dc-comm-posts",
171172
name: "Community with Posts",
172173
pageId: "comm-posts-page",
174+
slug: "comm-posts-page",
173175
enabled: true,
174176
deleted: false,
175177
});
@@ -208,6 +210,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
208210
communityId: "dc-comm-comments",
209211
name: "Community with Comments",
210212
pageId: "comm-comments-page",
213+
slug: "comm-comments-page",
211214
enabled: true,
212215
deleted: false,
213216
});
@@ -255,6 +258,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
255258
communityId: "dc-comm-reports",
256259
name: "Community with Reports",
257260
pageId: "comm-reports-page",
261+
slug: "comm-reports-page",
258262
enabled: true,
259263
deleted: false,
260264
});
@@ -293,6 +297,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
293297
communityId: "dc-comm-subs",
294298
name: "Community with Subscriptions",
295299
pageId: "comm-subs-page",
300+
slug: "comm-subs-page",
296301
enabled: true,
297302
deleted: false,
298303
});
@@ -340,6 +345,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
340345
communityId: "dc-comm-members",
341346
name: "Community with Members",
342347
pageId: "comm-members-page",
348+
slug: "comm-members-page",
343349
enabled: true,
344350
deleted: false,
345351
});
@@ -399,6 +405,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
399405
communityId: "dc-comm-subscriptions",
400406
name: "Community with Subscriptions",
401407
pageId: "comm-subscriptions-page",
408+
slug: "comm-subscriptions-page",
402409
enabled: true,
403410
deleted: false,
404411
});
@@ -476,6 +483,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
476483
communityId: "dc-comm-plans",
477484
name: "Community with Plans",
478485
pageId: "comm-plans-page",
486+
slug: "comm-plans-page",
479487
enabled: true,
480488
deleted: false,
481489
});
@@ -518,6 +526,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
518526
communityId: "dc-comm-included",
519527
name: "Community with Included Products",
520528
pageId: "comm-included-page",
529+
slug: "comm-included-page",
521530
enabled: true,
522531
deleted: false,
523532
});
@@ -592,6 +601,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
592601
communityId: "dc-comm-page",
593602
name: "Community with Page",
594603
pageId: "comm-page-test",
604+
slug: "comm-page-test",
595605
enabled: true,
596606
deleted: false,
597607
});
@@ -620,6 +630,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
620630
communityId: "dc-comm-media",
621631
name: "Community with Media",
622632
pageId: "comm-media-page",
633+
slug: "comm-media-page",
623634
enabled: true,
624635
deleted: false,
625636
featuredImage: {
@@ -657,6 +668,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
657668
communityId: "dc-comm-delete",
658669
name: "Community to Delete",
659670
pageId: "comm-delete-page",
671+
slug: "comm-delete-page",
660672
enabled: true,
661673
deleted: false,
662674
});
@@ -687,6 +699,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
687699
communityId: "dc-comm-complex",
688700
name: "Complex Community",
689701
pageId: "comm-complex-page",
702+
slug: "comm-complex-page",
690703
enabled: true,
691704
deleted: false,
692705
featuredImage: {
@@ -836,6 +849,7 @@ describe("deleteCommunity - Comprehensive Test Suite", () => {
836849
communityId: "dc-comm-empty",
837850
name: "Empty Community",
838851
pageId: "comm-empty-page",
852+
slug: "comm-empty-page",
839853
enabled: true,
840854
deleted: false,
841855
});

apps/web/graphql/communities/__tests__/logic.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ describe("Community Logic - Comment Count Tests", () => {
8282
communityId: "test-comm-logic",
8383
name: "Test Community Logic",
8484
pageId: "test-page-logic",
85+
slug: "test-page-logic",
8586
enabled: true,
8687
deleted: false,
8788
categories: ["General"],
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/**
2+
* @jest-environment node
3+
*/
4+
5+
import { createCommunity, updateCommunity } from "../logic";
6+
import CommunityModel from "@models/Community";
7+
import MembershipModel from "@models/Membership";
8+
import PaymentPlanModel from "@models/PaymentPlan";
9+
import PageModel from "@models/Page";
10+
import DomainModel from "@models/Domain";
11+
import UserModel from "@models/User";
12+
import constants from "@/config/constants";
13+
import { Constants } from "@courselit/common-models";
14+
15+
jest.mock("@/services/queue");
16+
jest.mock("nanoid", () => ({
17+
nanoid: () => Math.random().toString(36).substring(7),
18+
}));
19+
jest.mock("slugify", () => ({
20+
__esModule: true,
21+
default: jest.fn((str) =>
22+
str
23+
.toLowerCase()
24+
.replace(/[^a-z0-9]+/gi, "-")
25+
.replace(/^-+|-+$/g, "")
26+
.toLowerCase(),
27+
),
28+
}));
29+
jest.unmock("@courselit/utils");
30+
31+
const SLUG_SUITE_PREFIX = `comm-slug-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
32+
const id = (suffix: string) => `${SLUG_SUITE_PREFIX}-${suffix}`;
33+
const email = (suffix: string) => `${suffix}-${SLUG_SUITE_PREFIX}@example.com`;
34+
35+
describe("Community Slug Tests", () => {
36+
let domain: any;
37+
let adminUser: any;
38+
let mockCtx: any;
39+
40+
beforeAll(async () => {
41+
domain = await DomainModel.create({
42+
name: id("domain"),
43+
email: email("domain"),
44+
});
45+
46+
adminUser = await UserModel.create({
47+
domain: domain._id,
48+
userId: id("admin"),
49+
email: email("admin"),
50+
name: "Admin",
51+
permissions: [constants.permissions.manageCommunity],
52+
active: true,
53+
unsubscribeToken: id("unsub-admin"),
54+
});
55+
56+
// Internal payment plan (required by createCommunity)
57+
await PaymentPlanModel.create({
58+
domain: domain._id,
59+
planId: id("internal-plan"),
60+
userId: adminUser.userId,
61+
entityId: "internal",
62+
entityType: Constants.MembershipEntityType.COURSE,
63+
type: "free",
64+
name: constants.internalPaymentPlanName,
65+
internal: true,
66+
interval: "monthly",
67+
cost: 0,
68+
currencyISOCode: "USD",
69+
});
70+
71+
mockCtx = {
72+
user: adminUser,
73+
subdomain: domain,
74+
} as any;
75+
});
76+
77+
afterEach(async () => {
78+
await CommunityModel.deleteMany({ domain: domain._id });
79+
await MembershipModel.deleteMany({ domain: domain._id });
80+
await PageModel.deleteMany({ domain: domain._id });
81+
await PaymentPlanModel.deleteMany({
82+
domain: domain._id,
83+
planId: { $ne: id("internal-plan") },
84+
});
85+
});
86+
87+
afterAll(async () => {
88+
await PaymentPlanModel.deleteMany({ domain: domain._id });
89+
await UserModel.deleteMany({ domain: domain._id });
90+
await DomainModel.deleteOne({ _id: domain._id });
91+
});
92+
93+
describe("createCommunity", () => {
94+
it("should generate slug matching pageId", async () => {
95+
const result = await createCommunity({
96+
name: "My Test Community",
97+
ctx: mockCtx,
98+
});
99+
100+
expect(result.slug).toBe("my-test-community");
101+
102+
const community = await CommunityModel.findOne({
103+
communityId: result.communityId,
104+
});
105+
expect(community?.slug).toBe(community?.pageId);
106+
});
107+
108+
it("should auto-suffix slug when name collides", async () => {
109+
const first = await createCommunity({
110+
name: "Duplicate Name",
111+
ctx: mockCtx,
112+
});
113+
expect(first.slug).toBe("duplicate-name");
114+
115+
// Delete the first community so the name uniqueness check passes,
116+
// but leave the Page so the slug collides
117+
await CommunityModel.deleteMany({ domain: domain._id });
118+
await MembershipModel.deleteMany({ domain: domain._id });
119+
120+
const second = await createCommunity({
121+
name: "Duplicate Name",
122+
ctx: mockCtx,
123+
});
124+
expect(second.slug).toBe("duplicate-name-1");
125+
});
126+
});
127+
128+
describe("updateCommunity slug", () => {
129+
it("should update slug and sync with Page", async () => {
130+
const created = await createCommunity({
131+
name: "Slug Update Test",
132+
ctx: mockCtx,
133+
});
134+
135+
const updated = await updateCommunity({
136+
id: created.communityId,
137+
slug: "new-custom-slug",
138+
ctx: mockCtx,
139+
});
140+
141+
expect(updated.slug).toBe("new-custom-slug");
142+
143+
const community = await CommunityModel.findOne({
144+
communityId: created.communityId,
145+
});
146+
expect(community?.slug).toBe("new-custom-slug");
147+
expect(community?.pageId).toBe("new-custom-slug");
148+
149+
const page = await PageModel.findOne({
150+
entityId: created.communityId,
151+
domain: domain._id,
152+
});
153+
expect(page?.pageId).toBe("new-custom-slug");
154+
});
155+
156+
it("should reject duplicate slug with friendly error", async () => {
157+
const comm1 = await createCommunity({
158+
name: "Community One",
159+
ctx: mockCtx,
160+
});
161+
162+
await createCommunity({
163+
name: "Community Two",
164+
ctx: mockCtx,
165+
});
166+
167+
// Try to change comm1's slug to comm2's slug
168+
await expect(
169+
updateCommunity({
170+
id: comm1.communityId,
171+
slug: "community-two",
172+
ctx: mockCtx,
173+
}),
174+
).rejects.toThrow("slug is already in use");
175+
});
176+
177+
it("should not change slug when same slug is submitted", async () => {
178+
const created = await createCommunity({
179+
name: "Same Slug Community",
180+
ctx: mockCtx,
181+
});
182+
183+
const updated = await updateCommunity({
184+
id: created.communityId,
185+
slug: "same-slug-community",
186+
ctx: mockCtx,
187+
});
188+
189+
// Should succeed without error
190+
expect(updated.slug).toBe("same-slug-community");
191+
});
192+
193+
it("should validate slug format", async () => {
194+
const created = await createCommunity({
195+
name: "Format Test",
196+
ctx: mockCtx,
197+
});
198+
199+
await expect(
200+
updateCommunity({
201+
id: created.communityId,
202+
slug: "a".repeat(201),
203+
ctx: mockCtx,
204+
}),
205+
).rejects.toThrow();
206+
});
207+
});
208+
});

0 commit comments

Comments
 (0)