Skip to content

Commit da0d17c

Browse files
committed
test: add coverage for homePhoneNumber resolver
1 parent 5246239 commit da0d17c

1 file changed

Lines changed: 167 additions & 0 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { faker } from "@faker-js/faker";
2+
import type { GraphQLFieldResolver, GraphQLObjectType } from "graphql";
3+
import { createMockGraphQLContext } from "test/_Mocks_/mockContextCreator/mockContextCreator";
4+
import { afterEach, describe, expect, it, vi } from "vitest";
5+
import type { GraphQLContext } from "~/src/graphql/context";
6+
import { schema } from "~/src/graphql/schema";
7+
import type { User as UserType } from "~/src/graphql/types/User/User";
8+
9+
const userType = schema.getType("User") as GraphQLObjectType;
10+
const homePhoneNumberResolver = userType.getFields().homePhoneNumber
11+
?.resolve as GraphQLFieldResolver<UserType, GraphQLContext>;
12+
13+
describe("homePhoneNumberResolver", () => {
14+
const DEFAULT_PHONE = "1234567890";
15+
const ROLE_REGULAR = "regular";
16+
const ROLE_ADMIN = "administrator";
17+
18+
afterEach(() => {
19+
vi.restoreAllMocks();
20+
});
21+
22+
const runResolver = (parent: UserType, context: GraphQLContext) =>
23+
homePhoneNumberResolver(parent, {}, context, {} as never);
24+
25+
const createSetup = (
26+
isAuthenticated: boolean,
27+
targetPhone: string | null | undefined,
28+
isSelfAccess: boolean,
29+
) => {
30+
const currentUserId = faker.string.uuid();
31+
const targetUserId = isSelfAccess ? currentUserId : faker.string.uuid();
32+
const { context, mocks } = createMockGraphQLContext(
33+
isAuthenticated,
34+
currentUserId,
35+
);
36+
37+
const parent = {
38+
id: targetUserId,
39+
homePhoneNumber: targetPhone,
40+
} as unknown as UserType;
41+
42+
return { context, mocks, parent, currentUserId, targetUserId };
43+
};
44+
45+
it("throws unauthenticated error when client is not authenticated", async () => {
46+
const { context, mocks, parent } = createSetup(false, DEFAULT_PHONE, false);
47+
48+
await expect(runResolver(parent, context)).rejects.toThrowError(
49+
expect.objectContaining({
50+
extensions: expect.objectContaining({
51+
code: "unauthenticated",
52+
}),
53+
}),
54+
);
55+
expect(
56+
mocks.drizzleClient.query.usersTable.findFirst,
57+
).not.toHaveBeenCalled();
58+
});
59+
60+
it("throws unauthenticated error when current user cannot be found in database", async () => {
61+
const { context, mocks, parent } = createSetup(true, DEFAULT_PHONE, false);
62+
63+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue(undefined);
64+
65+
await expect(runResolver(parent, context)).rejects.toThrowError(
66+
expect.objectContaining({
67+
extensions: expect.objectContaining({
68+
code: "unauthenticated",
69+
}),
70+
}),
71+
);
72+
expect(
73+
mocks.drizzleClient.query.usersTable.findFirst,
74+
).toHaveBeenCalledOnce();
75+
});
76+
77+
it("throws unauthorized_action error when regular user accesses another user's data", async () => {
78+
const { context, mocks, parent } = createSetup(true, DEFAULT_PHONE, false);
79+
80+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
81+
role: ROLE_REGULAR,
82+
});
83+
84+
await expect(runResolver(parent, context)).rejects.toThrowError(
85+
expect.objectContaining({
86+
extensions: expect.objectContaining({
87+
code: "unauthorized_action",
88+
}),
89+
}),
90+
);
91+
expect(
92+
mocks.drizzleClient.query.usersTable.findFirst,
93+
).toHaveBeenCalledOnce();
94+
});
95+
96+
it("returns homePhoneNumber when user accesses their own data", async () => {
97+
const expectedPhone = faker.phone.number();
98+
const { context, mocks, parent } = createSetup(true, expectedPhone, true);
99+
100+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
101+
role: ROLE_REGULAR,
102+
});
103+
104+
const result = await runResolver(parent, context);
105+
expect(result).toBe(expectedPhone);
106+
expect(
107+
mocks.drizzleClient.query.usersTable.findFirst,
108+
).toHaveBeenCalledOnce();
109+
});
110+
111+
it("returns homePhoneNumber when administrator accesses another user's data", async () => {
112+
const expectedPhone = faker.phone.number();
113+
const { context, mocks, parent } = createSetup(true, expectedPhone, false);
114+
115+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
116+
role: ROLE_ADMIN,
117+
});
118+
119+
const result = await runResolver(parent, context);
120+
expect(result).toBe(expectedPhone);
121+
expect(
122+
mocks.drizzleClient.query.usersTable.findFirst,
123+
).toHaveBeenCalledOnce();
124+
});
125+
126+
it("returns null when homePhoneNumber is null", async () => {
127+
const { context, mocks, parent } = createSetup(true, null, true);
128+
129+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
130+
role: ROLE_REGULAR,
131+
});
132+
133+
const result = await runResolver(parent, context);
134+
expect(result).toBeNull();
135+
expect(
136+
mocks.drizzleClient.query.usersTable.findFirst,
137+
).toHaveBeenCalledOnce();
138+
});
139+
140+
it("returns empty string when homePhoneNumber is empty string", async () => {
141+
const { context, mocks, parent } = createSetup(true, "", true);
142+
143+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
144+
role: ROLE_REGULAR,
145+
});
146+
147+
const result = await runResolver(parent, context);
148+
expect(result).toBe("");
149+
expect(
150+
mocks.drizzleClient.query.usersTable.findFirst,
151+
).toHaveBeenCalledOnce();
152+
});
153+
154+
it("returns undefined when homePhoneNumber is undefined", async () => {
155+
const { context, mocks, parent } = createSetup(true, undefined, true);
156+
157+
mocks.drizzleClient.query.usersTable.findFirst.mockResolvedValue({
158+
role: ROLE_REGULAR,
159+
});
160+
161+
const result = await runResolver(parent, context);
162+
expect(result).toBeUndefined();
163+
expect(
164+
mocks.drizzleClient.query.usersTable.findFirst,
165+
).toHaveBeenCalledOnce();
166+
});
167+
});

0 commit comments

Comments
 (0)