@@ -107,6 +107,179 @@ describe('WebSocketFactory', () => {
107107 } )
108108 } )
109109
110+ describe ( 'Edge Runtime compatibility - dynamic property access' , ( ) => {
111+ // These tests verify that we use dynamic property access to avoid
112+ // Next.js Edge Runtime static analysis warnings
113+
114+ const originalProcess = global . process
115+
116+ afterEach ( ( ) => {
117+ global . process = originalProcess
118+ } )
119+
120+ test ( 'should handle undefined process.versions' , ( ) => {
121+ // Process exists but versions is undefined
122+ global . process = { } as any
123+ Object . defineProperty ( global . process , 'versions' , {
124+ value : undefined ,
125+ configurable : true ,
126+ } )
127+ delete global . WebSocket
128+ delete ( globalThis as any ) . WebSocket
129+
130+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
131+ expect ( env . type ) . toBe ( 'unsupported' )
132+ expect ( env . error ) . toContain ( 'Unknown JavaScript runtime' )
133+ } )
134+
135+ test ( 'should handle null process.versions' , ( ) => {
136+ // Process exists but versions is null
137+ global . process = { } as any
138+ Object . defineProperty ( global . process , 'versions' , {
139+ value : null ,
140+ configurable : true ,
141+ } )
142+ delete global . WebSocket
143+ delete ( globalThis as any ) . WebSocket
144+
145+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
146+ expect ( env . type ) . toBe ( 'unsupported' )
147+ expect ( env . error ) . toContain ( 'Unknown JavaScript runtime' )
148+ } )
149+
150+ test ( 'should handle process.versions.node being undefined' , ( ) => {
151+ global . process = { versions : { } } as any
152+ delete global . WebSocket
153+ delete ( globalThis as any ) . WebSocket
154+
155+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
156+ expect ( env . type ) . toBe ( 'unsupported' )
157+ expect ( env . error ) . toContain ( 'Unknown JavaScript runtime' )
158+ } )
159+
160+ test ( 'should handle process.versions.node being null' , ( ) => {
161+ global . process = { versions : { node : null } } as any
162+ delete global . WebSocket
163+ delete ( globalThis as any ) . WebSocket
164+
165+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
166+ expect ( env . type ) . toBe ( 'unsupported' )
167+ expect ( env . error ) . toContain ( 'Unknown JavaScript runtime' )
168+ } )
169+
170+ test ( 'should handle invalid Node.js version string' , ( ) => {
171+ global . process = { versions : { node : 'invalid-version' } } as any
172+ delete global . WebSocket
173+ delete ( globalThis as any ) . WebSocket
174+
175+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
176+ expect ( env . type ) . toBe ( 'unsupported' )
177+ // NaN from parseInt('invalid') makes nodeVersion < 22 true
178+ expect ( env . error ) . toContain ( 'detected without native WebSocket support' )
179+ } )
180+
181+ test ( 'should handle Node.js version without v prefix' , ( ) => {
182+ global . process = { versions : { node : '18.0.0' } } as any
183+ delete global . WebSocket
184+ delete ( globalThis as any ) . WebSocket
185+
186+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
187+ expect ( env . type ) . toBe ( 'unsupported' )
188+ expect ( env . error ) . toContain (
189+ 'Node.js 18 detected without native WebSocket support'
190+ )
191+ } )
192+
193+ test ( 'should correctly detect Node.js 16' , ( ) => {
194+ global . process = { versions : { node : 'v16.14.0' } } as any
195+ delete global . WebSocket
196+ delete ( globalThis as any ) . WebSocket
197+
198+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
199+ expect ( env . type ) . toBe ( 'unsupported' )
200+ expect ( env . error ) . toContain (
201+ 'Node.js 16 detected without native WebSocket support'
202+ )
203+ expect ( env . workaround ) . toContain ( 'ws' )
204+ } )
205+
206+ test ( 'should correctly detect Node.js 18' , ( ) => {
207+ global . process = { versions : { node : 'v18.0.0' } } as any
208+ delete global . WebSocket
209+ delete ( globalThis as any ) . WebSocket
210+
211+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
212+ expect ( env . type ) . toBe ( 'unsupported' )
213+ expect ( env . error ) . toContain (
214+ 'Node.js 18 detected without native WebSocket support'
215+ )
216+ expect ( env . workaround ) . toContain ( 'ws' )
217+ } )
218+
219+ test ( 'should correctly detect Node.js 20' , ( ) => {
220+ global . process = { versions : { node : 'v20.0.0' } } as any
221+ delete global . WebSocket
222+ delete ( globalThis as any ) . WebSocket
223+
224+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
225+ expect ( env . type ) . toBe ( 'unsupported' )
226+ expect ( env . error ) . toContain (
227+ 'Node.js 20 detected without native WebSocket support'
228+ )
229+ expect ( env . workaround ) . toContain ( 'ws' )
230+ } )
231+
232+ test ( 'should correctly detect Node.js 22 without WebSocket' , ( ) => {
233+ global . process = { versions : { node : 'v22.0.0' } } as any
234+ delete global . WebSocket
235+ delete ( globalThis as any ) . WebSocket
236+
237+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
238+ expect ( env . type ) . toBe ( 'unsupported' )
239+ expect ( env . error ) . toContain (
240+ 'Node.js 22 detected but native WebSocket not found'
241+ )
242+ expect ( env . workaround ) . toContain (
243+ 'Provide a WebSocket implementation via the transport option'
244+ )
245+ } )
246+
247+ test ( 'should correctly detect Node.js 22 with WebSocket' , ( ) => {
248+ global . process = { versions : { node : 'v22.0.0' } } as any
249+ delete global . WebSocket
250+ ; ( globalThis as any ) . WebSocket = MockWebSocket
251+
252+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
253+ expect ( env . type ) . toBe ( 'native' )
254+ expect ( env . constructor ) . toBe ( MockWebSocket )
255+
256+ delete ( globalThis as any ) . WebSocket
257+ } )
258+
259+ test ( 'ensures process.versions access uses bracket notation' , ( ) => {
260+ // This test verifies that our implementation doesn't directly access process.versions
261+ // which would trigger Next.js Edge Runtime warnings.
262+ // The actual verification happens through static analysis, but we can test the behavior.
263+
264+ const processProxy = new Proxy ( { } as any , {
265+ get ( target , prop ) {
266+ if ( prop === 'versions' ) {
267+ return { node : 'v18.0.0' }
268+ }
269+ return undefined
270+ } ,
271+ } )
272+
273+ global . process = processProxy
274+ delete global . WebSocket
275+ delete ( globalThis as any ) . WebSocket
276+
277+ const env = ( WebSocketFactory as any ) . detectEnvironment ( )
278+ expect ( env . type ) . toBe ( 'unsupported' )
279+ expect ( env . error ) . toContain ( 'Node.js 18' )
280+ } )
281+ } )
282+
110283 describe ( 'Node.js environment' , ( ) => {
111284 beforeEach ( ( ) => {
112285 delete global . WebSocket
0 commit comments