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