@@ -5,7 +5,10 @@ const mocks = vi.hoisted(() => ({
55 from : vi . fn ( )
66 } ,
77 mockJoinRoom : vi . fn ( ) ,
8- userEq : vi . fn ( )
8+ userEq : vi . fn ( ) ,
9+ participantEq : vi . fn ( ) ,
10+ participantIs : vi . fn ( ) ,
11+ participantSingle : vi . fn ( )
912} ) ) ;
1013
1114vi . mock ( '@/lib/api/middleware/auth.js' , ( ) => ( {
@@ -39,6 +42,18 @@ function createUserQuery() {
3942 return query ;
4043}
4144
45+ function createParticipantQuery ( ) {
46+ const query = {
47+ select : vi . fn ( ( ) => query ) ,
48+ eq : mocks . participantEq ,
49+ is : mocks . participantIs ,
50+ single : mocks . participantSingle
51+ } ;
52+ mocks . participantEq . mockReturnValue ( query ) ;
53+ mocks . participantIs . mockReturnValue ( query ) ;
54+ return query ;
55+ }
56+
4257function createRequest ( conversationId ) {
4358 return {
4459 json : vi . fn ( ) . mockResolvedValue ( { conversationId } )
@@ -49,8 +64,13 @@ describe('POST /api/conversations/join', () => {
4964 beforeEach ( ( ) => {
5065 vi . resetModules ( ) ;
5166 vi . clearAllMocks ( ) ;
67+ mocks . participantSingle . mockResolvedValue ( {
68+ data : { id : 'participant-id' } ,
69+ error : null
70+ } ) ;
5271 mocks . mockSupabase . from . mockImplementation ( ( table ) => {
5372 if ( table === 'users' ) return createUserQuery ( ) ;
73+ if ( table === 'conversation_participants' ) return createParticipantQuery ( ) ;
5474 throw new Error ( `Unexpected table: ${ table } ` ) ;
5575 } ) ;
5676 } ) ;
@@ -72,6 +92,24 @@ describe('POST /api/conversations/join', () => {
7292
7393 expect ( response . status ) . toBe ( 200 ) ;
7494 expect ( mocks . userEq ) . toHaveBeenCalledWith ( 'auth_user_id' , 'auth-user-id' ) ;
95+ expect ( mocks . participantEq ) . toHaveBeenCalledWith ( 'conversation_id' , 'conversation-1' ) ;
96+ expect ( mocks . participantEq ) . toHaveBeenCalledWith ( 'user_id' , 'internal-user-id' ) ;
97+ expect ( mocks . participantIs ) . toHaveBeenCalledWith ( 'left_at' , null ) ;
7598 expect ( mocks . mockJoinRoom ) . toHaveBeenCalledWith ( 'internal-user-id' , 'conversation-1' ) ;
7699 } ) ;
100+
101+ it ( 'rejects users who are not active conversation participants' , async ( ) => {
102+ mocks . participantSingle . mockResolvedValue ( {
103+ data : null ,
104+ error : { message : 'No rows found' }
105+ } ) ;
106+
107+ const { POST } = await import ( './route.js' ) ;
108+ const response = await POST ( createRequest ( 'conversation-1' ) ) ;
109+ const body = await response . json ( ) ;
110+
111+ expect ( response . status ) . toBe ( 403 ) ;
112+ expect ( body ) . toEqual ( { error : 'Access denied to conversation' } ) ;
113+ expect ( mocks . mockJoinRoom ) . not . toHaveBeenCalled ( ) ;
114+ } ) ;
77115} ) ;
0 commit comments