Skip to content

Commit faee196

Browse files
Improve Test Coverage for src/graphql/types/Query/post.ts (PalisadoesFoundation#3261)
* fixed issue-3043 * Fix for the failing tests * code formatting * made suggested changes * fixed the error message --------- Co-authored-by: Peter Harrison <[email protected]>
1 parent cd1e06b commit faee196

File tree

1 file changed

+336
-0
lines changed

1 file changed

+336
-0
lines changed
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
import { faker } from "@faker-js/faker";
2+
import { hash } from "@node-rs/argon2";
3+
import { eq } from "drizzle-orm";
4+
import { organizationsTable, postsTable, usersTable } from "src/drizzle/schema";
5+
import { uuidv7 } from "uuidv7";
6+
import { beforeEach, expect, suite, test } from "vitest";
7+
import type {
8+
ArgumentsAssociatedResourcesNotFoundExtensions,
9+
InvalidArgumentsExtensions,
10+
TalawaGraphQLFormattedError,
11+
UnauthenticatedExtensions,
12+
UnauthorizedActionOnArgumentsAssociatedResourcesExtensions,
13+
} from "~/src/utilities/TalawaGraphQLError";
14+
import { server } from "../../../server";
15+
import { mercuriusClient } from "../client";
16+
import { Query_post, Query_signIn } from "../documentNodes";
17+
18+
suite("Query field post", () => {
19+
let adminUserId: string;
20+
21+
// Add the helper function for creating test users
22+
const createTestUser = async (
23+
role: "regular" | "administrator" = "regular",
24+
) => {
25+
const testEmail = `test.user.${faker.string.ulid()}@email.com`;
26+
const testPassword = "password";
27+
28+
const hashedPassword = await hash(testPassword);
29+
30+
const [userRow] = await server.drizzleClient
31+
.insert(usersTable)
32+
.values({
33+
emailAddress: testEmail,
34+
passwordHash: hashedPassword,
35+
role,
36+
name: faker.person.fullName(),
37+
isEmailAddressVerified: true,
38+
})
39+
.returning({
40+
id: usersTable.id,
41+
});
42+
43+
if (!userRow)
44+
throw new Error(
45+
"Failed to create test user: Database insert operation returned no rows",
46+
);
47+
48+
return { userId: userRow.id, email: testEmail, password: testPassword };
49+
};
50+
51+
beforeEach(async () => {
52+
const [existingAdmin] = await server.drizzleClient
53+
.select({ id: usersTable.id })
54+
.from(usersTable)
55+
.where(
56+
eq(
57+
usersTable.emailAddress,
58+
server.envConfig.API_ADMINISTRATOR_USER_EMAIL_ADDRESS,
59+
),
60+
)
61+
.limit(1);
62+
if (existingAdmin) {
63+
adminUserId = existingAdmin.id;
64+
return;
65+
}
66+
const [newAdmin] = await server.drizzleClient
67+
.insert(usersTable)
68+
.values({
69+
emailAddress: server.envConfig.API_ADMINISTRATOR_USER_EMAIL_ADDRESS,
70+
passwordHash: server.envConfig.API_ADMINISTRATOR_USER_PASSWORD,
71+
role: "administrator",
72+
name: server.envConfig.API_ADMINISTRATOR_USER_NAME,
73+
isEmailAddressVerified: true,
74+
})
75+
.onConflictDoNothing()
76+
.returning({ id: usersTable.id });
77+
if (!newAdmin) throw new Error("Failed to create admin user");
78+
adminUserId = newAdmin.id;
79+
});
80+
81+
const getAuthToken = async () => {
82+
const signInResult = await mercuriusClient.query(Query_signIn, {
83+
variables: {
84+
input: {
85+
emailAddress: server.envConfig.API_ADMINISTRATOR_USER_EMAIL_ADDRESS,
86+
password: server.envConfig.API_ADMINISTRATOR_USER_PASSWORD,
87+
},
88+
},
89+
});
90+
if (!signInResult.data?.signIn?.authenticationToken) {
91+
throw new Error(
92+
"Failed to get authentication token: Sign-in operation failed",
93+
);
94+
}
95+
return signInResult.data.signIn?.authenticationToken;
96+
};
97+
98+
const createTestPost = async (creatorId: string) => {
99+
const [organizationRow] = await server.drizzleClient
100+
.insert(organizationsTable)
101+
.values({
102+
name: faker.company.name(),
103+
countryCode: "us",
104+
})
105+
.returning({ id: organizationsTable.id });
106+
107+
const organizationId = organizationRow?.id;
108+
if (!organizationId) throw new Error("Failed to create organization.");
109+
110+
const [postRow] = await server.drizzleClient
111+
.insert(postsTable)
112+
.values({
113+
caption: faker.lorem.paragraph(),
114+
creatorId,
115+
organizationId,
116+
})
117+
.returning({ id: postsTable.id });
118+
119+
const postId = postRow?.id;
120+
if (!postId) throw new Error("Failed to create post.");
121+
122+
return { postId, organizationId };
123+
};
124+
125+
suite(
126+
`results in a graphql error with "unauthenticated" extensions code in the "errors" field and "null" as the value of "data.post" field if`,
127+
() => {
128+
test("client triggering the graphql operation is not authenticated.", async () => {
129+
const result = await mercuriusClient.query(Query_post, {
130+
variables: {
131+
input: {
132+
id: uuidv7(),
133+
},
134+
},
135+
});
136+
expect(result.data.post).toEqual(null);
137+
expect(result.errors).toEqual(
138+
expect.arrayContaining<TalawaGraphQLFormattedError>([
139+
expect.objectContaining<TalawaGraphQLFormattedError>({
140+
extensions: expect.objectContaining<UnauthenticatedExtensions>({
141+
code: "unauthenticated",
142+
}),
143+
message: expect.any(String),
144+
path: ["post"],
145+
}),
146+
]),
147+
);
148+
});
149+
},
150+
);
151+
suite(
152+
`results in a graphql error with "invalid_arguments" extensions code in the "errors" field and "null" as the value of "data.post" field if`,
153+
() => {
154+
test("the provided post ID is not a valid UUID.", async () => {
155+
const authToken = await getAuthToken();
156+
const result = await mercuriusClient.query(Query_post, {
157+
headers: {
158+
authorization: `bearer ${authToken}`,
159+
},
160+
variables: {
161+
input: {
162+
id: "not-a-uuid",
163+
},
164+
},
165+
});
166+
expect(result.data.post).toEqual(null);
167+
expect(result.errors).toEqual(
168+
expect.arrayContaining<TalawaGraphQLFormattedError>([
169+
expect.objectContaining<TalawaGraphQLFormattedError>({
170+
extensions: expect.objectContaining<InvalidArgumentsExtensions>({
171+
code: "invalid_arguments",
172+
issues: expect.arrayContaining([
173+
{
174+
argumentPath: ["input", "id"],
175+
message: expect.any(String),
176+
},
177+
]),
178+
}),
179+
message: expect.any(String),
180+
path: ["post"],
181+
}),
182+
]),
183+
);
184+
});
185+
},
186+
);
187+
suite(
188+
`results in a graphql error with "arguments_associated_resources_not_found" extensions code in the "errors" field and "null" as the value of "data.post" field if`,
189+
() => {
190+
test(`value of the "input.id" does not correspond to an existing post.`, async () => {
191+
const authToken = await getAuthToken();
192+
const result = await mercuriusClient.query(Query_post, {
193+
headers: {
194+
authorization: `bearer ${authToken}`,
195+
},
196+
variables: {
197+
input: {
198+
id: uuidv7(),
199+
},
200+
},
201+
});
202+
expect(result.data.post).toEqual(null);
203+
expect(result.errors).toEqual(
204+
expect.arrayContaining<TalawaGraphQLFormattedError>([
205+
expect.objectContaining<TalawaGraphQLFormattedError>({
206+
extensions:
207+
expect.objectContaining<ArgumentsAssociatedResourcesNotFoundExtensions>(
208+
{
209+
code: "arguments_associated_resources_not_found",
210+
issues: expect.arrayContaining<
211+
ArgumentsAssociatedResourcesNotFoundExtensions["issues"][number]
212+
>([
213+
{
214+
argumentPath: ["input", "id"],
215+
},
216+
]),
217+
},
218+
),
219+
message: expect.any(String),
220+
path: ["post"],
221+
}),
222+
]),
223+
);
224+
});
225+
},
226+
);
227+
suite(
228+
`results in a graphql error with "unauthenticated" extensions code in the "errors" field and "null" as the value of "data.post" field if`,
229+
() => {
230+
test("authenticated user exists in token but not in database.", async () => {
231+
const { userId, email, password } =
232+
await createTestUser("administrator");
233+
const signInResult = await mercuriusClient.query(Query_signIn, {
234+
variables: {
235+
input: {
236+
emailAddress: email,
237+
password: password,
238+
},
239+
},
240+
});
241+
242+
const authToken = signInResult.data?.signIn?.authenticationToken;
243+
if (!authToken)
244+
throw new Error(
245+
"Failed to get authentication token from sign-in result",
246+
);
247+
248+
await server.drizzleClient
249+
.delete(usersTable)
250+
.where(eq(usersTable.id, userId));
251+
const result = await mercuriusClient.query(Query_post, {
252+
headers: {
253+
authorization: `bearer ${authToken}`,
254+
},
255+
variables: {
256+
input: {
257+
id: uuidv7(),
258+
},
259+
},
260+
});
261+
expect(result.data.post).toEqual(null);
262+
expect(result.errors).toEqual(
263+
expect.arrayContaining<TalawaGraphQLFormattedError>([
264+
expect.objectContaining<TalawaGraphQLFormattedError>({
265+
extensions: expect.objectContaining<UnauthenticatedExtensions>({
266+
code: "unauthenticated",
267+
}),
268+
message: expect.any(String),
269+
path: ["post"],
270+
}),
271+
]),
272+
);
273+
});
274+
},
275+
);
276+
suite(
277+
`results in a graphql error with "unauthorized_action_on_arguments_associated_resources" extensions code in the "errors" field and "null" as the value of "data.post" field if`,
278+
() => {
279+
test("regular user attempts to access a post from an organization they are not a member of", async () => {
280+
// Create test user using the helper function
281+
const { email, password } = await createTestUser();
282+
// Create a different user's post
283+
const { postId } = await createTestPost(adminUserId);
284+
// Sign in with plain password
285+
const signInResult = await mercuriusClient.query(Query_signIn, {
286+
variables: {
287+
input: {
288+
emailAddress: email,
289+
password: password,
290+
},
291+
},
292+
});
293+
const authToken = signInResult.data?.signIn?.authenticationToken;
294+
// validation for authentication token
295+
if (!authToken) {
296+
console.error(
297+
"SignIn Result:",
298+
JSON.stringify(signInResult, null, 2),
299+
);
300+
throw new Error("Failed to get authentication token");
301+
}
302+
// Attempt to access post
303+
const result = await mercuriusClient.query(Query_post, {
304+
headers: {
305+
authorization: `bearer ${authToken}`,
306+
},
307+
variables: {
308+
input: {
309+
id: postId,
310+
},
311+
},
312+
});
313+
expect(result.data.post).toEqual(null);
314+
expect(result.errors).toEqual(
315+
expect.arrayContaining<TalawaGraphQLFormattedError>([
316+
expect.objectContaining<TalawaGraphQLFormattedError>({
317+
extensions:
318+
expect.objectContaining<UnauthorizedActionOnArgumentsAssociatedResourcesExtensions>(
319+
{
320+
code: "unauthorized_action_on_arguments_associated_resources",
321+
issues: expect.arrayContaining([
322+
{
323+
argumentPath: ["input", "id"],
324+
},
325+
]),
326+
},
327+
),
328+
message: expect.any(String),
329+
path: ["post"],
330+
}),
331+
]),
332+
);
333+
});
334+
},
335+
);
336+
});

0 commit comments

Comments
 (0)