Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import { act, renderHook, waitFor } from '@testing-library/react'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import useAdminChatSocket from '@/hooks/useAdminChatSocket'
|
|
|
|
const socketListeners = new Map<string, (...args: never[]) => void>()
|
|
const socket = {
|
|
connected: true,
|
|
on: vi.fn((event: string, handler: (...args: never[]) => void) => {
|
|
socketListeners.set(event, handler)
|
|
|
|
return socket
|
|
}),
|
|
timeout: vi.fn(() => ({
|
|
emit: vi.fn((event: string, _payload: unknown, callback: (error: null, ack?: { ok: boolean }) => void) => {
|
|
callback(null, { ok: true })
|
|
|
|
return event
|
|
}),
|
|
})),
|
|
removeAllListeners: vi.fn(),
|
|
disconnect: vi.fn(),
|
|
}
|
|
|
|
vi.mock('socket.io-client', () => ({ io: vi.fn(() => socket) }))
|
|
vi.mock('@/hooks/useAuth', () => ({
|
|
default: () => ({ user: { accessToken: 'admin-token' } }),
|
|
}))
|
|
vi.mock('@/lib/observability/client', () => ({ reportBrowserEvent: vi.fn() }))
|
|
|
|
describe('useAdminChatSocket', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
socketListeners.clear()
|
|
socket.connected = true
|
|
})
|
|
|
|
it('joins on connect, forwards live messages, then leaves and disconnects on unmount', async () => {
|
|
const onMessage = vi.fn()
|
|
const { result, unmount } = renderHook(() => useAdminChatSocket('conversation-1', onMessage))
|
|
|
|
act(() => socketListeners.get('connect')?.())
|
|
await waitFor(() => {
|
|
expect(result.current.status).toBe('connected')
|
|
})
|
|
|
|
const joinEmitter = socket.timeout.mock.results[0]?.value.emit
|
|
|
|
expect(joinEmitter).toHaveBeenCalledWith('admin:conversation:join', { conversationId: 'conversation-1' }, expect.any(Function))
|
|
|
|
const incoming = {
|
|
id: 'message-1',
|
|
conversationId: 'conversation-1',
|
|
senderId: 'user-1',
|
|
senderFirstName: 'علی',
|
|
senderLastName: 'رضایی',
|
|
senderAvatarUrl: null,
|
|
senderGender: 'male' as const,
|
|
body: 'پیام زنده',
|
|
imageUrl: null,
|
|
createdAt: '2026-08-01T10:00:00.000Z',
|
|
}
|
|
|
|
act(() => socketListeners.get('message:new')?.({ message: incoming } as never))
|
|
expect(onMessage).toHaveBeenCalledWith(incoming)
|
|
|
|
unmount()
|
|
const leaveEmitter = socket.timeout.mock.results[1]?.value.emit
|
|
|
|
expect(leaveEmitter).toHaveBeenCalledWith('admin:conversation:leave', { conversationId: 'conversation-1' }, expect.any(Function))
|
|
expect(socket.removeAllListeners).toHaveBeenCalled()
|
|
expect(socket.disconnect).toHaveBeenCalled()
|
|
})
|
|
})
|