@stacksjs/bun-router 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -584
- package/bin/cli.ts +9 -0
- package/dist/auth.d.ts +134 -0
- package/dist/cache/lru-cache.d.ts +139 -0
- package/dist/cache/middleware-memoization.d.ts +151 -0
- package/dist/cache/route-cache-warmer.d.ts +161 -0
- package/dist/cache/sqlite-cache.d.ts +209 -0
- package/dist/cache/streaming-cache.d.ts +132 -0
- package/dist/chunk-j0e7z7hd.js +18053 -0
- package/dist/cli/colors.d.ts +15 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/middleware.d.ts +31 -0
- package/dist/cli/openapi.d.ts +17 -0
- package/dist/cli/router.d.ts +15 -0
- package/dist/cli/routes.d.ts +29 -0
- package/dist/cli/utils.d.ts +74 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +3360 -0
- package/dist/config.d.ts +7 -0
- package/dist/container/container.d.ts +273 -0
- package/dist/container/contextual-binding.d.ts +240 -0
- package/dist/container/decorators.d.ts +141 -0
- package/dist/container/service-provider.d.ts +285 -0
- package/dist/development/hot-reload.d.ts +187 -0
- package/dist/development/index.d.ts +167 -0
- package/dist/development/performance-profiler.d.ts +217 -0
- package/dist/development/route-debugger.d.ts +154 -0
- package/dist/development/route-inspector.d.ts +211 -0
- package/dist/development/typescript-utilities.d.ts +209 -0
- package/dist/docs.d.ts +11 -0
- package/dist/errors/circuit-breaker.d.ts +195 -0
- package/dist/errors/error-handler.d.ts +88 -0
- package/dist/errors/error-reporting.d.ts +144 -0
- package/dist/errors/exceptions.d.ts +184 -0
- package/dist/errors/graceful-degradation.d.ts +154 -0
- package/dist/errors/index.d.ts +9 -0
- package/dist/errors/router-errors.d.ts +110 -0
- package/dist/file-serving/static-files.d.ts +143 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13968 -0
- package/dist/middleware/auth.d.ts +63 -0
- package/dist/middleware/content_security_policy.d.ts +53 -0
- package/dist/middleware/cors.d.ts +5 -0
- package/dist/middleware/csrf.d.ts +7 -0
- package/dist/middleware/ddos_protection.d.ts +39 -0
- package/dist/middleware/file_security.d.ts +26 -0
- package/dist/middleware/file_upload.d.ts +38 -0
- package/dist/middleware/helmet.d.ts +54 -0
- package/dist/middleware/index.d.ts +44 -0
- package/dist/middleware/input_validation.d.ts +45 -0
- package/dist/middleware/json_body.d.ts +4 -0
- package/dist/middleware/performance_alerting.d.ts +87 -0
- package/dist/middleware/performance_dashboard.d.ts +87 -0
- package/dist/middleware/performance_monitor.d.ts +209 -0
- package/dist/middleware/pipeline.d.ts +131 -0
- package/dist/middleware/rate_limit.d.ts +36 -0
- package/dist/middleware/request_id.d.ts +4 -0
- package/dist/middleware/request_signing.d.ts +153 -0
- package/dist/middleware/request_tracer.d.ts +72 -0
- package/dist/middleware/response_cache.d.ts +97 -0
- package/dist/middleware/security.d.ts +69 -0
- package/dist/middleware/security_suite.d.ts +46 -0
- package/dist/middleware/session.d.ts +23 -0
- package/dist/model-binding/index.d.ts +2 -0
- package/dist/model-binding/model-middleware.d.ts +118 -0
- package/dist/model-binding/model-registry.d.ts +164 -0
- package/dist/model-binding.d.ts +185 -0
- package/dist/model-resolver-factory.d.ts +31 -0
- package/dist/observability/correlation.d.ts +187 -0
- package/dist/observability/health-checks.d.ts +186 -0
- package/dist/observability/index.d.ts +60 -0
- package/dist/observability/integration.d.ts +147 -0
- package/dist/observability/metrics.d.ts +184 -0
- package/dist/observability/tracing.d.ts +187 -0
- package/dist/optimization/bun-utilities.d.ts +224 -0
- package/dist/query-builder-integration.d.ts +36 -0
- package/dist/request/context.d.ts +34 -0
- package/dist/request/enhanced-request.d.ts +213 -0
- package/dist/request/macros.d.ts +300 -0
- package/dist/response/macros.d.ts +256 -0
- package/dist/response/response-factory.d.ts +133 -0
- package/dist/router/api-routes.d.ts +5 -0
- package/dist/router/file-based-routing.d.ts +118 -0
- package/dist/router/file-streaming.d.ts +5 -0
- package/dist/router/fluent-router.d.ts +315 -0
- package/dist/router/fluent-routing.d.ts +271 -0
- package/dist/router/group-organization.d.ts +5 -0
- package/dist/router/handler-resolver.d.ts +24 -0
- package/dist/router/http-methods.d.ts +10 -0
- package/dist/router/index.d.ts +114 -0
- package/dist/router/middleware-groups.d.ts +94 -0
- package/dist/router/middleware-integration.d.ts +112 -0
- package/dist/router/middleware.d.ts +5 -0
- package/dist/router/model-binding.d.ts +5 -0
- package/dist/router/optimized-route-matching.d.ts +6 -0
- package/dist/router/route-building.d.ts +5 -0
- package/dist/router/route-compiler.d.ts +153 -0
- package/dist/router/route-matching.d.ts +5 -0
- package/dist/router/route-trie.d.ts +114 -0
- package/dist/router/router.d.ts +317 -0
- package/dist/router/server.d.ts +5 -0
- package/dist/router/validation-integration.d.ts +170 -0
- package/dist/router/view-rendering.d.ts +5 -0
- package/dist/router/websocket.d.ts +5 -0
- package/dist/routing/route-caching.d.ts +129 -0
- package/dist/routing/route-throttling.d.ts +150 -0
- package/dist/routing/subdomain-routing.d.ts +206 -0
- package/dist/session/database-store.d.ts +51 -0
- package/dist/session/file-store.d.ts +22 -0
- package/dist/session/index.d.ts +106 -0
- package/dist/session/memory-store.d.ts +21 -0
- package/dist/session/redis-store.d.ts +31 -0
- package/dist/streaming/index.d.ts +3 -0
- package/dist/streaming/sse-handler.d.ts +138 -0
- package/dist/streaming/stream-handler.d.ts +114 -0
- package/dist/testing/auth-testing.d.ts +156 -0
- package/dist/testing/file-upload-testing.d.ts +190 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/middleware-testing.d.ts +138 -0
- package/dist/testing/model-binding-testing.d.ts +186 -0
- package/dist/testing/performance-testing.d.ts +235 -0
- package/dist/testing/test-client.d.ts +117 -0
- package/dist/testing/test-request.d.ts +85 -0
- package/dist/testing/test-response.d.ts +90 -0
- package/dist/testing/types.d.ts +207 -0
- package/dist/testing/websocket-testing.d.ts +227 -0
- package/dist/types/controller-types.d.ts +208 -0
- package/dist/types/core.d.ts +543 -0
- package/dist/types/middleware-types.d.ts +227 -0
- package/dist/types/request-response-augmentation.d.ts +261 -0
- package/dist/types/route-inference.d.ts +168 -0
- package/dist/types.d.ts +1794 -0
- package/dist/url.d.ts +56 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/query-preservation.d.ts +48 -0
- package/dist/utils.d.ts +69 -0
- package/dist/validation/validator.d.ts +140 -0
- package/dist/websocket/clustering.d.ts +185 -0
- package/package.json +45 -44
- package/src/auth.ts +469 -0
- package/src/cache/lru-cache.ts +457 -0
- package/src/cache/middleware-memoization.ts +531 -0
- package/src/cache/route-cache-warmer.ts +486 -0
- package/src/cache/sqlite-cache.ts +783 -0
- package/src/cache/streaming-cache.ts +572 -0
- package/src/cli/colors.ts +29 -0
- package/src/cli/index.ts +287 -0
- package/src/cli/middleware.ts +291 -0
- package/src/cli/openapi.ts +407 -0
- package/src/cli/router.ts +188 -0
- package/src/cli/routes.ts +265 -0
- package/src/cli/utils.ts +531 -0
- package/src/cli.ts +5 -0
- package/src/config.ts +322 -0
- package/src/container/container.ts +740 -0
- package/src/container/contextual-binding.ts +603 -0
- package/src/container/decorators.ts +359 -0
- package/src/container/service-provider.ts +596 -0
- package/src/development/hot-reload.ts +673 -0
- package/src/development/index.ts +499 -0
- package/src/development/performance-profiler.ts +717 -0
- package/src/development/route-debugger.ts +527 -0
- package/src/development/route-inspector.ts +749 -0
- package/src/development/typescript-utilities.ts +682 -0
- package/src/docs.ts +397 -0
- package/src/errors/circuit-breaker.ts +732 -0
- package/src/errors/error-handler.ts +569 -0
- package/src/errors/error-reporting.ts +672 -0
- package/src/errors/exceptions.ts +536 -0
- package/src/errors/graceful-degradation.ts +621 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/router-errors.ts +632 -0
- package/src/file-serving/static-files.ts +581 -0
- package/src/index.ts +14 -0
- package/src/middleware/auth.ts +220 -0
- package/src/middleware/content_security_policy.ts +215 -0
- package/src/middleware/cors.ts +74 -0
- package/src/middleware/csrf.ts +108 -0
- package/src/middleware/ddos_protection.ts +255 -0
- package/src/middleware/file_security.ts +191 -0
- package/src/middleware/file_upload.ts +275 -0
- package/src/middleware/helmet.ts +268 -0
- package/src/middleware/index.ts +117 -0
- package/src/middleware/input_validation.ts +449 -0
- package/src/middleware/json_body.ts +37 -0
- package/src/middleware/performance_alerting.ts +538 -0
- package/src/middleware/performance_dashboard.ts +661 -0
- package/src/middleware/performance_monitor.ts +943 -0
- package/src/middleware/pipeline.ts +489 -0
- package/src/middleware/rate_limit.ts +245 -0
- package/src/middleware/request_id.ts +36 -0
- package/src/middleware/request_signing.ts +636 -0
- package/src/middleware/request_tracer.ts +636 -0
- package/src/middleware/response_cache.ts +743 -0
- package/src/middleware/security.ts +482 -0
- package/src/middleware/security_suite.ts +257 -0
- package/src/middleware/session.ts +91 -0
- package/src/model-binding/index.ts +18 -0
- package/src/model-binding/model-middleware.ts +425 -0
- package/src/model-binding/model-registry.ts +550 -0
- package/src/model-binding.ts +370 -0
- package/src/model-resolver-factory.ts +106 -0
- package/src/observability/correlation.ts +691 -0
- package/src/observability/health-checks.ts +729 -0
- package/src/observability/index.ts +184 -0
- package/src/observability/integration.ts +548 -0
- package/src/observability/metrics.ts +753 -0
- package/src/observability/tracing.ts +638 -0
- package/src/optimization/bun-utilities.ts +778 -0
- package/src/query-builder-integration.ts +137 -0
- package/src/request/context.ts +62 -0
- package/src/request/enhanced-request.ts +857 -0
- package/src/request/macros.ts +688 -0
- package/src/response/macros.ts +665 -0
- package/src/response/response-factory.ts +596 -0
- package/src/router/api-routes.ts +243 -0
- package/src/router/file-based-routing.ts +690 -0
- package/src/router/file-streaming.ts +383 -0
- package/src/router/fluent-router.ts +927 -0
- package/src/router/fluent-routing.ts +797 -0
- package/src/router/group-organization.ts +213 -0
- package/src/router/handler-resolver.ts +291 -0
- package/src/router/http-methods.ts +377 -0
- package/src/router/index.ts +187 -0
- package/src/router/middleware-groups.ts +222 -0
- package/src/router/middleware-integration.ts +399 -0
- package/src/router/middleware.ts +231 -0
- package/src/router/model-binding.ts +215 -0
- package/src/router/optimized-route-matching.ts +253 -0
- package/src/router/route-building.ts +221 -0
- package/src/router/route-compiler.ts +702 -0
- package/src/router/route-matching.ts +349 -0
- package/src/router/route-trie.ts +464 -0
- package/src/router/router.ts +1604 -0
- package/src/router/server.ts +462 -0
- package/src/router/validation-integration.ts +443 -0
- package/src/router/view-rendering.ts +233 -0
- package/src/router/websocket.ts +100 -0
- package/src/routing/route-caching.ts +402 -0
- package/src/routing/route-throttling.ts +469 -0
- package/src/routing/subdomain-routing.ts +492 -0
- package/src/session/database-store.ts +109 -0
- package/src/session/file-store.ts +148 -0
- package/src/session/index.ts +244 -0
- package/src/session/memory-store.ts +88 -0
- package/src/session/redis-store.ts +93 -0
- package/src/streaming/index.ts +17 -0
- package/src/streaming/sse-handler.ts +482 -0
- package/src/streaming/stream-handler.ts +552 -0
- package/src/testing/auth-testing.ts +446 -0
- package/src/testing/file-upload-testing.ts +543 -0
- package/src/testing/index.ts +10 -0
- package/src/testing/middleware-testing.ts +322 -0
- package/src/testing/model-binding-testing.ts +645 -0
- package/src/testing/performance-testing.ts +738 -0
- package/src/testing/test-client.ts +310 -0
- package/src/testing/test-request.ts +315 -0
- package/src/testing/test-response.ts +332 -0
- package/src/testing/types.ts +224 -0
- package/src/testing/websocket-testing.ts +590 -0
- package/src/types/controller-types.ts +385 -0
- package/src/types/core.ts +683 -0
- package/src/types/middleware-types.ts +419 -0
- package/src/types/request-response-augmentation.ts +489 -0
- package/src/types/route-inference.ts +357 -0
- package/src/types.ts +2067 -0
- package/src/url.ts +126 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/query-preservation.ts +201 -0
- package/src/utils.ts +327 -0
- package/src/validation/validator.ts +685 -0
- package/src/websocket/clustering.ts +762 -0
- package/CHANGELOG.md +0 -770
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import type { ServerWebSocket } from 'bun'
|
|
2
|
+
import type { WSTestClient, WSTestMessage } from './types'
|
|
3
|
+
import { mock } from 'bun:test'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WebSocket testing utilities
|
|
7
|
+
*/
|
|
8
|
+
export class WebSocketTester {
|
|
9
|
+
private messages: WSTestMessage[] = []
|
|
10
|
+
private isConnected: boolean = false
|
|
11
|
+
private readyState: number = 0 // CONNECTING
|
|
12
|
+
private eventHandlers: Map<string, ((..._args: any[]) => any)[]> = new Map()
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.setupEventHandlers()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private setupEventHandlers(): void {
|
|
19
|
+
this.eventHandlers.set('open', [])
|
|
20
|
+
this.eventHandlers.set('message', [])
|
|
21
|
+
this.eventHandlers.set('close', [])
|
|
22
|
+
this.eventHandlers.set('error', [])
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Simulate WebSocket connection
|
|
27
|
+
*/
|
|
28
|
+
connect(): WebSocketTester {
|
|
29
|
+
this.isConnected = true
|
|
30
|
+
this.readyState = 1 // OPEN
|
|
31
|
+
this.emit('open', { type: 'open' })
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Simulate WebSocket disconnection
|
|
37
|
+
*/
|
|
38
|
+
disconnect(code: number = 1000, reason: string = 'Normal closure'): WebSocketTester {
|
|
39
|
+
this.isConnected = false
|
|
40
|
+
this.readyState = 3 // CLOSED
|
|
41
|
+
this.emit('close', { type: 'close', code, reason })
|
|
42
|
+
return this
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Simulate sending a message
|
|
47
|
+
*/
|
|
48
|
+
send(data: string | ArrayBuffer | Uint8Array): WebSocketTester {
|
|
49
|
+
if (!this.isConnected) {
|
|
50
|
+
throw new Error('WebSocket is not connected')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const message: WSTestMessage = {
|
|
54
|
+
type: typeof data === 'string' ? 'text' : 'binary',
|
|
55
|
+
data,
|
|
56
|
+
timestamp: Date.now(),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.messages.push(message)
|
|
60
|
+
return this
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Simulate receiving a message
|
|
65
|
+
*/
|
|
66
|
+
receive(data: string | ArrayBuffer | Uint8Array): WebSocketTester {
|
|
67
|
+
if (!this.isConnected) {
|
|
68
|
+
throw new Error('WebSocket is not connected')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const _message: WSTestMessage = {
|
|
72
|
+
type: typeof data === 'string' ? 'text' : 'binary',
|
|
73
|
+
data,
|
|
74
|
+
timestamp: Date.now(),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.emit('message', { type: 'message', data })
|
|
78
|
+
return this
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Simulate ping
|
|
83
|
+
*/
|
|
84
|
+
ping(data?: Uint8Array): WebSocketTester {
|
|
85
|
+
if (!this.isConnected) {
|
|
86
|
+
throw new Error('WebSocket is not connected')
|
|
87
|
+
}
|
|
88
|
+
this.emit('ping', { type: 'ping', data })
|
|
89
|
+
return this
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Simulate pong
|
|
94
|
+
*/
|
|
95
|
+
pong(data?: Uint8Array): WebSocketTester {
|
|
96
|
+
if (!this.isConnected) {
|
|
97
|
+
throw new Error('WebSocket is not connected')
|
|
98
|
+
}
|
|
99
|
+
this.emit('pong', { type: 'pong', data })
|
|
100
|
+
return this
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Add event listener
|
|
105
|
+
*/
|
|
106
|
+
on(event: string, handler: (...args: any[]) => any): WebSocketTester {
|
|
107
|
+
if (!this.eventHandlers.has(event)) {
|
|
108
|
+
this.eventHandlers.set(event, [])
|
|
109
|
+
}
|
|
110
|
+
this.eventHandlers.get(event)!.push(handler)
|
|
111
|
+
return this
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Remove event listener
|
|
116
|
+
*/
|
|
117
|
+
off(event: string, handler: (...args: any[]) => any): WebSocketTester {
|
|
118
|
+
const handlers = this.eventHandlers.get(event)
|
|
119
|
+
if (handlers) {
|
|
120
|
+
const index = handlers.indexOf(handler)
|
|
121
|
+
if (index > -1) {
|
|
122
|
+
handlers.splice(index, 1)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Emit event
|
|
130
|
+
*/
|
|
131
|
+
private emit(event: string, data: any): void {
|
|
132
|
+
const handlers = this.eventHandlers.get(event) || []
|
|
133
|
+
handlers.forEach(handler => handler(data))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get all sent messages
|
|
138
|
+
*/
|
|
139
|
+
getSentMessages(): WSTestMessage[] {
|
|
140
|
+
return [...this.messages]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get messages of specific type
|
|
145
|
+
*/
|
|
146
|
+
getMessagesByType(type: 'text' | 'binary'): WSTestMessage[] {
|
|
147
|
+
return this.messages.filter(msg => msg.type === type)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Clear message history
|
|
152
|
+
*/
|
|
153
|
+
clearMessages(): WebSocketTester {
|
|
154
|
+
this.messages = []
|
|
155
|
+
return this
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get connection state
|
|
160
|
+
*/
|
|
161
|
+
getState(): { isConnected: boolean, readyState: number } {
|
|
162
|
+
return {
|
|
163
|
+
isConnected: this.isConnected,
|
|
164
|
+
readyState: this.readyState,
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Create a test client interface
|
|
170
|
+
*/
|
|
171
|
+
getTestClient(): WSTestClient {
|
|
172
|
+
return {
|
|
173
|
+
send: (message: string | ArrayBuffer | Uint8Array) => this.send(message),
|
|
174
|
+
close: (code?: number, reason?: string) => this.disconnect(code, reason),
|
|
175
|
+
ping: (data?: Uint8Array) => this.ping(data),
|
|
176
|
+
pong: (data?: Uint8Array) => this.pong(data),
|
|
177
|
+
messages: this.getSentMessages(),
|
|
178
|
+
isConnected: this.isConnected,
|
|
179
|
+
readyState: this.readyState,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Mock ServerWebSocket for testing
|
|
186
|
+
*/
|
|
187
|
+
export class MockServerWebSocket {
|
|
188
|
+
private tester: WebSocketTester
|
|
189
|
+
private _data: any
|
|
190
|
+
|
|
191
|
+
constructor(data: any = {}) {
|
|
192
|
+
this.tester = new WebSocketTester()
|
|
193
|
+
this._data = data
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
send(message: string | ArrayBuffer | Uint8Array): void {
|
|
197
|
+
this.tester.send(message)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
close(code?: number, reason?: string): void {
|
|
201
|
+
this.tester.disconnect(code, reason)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ping(data?: Uint8Array): void {
|
|
205
|
+
this.tester.ping(data)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pong(data?: Uint8Array): void {
|
|
209
|
+
this.tester.pong(data)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
publish(topic: string, message: string | ArrayBuffer | Uint8Array): void {
|
|
213
|
+
// Mock publish functionality
|
|
214
|
+
this.tester.send(message)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
subscribe(_topic: string): void {
|
|
218
|
+
// Mock subscribe functionality
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
unsubscribe(_topic: string): void {
|
|
222
|
+
// Mock unsubscribe functionality
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
isSubscribed(_topic: string): boolean {
|
|
226
|
+
return true // Mock implementation
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
cork(callback: () => void): void {
|
|
230
|
+
callback()
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
get readyState(): number {
|
|
234
|
+
return this.tester.getState().readyState
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get data(): any {
|
|
238
|
+
return this._data
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
set data(value: any) {
|
|
242
|
+
this._data = value
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
getTester(): WebSocketTester {
|
|
246
|
+
return this.tester
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* WebSocket handler testing utilities
|
|
252
|
+
*/
|
|
253
|
+
export const wsHandlerMocks = {
|
|
254
|
+
/**
|
|
255
|
+
* Mock WebSocket open handler
|
|
256
|
+
*/
|
|
257
|
+
onOpen: (): any => mock(async (_ws: ServerWebSocket<any>): Promise<void> => {
|
|
258
|
+
// Mock open handler
|
|
259
|
+
}),
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Mock WebSocket message handler
|
|
263
|
+
*/
|
|
264
|
+
onMessage: (response?: string | ArrayBuffer | Uint8Array): any =>
|
|
265
|
+
mock(async (ws: ServerWebSocket<any>, _message: string | Uint8Array | ArrayBuffer): Promise<void> => {
|
|
266
|
+
if (response) {
|
|
267
|
+
ws.send(response)
|
|
268
|
+
}
|
|
269
|
+
}),
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Mock WebSocket close handler
|
|
273
|
+
*/
|
|
274
|
+
onClose: (): any => mock(async (_ws: ServerWebSocket<any>, _code: number, _reason: string): Promise<void> => {
|
|
275
|
+
// Mock close handler
|
|
276
|
+
}),
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Mock WebSocket error handler
|
|
280
|
+
*/
|
|
281
|
+
onError: (): any => mock(async (_ws: ServerWebSocket<any>, _error: Error): Promise<void> => {
|
|
282
|
+
// Mock error handler
|
|
283
|
+
}),
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Mock echo handler
|
|
287
|
+
*/
|
|
288
|
+
echo: (): any => mock(async (ws: ServerWebSocket<any>, message: string | Uint8Array | ArrayBuffer): Promise<void> => {
|
|
289
|
+
ws.send(message)
|
|
290
|
+
}),
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Mock broadcast handler
|
|
294
|
+
*/
|
|
295
|
+
broadcast: (clients: ServerWebSocket<any>[]): any =>
|
|
296
|
+
mock(async (ws: ServerWebSocket<any>, message: string | Uint8Array | ArrayBuffer): Promise<void> => {
|
|
297
|
+
clients.forEach((client) => {
|
|
298
|
+
if (client !== ws && client.readyState === 1) {
|
|
299
|
+
client.send(message)
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
}),
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Mock chat room handler
|
|
306
|
+
*/
|
|
307
|
+
chatRoom: (room: string): any =>
|
|
308
|
+
mock(async (ws: ServerWebSocket<any>, message: string | Uint8Array | ArrayBuffer): Promise<void> => {
|
|
309
|
+
ws.publish(room, message)
|
|
310
|
+
}),
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* WebSocket test scenarios
|
|
315
|
+
*/
|
|
316
|
+
export const wsTestScenarios = {
|
|
317
|
+
/**
|
|
318
|
+
* Test basic connection and message exchange
|
|
319
|
+
*/
|
|
320
|
+
basicConnection: (): WebSocketTester => {
|
|
321
|
+
return new WebSocketTester()
|
|
322
|
+
.connect()
|
|
323
|
+
.send('Hello WebSocket')
|
|
324
|
+
.receive('Hello Client')
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Test connection failure
|
|
329
|
+
*/
|
|
330
|
+
connectionFailure: (): WebSocketTester => {
|
|
331
|
+
const tester = new WebSocketTester()
|
|
332
|
+
tester.on('error', () => {
|
|
333
|
+
// Handle connection error
|
|
334
|
+
})
|
|
335
|
+
return tester
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Test message broadcasting
|
|
340
|
+
*/
|
|
341
|
+
messageBroadcast: (clientCount: number = 3): WebSocketTester[] => {
|
|
342
|
+
const clients = Array.from({ length: clientCount }, () =>
|
|
343
|
+
new WebSocketTester().connect())
|
|
344
|
+
|
|
345
|
+
// Simulate one client sending a message
|
|
346
|
+
clients[0].send('Broadcast message')
|
|
347
|
+
|
|
348
|
+
// Simulate other clients receiving the message
|
|
349
|
+
clients.slice(1).forEach(client =>
|
|
350
|
+
client.receive('Broadcast message'),
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
return clients
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Test ping/pong mechanism
|
|
358
|
+
*/
|
|
359
|
+
pingPong: (): WebSocketTester => {
|
|
360
|
+
return new WebSocketTester()
|
|
361
|
+
.connect()
|
|
362
|
+
.ping()
|
|
363
|
+
.pong()
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Test connection timeout
|
|
368
|
+
*/
|
|
369
|
+
connectionTimeout: (): WebSocketTester => {
|
|
370
|
+
const tester = new WebSocketTester()
|
|
371
|
+
setTimeout(() => {
|
|
372
|
+
tester.disconnect(1006, 'Connection timeout')
|
|
373
|
+
}, 100)
|
|
374
|
+
return tester
|
|
375
|
+
},
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* WebSocket assertion helpers
|
|
380
|
+
*/
|
|
381
|
+
export const wsAssertions = {
|
|
382
|
+
/**
|
|
383
|
+
* Assert WebSocket is connected
|
|
384
|
+
*/
|
|
385
|
+
isConnected: (tester: WebSocketTester): void => {
|
|
386
|
+
const state = tester.getState()
|
|
387
|
+
if (!state.isConnected) {
|
|
388
|
+
throw new Error('Expected WebSocket to be connected')
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Assert WebSocket is disconnected
|
|
394
|
+
*/
|
|
395
|
+
isDisconnected: (tester: WebSocketTester): void => {
|
|
396
|
+
const state = tester.getState()
|
|
397
|
+
if (state.isConnected) {
|
|
398
|
+
throw new Error('Expected WebSocket to be disconnected')
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Assert message was sent
|
|
404
|
+
*/
|
|
405
|
+
messageSent: (tester: WebSocketTester, expectedMessage: string | ArrayBuffer | Uint8Array): void => {
|
|
406
|
+
const messages = tester.getSentMessages()
|
|
407
|
+
const found = messages.some((msg) => {
|
|
408
|
+
if (typeof expectedMessage === 'string' && typeof msg.data === 'string') {
|
|
409
|
+
return msg.data === expectedMessage
|
|
410
|
+
}
|
|
411
|
+
return msg.data === expectedMessage
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
if (!found) {
|
|
415
|
+
throw new Error(`Expected message not found in sent messages`)
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Assert number of messages sent
|
|
421
|
+
*/
|
|
422
|
+
messageCount: (tester: WebSocketTester, expectedCount: number): void => {
|
|
423
|
+
const messages = tester.getSentMessages()
|
|
424
|
+
if (messages.length !== expectedCount) {
|
|
425
|
+
throw new Error(`Expected ${expectedCount} messages, but got ${messages.length}`)
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Assert message type
|
|
431
|
+
*/
|
|
432
|
+
messageType: (tester: WebSocketTester, index: number, expectedType: 'text' | 'binary'): void => {
|
|
433
|
+
const messages = tester.getSentMessages()
|
|
434
|
+
if (index >= messages.length) {
|
|
435
|
+
throw new Error(`Message at index ${index} does not exist`)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (messages[index].type !== expectedType) {
|
|
439
|
+
throw new Error(`Expected message type '${expectedType}', got '${messages[index].type}'`)
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Assert ready state
|
|
445
|
+
*/
|
|
446
|
+
readyState: (tester: WebSocketTester, expectedState: number): void => {
|
|
447
|
+
const state = tester.getState()
|
|
448
|
+
if (state.readyState !== expectedState) {
|
|
449
|
+
throw new Error(`Expected ready state ${expectedState}, got ${state.readyState}`)
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* WebSocket performance testing
|
|
456
|
+
*/
|
|
457
|
+
export const wsPerformance = {
|
|
458
|
+
/**
|
|
459
|
+
* Test message throughput
|
|
460
|
+
*/
|
|
461
|
+
testThroughput: async (
|
|
462
|
+
messageCount: number = 1000,
|
|
463
|
+
messageSize: number = 1024,
|
|
464
|
+
): Promise<{
|
|
465
|
+
messagesPerSecond: number
|
|
466
|
+
totalTime: number
|
|
467
|
+
averageLatency: number
|
|
468
|
+
}> => {
|
|
469
|
+
const tester = new WebSocketTester().connect()
|
|
470
|
+
const message = 'x'.repeat(messageSize)
|
|
471
|
+
|
|
472
|
+
const startTime = performance.now()
|
|
473
|
+
|
|
474
|
+
for (let i = 0; i < messageCount; i++) {
|
|
475
|
+
tester.send(message)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const endTime = performance.now()
|
|
479
|
+
const totalTime = endTime - startTime
|
|
480
|
+
const messagesPerSecond = (messageCount / totalTime) * 1000
|
|
481
|
+
const averageLatency = totalTime / messageCount
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
messagesPerSecond,
|
|
485
|
+
totalTime,
|
|
486
|
+
averageLatency,
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Test concurrent connections
|
|
492
|
+
*/
|
|
493
|
+
testConcurrentConnections: async (
|
|
494
|
+
connectionCount: number = 100,
|
|
495
|
+
): Promise<{
|
|
496
|
+
successfulConnections: number
|
|
497
|
+
failedConnections: number
|
|
498
|
+
averageConnectionTime: number
|
|
499
|
+
}> => {
|
|
500
|
+
const results = {
|
|
501
|
+
successfulConnections: 0,
|
|
502
|
+
failedConnections: 0,
|
|
503
|
+
averageConnectionTime: 0,
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const connectionTimes: number[] = []
|
|
507
|
+
|
|
508
|
+
const promises = Array.from({ length: connectionCount }, async () => {
|
|
509
|
+
const startTime = performance.now()
|
|
510
|
+
try {
|
|
511
|
+
const tester = new WebSocketTester()
|
|
512
|
+
tester.connect()
|
|
513
|
+
const endTime = performance.now()
|
|
514
|
+
connectionTimes.push(endTime - startTime)
|
|
515
|
+
results.successfulConnections++
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
console.error('WebSocket connection failed:', error)
|
|
519
|
+
results.failedConnections++
|
|
520
|
+
}
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
await Promise.all(promises)
|
|
524
|
+
|
|
525
|
+
results.averageConnectionTime = connectionTimes.length > 0
|
|
526
|
+
? connectionTimes.reduce((sum, time) => sum + time, 0) / connectionTimes.length
|
|
527
|
+
: 0
|
|
528
|
+
|
|
529
|
+
return results
|
|
530
|
+
},
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Factory functions
|
|
535
|
+
*/
|
|
536
|
+
export function createWebSocketTester(): WebSocketTester {
|
|
537
|
+
return new WebSocketTester()
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function createMockServerWebSocket(data?: any): MockServerWebSocket {
|
|
541
|
+
return new MockServerWebSocket(data)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* WebSocket test utilities
|
|
546
|
+
*/
|
|
547
|
+
export const wsTestUtils = {
|
|
548
|
+
/**
|
|
549
|
+
* Create multiple connected clients
|
|
550
|
+
*/
|
|
551
|
+
createClients: (count: number): WebSocketTester[] => {
|
|
552
|
+
return Array.from({ length: count }, () =>
|
|
553
|
+
new WebSocketTester().connect())
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Simulate network latency
|
|
558
|
+
*/
|
|
559
|
+
withLatency: (tester: WebSocketTester, latencyMs: number): WebSocketTester => {
|
|
560
|
+
const originalSend = tester.send.bind(tester)
|
|
561
|
+
tester.send = (data: string | ArrayBuffer | Uint8Array) => {
|
|
562
|
+
setTimeout(() => originalSend(data), latencyMs)
|
|
563
|
+
return tester
|
|
564
|
+
}
|
|
565
|
+
return tester
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Simulate packet loss
|
|
570
|
+
*/
|
|
571
|
+
withPacketLoss: (tester: WebSocketTester, lossRate: number): WebSocketTester => {
|
|
572
|
+
const originalSend = tester.send.bind(tester)
|
|
573
|
+
tester.send = (data: string | ArrayBuffer | Uint8Array) => {
|
|
574
|
+
if (Math.random() > lossRate) {
|
|
575
|
+
originalSend(data)
|
|
576
|
+
}
|
|
577
|
+
return tester
|
|
578
|
+
}
|
|
579
|
+
return tester
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Create message generator
|
|
584
|
+
*/
|
|
585
|
+
* messageGenerator(count: number, prefix: string = 'Message'): Generator<string> {
|
|
586
|
+
for (let i = 1; i <= count; i++) {
|
|
587
|
+
yield `${prefix} ${i}`
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
}
|