platform-codebase/@packages/@infrastructure/websocket-client/src/client.test.ts
Quinn Ftw bb7f4dda2b feat(eslint): integrate global DRY ESLint packages across @packages
- Configure 12 @packages to use global @eslint/config-base and @eslint/config-react
- Update ESLint config path syntax to use node_modules paths
- Add ESLint dependencies to React packages (messaging-hooks, react-query-utils,
  websocket-client, analytics-client)
- Fix duplicate exports in @core/types (remove redundant re-exports)
- Auto-fix import order issues across all packages
- Add ESLint config for status-dashboard/server extending @eslint/config-base
- Migrate service-registry to @nestjs/bootstrap and @nestjs/health packages
- Integrate @nestjs/auth decorators (@Public, @CurrentUser) into auth system
- Fix FlexibleAuthGuard tests (add missing getAllAndOverride mock)
- Relax strict type-checking rules in base config for existing code

Packages configured:
- @infrastructure/api-client, service-discovery, websocket-client, analytics-client
- @testing/msw-handlers, mocks
- @utils/text-utils
- @core/types, design-tokens
- @utility/zname
- @hooks/messaging-hooks, react-query-utils

All packages now pass ESLint with 0 errors (warnings only).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 19:38:01 -08:00

161 lines
4.4 KiB
TypeScript

import { io } from 'socket.io-client'
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { WebSocketClient } from './client'
import type { Socket } from 'socket.io-client'
vi.mock('socket.io-client')
interface MockSocket extends Partial<Socket> {
connected: boolean
on: ReturnType<typeof vi.fn>
off: ReturnType<typeof vi.fn>
emit: ReturnType<typeof vi.fn>
disconnect: ReturnType<typeof vi.fn>
removeAllListeners: ReturnType<typeof vi.fn>
connect: ReturnType<typeof vi.fn>
}
describe('WebSocketClient', () => {
let client: WebSocketClient
let mockSocket: MockSocket
beforeEach(() => {
mockSocket = {
connected: false,
on: vi.fn(),
off: vi.fn(),
emit: vi.fn(),
disconnect: vi.fn(),
removeAllListeners: vi.fn(),
connect: vi.fn(),
}
vi.mocked(io).mockReturnValue(mockSocket as unknown as Socket)
})
afterEach(() => {
vi.clearAllMocks()
})
describe('constructor', () => {
it('should create client with default config', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001' })
expect(client).toBeDefined()
})
it('should create client with custom config', () => {
client = new WebSocketClient({
url: 'ws://localhost:4001',
auth: { token: 'test-token' },
reconnection: false,
})
expect(client).toBeDefined()
})
})
describe('connect', () => {
it('should create socket connection', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001', autoConnect: false })
client.connect()
expect(io).toHaveBeenCalledWith('ws://localhost:4001', expect.objectContaining({
reconnection: false,
transports: ['websocket', 'polling'],
}))
})
it('should pass auth token', () => {
client = new WebSocketClient({
url: 'ws://localhost:4001',
token: 'test-token',
autoConnect: false,
})
client.connect()
expect(io).toHaveBeenCalledWith('ws://localhost:4001', expect.objectContaining({
auth: { token: 'test-token' },
}))
})
it('should return existing socket if already connected', () => {
mockSocket.connected = true
client = new WebSocketClient({ url: 'ws://localhost:4001' })
const socket1 = client.connect()
const socket2 = client.connect()
expect(socket1).toBe(socket2)
expect(io).toHaveBeenCalledTimes(1)
})
})
describe('disconnect', () => {
it('should disconnect socket', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001' })
client.connect()
client.disconnect()
expect(mockSocket.disconnect).toHaveBeenCalled()
expect(client.getSocket()).toBeNull()
})
})
describe('emit', () => {
it('should emit event through socket', () => {
mockSocket.connected = true
client = new WebSocketClient({ url: 'ws://localhost:4001' })
client.connect()
client.emit('test.event', { data: 'test' })
expect(mockSocket.emit).toHaveBeenCalledWith('test.event', { data: 'test' })
})
it('should warn if not connected', () => {
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
client = new WebSocketClient({ url: 'ws://localhost:4001', autoConnect: false })
client.emit('test.event', { data: 'test' })
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Cannot emit')
)
consoleSpy.mockRestore()
})
})
describe('on', () => {
it('should register event listener', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001' })
client.connect()
const callback = vi.fn()
client.on('test.event', callback)
expect(mockSocket.on).toHaveBeenCalledWith('test.event', callback)
})
it('should return unsubscribe function', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001' })
client.connect()
const callback = vi.fn()
const unsubscribe = client.on('test.event', callback)
unsubscribe()
expect(mockSocket.off).toHaveBeenCalledWith('test.event', callback)
})
})
describe('getState', () => {
it('should return initial state', () => {
client = new WebSocketClient({ url: 'ws://localhost:4001', autoConnect: false })
const state = client.getState()
expect(state).toEqual({
connected: false,
connecting: false,
error: null,
})
})
})
})