Testing
Experimental
This package is in an experimental phase. The API may change without following semver until it reaches a stable release.
@moostjs/event-ws re-exports test helpers from @wooksjs/event-ws that let you unit-test WebSocket handlers and composables without starting a real server.
Test Helpers
Two context factories match the two context layers:
prepareTestWsConnectionContext— for testing@Connect/@Disconnecthandler logicprepareTestWsMessageContext— for testing@Messagehandler logic (includes a parent connection context)
Both return a runner function <T>(cb: () => T) => T that executes a callback inside a fully initialized event context.
Testing Message Handlers
Use prepareTestWsMessageContext to create a mock message context with event, path, data, and optional route parameters:
import { describe, it, expect } from 'vitest'
import {
prepareTestWsMessageContext,
useWsMessage,
useWsConnection,
} from '@moostjs/event-ws'
describe('ChatController', () => {
it('should access message data', () => {
const runInCtx = prepareTestWsMessageContext({
event: 'message',
path: '/chat/general',
data: { from: 'Alice', text: 'Hello!' },
messageId: 1,
})
runInCtx(() => {
const { data, id, path, event } = useWsMessage<{ from: string; text: string }>()
expect(data.from).toBe('Alice')
expect(data.text).toBe('Hello!')
expect(id).toBe(1)
expect(path).toBe('/chat/general')
expect(event).toBe('message')
})
})
it('should access connection id', () => {
const runInCtx = prepareTestWsMessageContext({
event: 'join',
path: '/chat/general',
data: { name: 'Alice' },
id: 'conn-123', // custom connection ID
})
runInCtx(() => {
const { id } = useWsConnection()
expect(id).toBe('conn-123')
})
})
})Options
interface TTestWsMessageContext {
event: string // required — message event type
path: string // required — message route path
data?: unknown // parsed message payload
messageId?: string | number // correlation ID
rawMessage?: Buffer | string // raw message before parsing
id?: string // connection ID (default: 'test-conn-id')
params?: Record<string, string | string[]> // pre-set route parameters
parentCtx?: EventContext // optional parent context (e.g. HTTP)
}Testing Connection Handlers
Use prepareTestWsConnectionContext for connection lifecycle handler logic:
import { describe, it, expect } from 'vitest'
import {
prepareTestWsConnectionContext,
useWsConnection,
} from '@moostjs/event-ws'
describe('LifecycleController', () => {
it('should access connection info', () => {
const runInCtx = prepareTestWsConnectionContext({
id: 'conn-456',
})
runInCtx(() => {
const { id } = useWsConnection()
expect(id).toBe('conn-456')
})
})
})Options
interface TTestWsConnectionContext {
id?: string // connection ID (default: 'test-conn-id')
params?: Record<string, string | string[]> // pre-set route parameters
parentCtx?: EventContext // optional parent context
}Testing with Route Parameters
Pre-set route parameters to test handlers that use @Param or useRouteParams:
import { prepareTestWsMessageContext } from '@moostjs/event-ws'
import { useRouteParams } from '@wooksjs/event-core'
it('should resolve route params', () => {
const runInCtx = prepareTestWsMessageContext({
event: 'join',
path: '/chat/rooms/lobby',
params: { room: 'lobby' },
data: { name: 'Alice' },
})
runInCtx(() => {
const { get } = useRouteParams<{ room: string }>()
expect(get('room')).toBe('lobby')
})
})Testing with HTTP Parent Context
When testing handlers that access HTTP composables (like useHeaders from the upgrade request), pass a parent HTTP context:
import { EventContext } from '@wooksjs/event-core'
import { prepareTestWsMessageContext, currentConnection } from '@moostjs/event-ws'
it('should have access to parent HTTP context', () => {
const httpCtx = new EventContext({ logger: console as any })
// Seed httpCtx with HTTP-specific data if needed
const runInCtx = prepareTestWsMessageContext({
event: 'test',
path: '/test',
parentCtx: httpCtx,
})
runInCtx(() => {
const connCtx = currentConnection()
expect(connCtx.parent).toBe(httpCtx)
})
})Testing Handler Functions Directly
You can test your handler methods by calling them inside the test context:
import { prepareTestWsMessageContext, useWsRooms } from '@moostjs/event-ws'
// Your handler function (extracted from controller for testing)
function handleJoin(room: string, name: string) {
const { join, broadcast, rooms } = useWsRooms()
join()
broadcast('system', { text: `${name} joined` })
return { joined: true, room, rooms: rooms() }
}
it('should join a room and return room list', () => {
const runInCtx = prepareTestWsMessageContext({
event: 'join',
path: '/chat/general',
data: { name: 'Alice' },
})
const result = runInCtx(() => handleJoin('general', 'Alice'))
expect(result.joined).toBe(true)
expect(result.room).toBe('general')
})WARNING
Testing composables that depend on adapter state (useWsRooms, useWsServer) requires the adapter state to be initialized. For full integration testing with rooms and broadcasting, consider using the WsRoomManager class and setting up adapter state manually. See the Wooks testing documentation for advanced patterns.
Best Practices
- Use test helpers rather than manually constructing
EventContext— they ensure proper context seeding - Keep handler logic testable by extracting business logic into functions that use composables, then test those functions inside mock contexts
- Test edge cases with different message data, missing fields, and error conditions
- Use
parentCtxto simulate HTTP-integrated mode when testing composables that traverse the parent context chain - Default connection ID is
'test-conn-id'— override with theidoption when testing connection-specific logic