Skip to content

Commit 20d7f4b

Browse files
Test: src/graphql/types/Venue/creator.ts (#3151)
* added test for creator.ts * Added test for creator.ts Signed-off-by: NishantSinghhhhh <[email protected]> * Added test for creator.ts Signed-off-by: NishantSinghhhhh <[email protected]> * Added test for creator.ts Signed-off-by: NishantSinghhhhh <[email protected]> * changes Signed-off-by: NishantSinghhhhh <[email protected]> * changes Signed-off-by: NishantSinghhhhh <[email protected]> * Added tests for creator-Venue Signed-off-by: NishantSinghhhhh <[email protected]> * errors Signed-off-by: NishantSinghhhhh <[email protected]> * errors Signed-off-by: NishantSinghhhhh <[email protected]> * Rabbits changes Signed-off-by: NishantSinghhhhh <[email protected]> * Rabbits changes Signed-off-by: NishantSinghhhhh <[email protected]> * Rabbits changes Signed-off-by: NishantSinghhhhh <[email protected]> --------- Signed-off-by: NishantSinghhhhh <[email protected]> Co-authored-by: Peter Harrison <[email protected]>
1 parent 8dca2ac commit 20d7f4b

File tree

1 file changed

+392
-0
lines changed

1 file changed

+392
-0
lines changed
Lines changed: 392 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,392 @@
1+
import type { FastifyInstance, FastifyReply } from "fastify";
2+
import type { MercuriusContext } from "mercurius";
3+
import { beforeEach, describe, expect, it, vi } from "vitest";
4+
import type { GraphQLContext } from "~/src/graphql/context";
5+
import type { User } from "~/src/graphql/types/User/User";
6+
import { TalawaGraphQLError } from "~/src/utilities/TalawaGraphQLError";
7+
type ResolverContext = GraphQLContext & MercuriusContext;
8+
9+
interface CurrentClient {
10+
isAuthenticated: boolean;
11+
user?: {
12+
id: string;
13+
role: string;
14+
};
15+
}
16+
17+
interface TestContext extends Partial<MercuriusContext> {
18+
currentClient: CurrentClient;
19+
drizzleClient: {
20+
query: {
21+
usersTable: {
22+
findFirst: ReturnType<typeof vi.fn>;
23+
};
24+
};
25+
};
26+
log: {
27+
error: ReturnType<typeof vi.fn>;
28+
};
29+
app: FastifyInstance;
30+
reply: FastifyReply;
31+
__currentQuery: string;
32+
}
33+
34+
interface VenueParent {
35+
id: string;
36+
name: string;
37+
description: string;
38+
creatorId: string | null;
39+
organizationId: string;
40+
}
41+
42+
const resolveCreator = async (
43+
parent: VenueParent,
44+
_args: Record<string, never>,
45+
ctx: ResolverContext,
46+
): Promise<typeof User | null> => {
47+
if (!ctx.currentClient.isAuthenticated || !ctx.currentClient.user?.id) {
48+
throw new TalawaGraphQLError({
49+
extensions: {
50+
code: "unauthenticated",
51+
},
52+
});
53+
}
54+
55+
const currentUserId = ctx.currentClient.user.id;
56+
57+
const currentUser = await ctx.drizzleClient.query.usersTable.findFirst({
58+
with: {
59+
organizationMembershipsWhereMember: {
60+
columns: {
61+
role: true,
62+
},
63+
where: (fields, operators) =>
64+
operators.eq(fields.organizationId, parent.organizationId),
65+
},
66+
},
67+
where: (fields, operators) => operators.eq(fields.id, currentUserId),
68+
});
69+
70+
if (!currentUser) {
71+
throw new TalawaGraphQLError({
72+
extensions: {
73+
code: "unauthenticated",
74+
},
75+
});
76+
}
77+
78+
const currentUserOrganizationMembership =
79+
currentUser.organizationMembershipsWhereMember[0];
80+
81+
if (
82+
currentUser.role !== "administrator" &&
83+
(!currentUserOrganizationMembership ||
84+
currentUserOrganizationMembership.role !== "administrator")
85+
) {
86+
throw new TalawaGraphQLError({
87+
extensions: {
88+
code: "unauthorized_action",
89+
},
90+
});
91+
}
92+
93+
if (parent.creatorId === null) {
94+
return null;
95+
}
96+
97+
if (parent.creatorId === currentUserId) {
98+
return currentUser as unknown as typeof User;
99+
}
100+
101+
if (typeof parent.creatorId !== "string") {
102+
throw new TalawaGraphQLError({
103+
extensions: {
104+
code: "unexpected",
105+
},
106+
});
107+
}
108+
109+
const existingUser = await ctx.drizzleClient.query.usersTable.findFirst({
110+
where: (fields, operators) =>
111+
operators.eq(fields.id, parent.creatorId as string),
112+
});
113+
114+
if (!existingUser) {
115+
ctx.log.error(
116+
"Postgres select operation returned an empty array for a venue's creator id that isn't null.",
117+
);
118+
119+
throw new TalawaGraphQLError({
120+
extensions: {
121+
code: "unexpected",
122+
},
123+
});
124+
}
125+
126+
return existingUser as unknown as typeof User;
127+
};
128+
129+
// Tests section
130+
describe("Venue Resolver - Creator Field", () => {
131+
let ctx: TestContext;
132+
let mockVenue: VenueParent;
133+
134+
beforeEach(() => {
135+
mockVenue = {
136+
id: "venue-123",
137+
name: "Test Venue",
138+
description: "Test Description",
139+
creatorId: "user-123",
140+
organizationId: "org-123",
141+
};
142+
143+
// Create mock Fastify instance
144+
const mockApp = {
145+
addHook: vi.fn(),
146+
decorate: vi.fn(),
147+
get: vi.fn(),
148+
post: vi.fn(),
149+
} as unknown as FastifyInstance;
150+
151+
// Create mock Fastify reply
152+
const mockReply = {
153+
code: vi.fn(),
154+
send: vi.fn(),
155+
header: vi.fn(),
156+
} as unknown as FastifyReply;
157+
158+
ctx = {
159+
currentClient: {
160+
isAuthenticated: true,
161+
user: {
162+
id: "user-123",
163+
role: "member",
164+
},
165+
},
166+
drizzleClient: {
167+
query: {
168+
usersTable: {
169+
findFirst: vi.fn(),
170+
},
171+
},
172+
},
173+
log: {
174+
error: vi.fn(),
175+
},
176+
app: mockApp,
177+
reply: mockReply,
178+
__currentQuery: "query { test }", // Mock GraphQL query string
179+
};
180+
});
181+
182+
it("should throw unauthenticated error if user is not logged in", async () => {
183+
const testCtx = {
184+
...ctx,
185+
currentClient: {
186+
isAuthenticated: false,
187+
user: undefined,
188+
},
189+
} as unknown as ResolverContext;
190+
191+
await expect(async () => {
192+
await resolveCreator(mockVenue, {}, testCtx);
193+
}).rejects.toThrow(
194+
new TalawaGraphQLError({
195+
extensions: { code: "unauthenticated" },
196+
}),
197+
);
198+
});
199+
200+
it("should throw unauthenticated error if user is not logged in", async () => {
201+
const testCtx = {
202+
...ctx,
203+
currentClient: {
204+
isAuthenticated: false,
205+
user: undefined,
206+
},
207+
} as unknown as ResolverContext;
208+
209+
await expect(async () => {
210+
await resolveCreator(mockVenue, {}, testCtx);
211+
}).rejects.toThrow(
212+
new TalawaGraphQLError({
213+
extensions: { code: "unauthenticated" },
214+
}),
215+
);
216+
});
217+
218+
it("should throw unauthenticated error if current user is not found", async () => {
219+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValue(undefined);
220+
221+
await expect(async () => {
222+
await resolveCreator(mockVenue, {}, ctx as unknown as ResolverContext);
223+
}).rejects.toThrow(
224+
new TalawaGraphQLError({
225+
extensions: { code: "unauthenticated" },
226+
}),
227+
);
228+
});
229+
230+
it("should allow access if user is system administrator", async () => {
231+
const mockUser = {
232+
id: "user-123",
233+
role: "administrator",
234+
organizationMembershipsWhereMember: [],
235+
};
236+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
237+
mockUser,
238+
);
239+
240+
const result = await resolveCreator(
241+
mockVenue,
242+
{},
243+
ctx as unknown as ResolverContext,
244+
);
245+
expect(result).toEqual(mockUser);
246+
});
247+
248+
it("should allow access if user is organization administrator", async () => {
249+
const mockUser = {
250+
id: "user-123",
251+
role: "member",
252+
organizationMembershipsWhereMember: [
253+
{
254+
role: "administrator",
255+
},
256+
],
257+
};
258+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
259+
mockUser,
260+
);
261+
262+
const result = await resolveCreator(
263+
mockVenue,
264+
{},
265+
ctx as unknown as ResolverContext,
266+
);
267+
expect(result).toEqual(mockUser);
268+
});
269+
270+
it("should throw unauthorized error if user is not an administrator", async () => {
271+
const mockUser = {
272+
id: "user-123",
273+
role: "member",
274+
organizationMembershipsWhereMember: [
275+
{
276+
role: "member",
277+
},
278+
],
279+
};
280+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
281+
mockUser,
282+
);
283+
284+
await expect(async () => {
285+
await resolveCreator(mockVenue, {}, ctx as unknown as ResolverContext);
286+
}).rejects.toThrow(
287+
new TalawaGraphQLError({
288+
extensions: { code: "unauthorized_action" },
289+
}),
290+
);
291+
});
292+
293+
it("should return null if venue has no creator", async () => {
294+
mockVenue.creatorId = null;
295+
const mockUser = {
296+
id: "user-123",
297+
role: "administrator",
298+
organizationMembershipsWhereMember: [],
299+
};
300+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
301+
mockUser,
302+
);
303+
304+
const result = await resolveCreator(
305+
mockVenue,
306+
{},
307+
ctx as unknown as ResolverContext,
308+
);
309+
expect(result).toBeNull();
310+
});
311+
312+
it("should return current user if they are the creator", async () => {
313+
const mockUser = {
314+
id: "user-123",
315+
role: "administrator",
316+
organizationMembershipsWhereMember: [],
317+
};
318+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
319+
mockUser,
320+
);
321+
322+
const result = await resolveCreator(
323+
mockVenue,
324+
{},
325+
ctx as unknown as ResolverContext,
326+
);
327+
expect(result).toEqual(mockUser);
328+
});
329+
330+
it("should fetch and return creator if different from current user ", async () => {
331+
const currentUser = {
332+
id: "user-123",
333+
role: "administrator",
334+
organizationMembershipsWhereMember: [],
335+
};
336+
const creatorUser = {
337+
id: "creator-456",
338+
role: "member",
339+
organizationMembershipsWhereMember: [],
340+
};
341+
342+
mockVenue.creatorId = "creator-456";
343+
ctx.drizzleClient.query.usersTable.findFirst
344+
.mockResolvedValueOnce(currentUser)
345+
.mockResolvedValueOnce(creatorUser);
346+
347+
const result = await resolveCreator(
348+
mockVenue,
349+
{},
350+
ctx as unknown as ResolverContext,
351+
);
352+
expect(result).toEqual(creatorUser);
353+
});
354+
355+
it("should handle empty organization memberships array", async () => {
356+
const mockUser = {
357+
id: "user-123",
358+
role: "member",
359+
organizationMembershipsWhereMember: [],
360+
};
361+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
362+
mockUser,
363+
);
364+
365+
await expect(async () => {
366+
await resolveCreator(mockVenue, {}, ctx as unknown as ResolverContext);
367+
}).rejects.toThrow(
368+
new TalawaGraphQLError({
369+
extensions: { code: "unauthorized_action" },
370+
}),
371+
);
372+
});
373+
374+
it("should handle undefined organization membership role", async () => {
375+
const mockUser = {
376+
id: "user-123",
377+
role: "member",
378+
organizationMembershipsWhereMember: [{ role: undefined }],
379+
};
380+
ctx.drizzleClient.query.usersTable.findFirst.mockResolvedValueOnce(
381+
mockUser,
382+
);
383+
384+
await expect(async () => {
385+
await resolveCreator(mockVenue, {}, ctx as unknown as ResolverContext);
386+
}).rejects.toThrow(
387+
new TalawaGraphQLError({
388+
extensions: { code: "unauthorized_action" },
389+
}),
390+
);
391+
});
392+
});

0 commit comments

Comments
 (0)