11// Gateway Smoke tests cover gateway smoke script behavior.
2- import { describe , expect , it } from "vitest" ;
2+ import { createServer , type Server } from "node:http" ;
3+ import { afterEach , describe , expect , it } from "vitest" ;
4+ import { WebSocket , WebSocketServer } from "ws" ;
35import { runGatewaySmoke } from "../../scripts/dev/gateway-smoke.js" ;
46
7+ let server : Server | undefined ;
8+ let wss : WebSocketServer | undefined ;
9+
10+ afterEach ( async ( ) => {
11+ await new Promise < void > ( ( resolve ) => {
12+ wss ?. close ( ( ) => resolve ( ) ) ;
13+ if ( ! wss ) {
14+ resolve ( ) ;
15+ }
16+ } ) ;
17+ wss = undefined ;
18+
19+ await new Promise < void > ( ( resolve , reject ) => {
20+ server ?. close ( ( error ) => {
21+ if ( error ) {
22+ reject ( error ) ;
23+ return ;
24+ }
25+ resolve ( ) ;
26+ } ) ;
27+ if ( ! server ) {
28+ resolve ( ) ;
29+ }
30+ } ) ;
31+ server = undefined ;
32+ } ) ;
33+
534describe ( "gateway-smoke" , ( ) => {
635 function healthResponse ( ) {
736 return {
@@ -19,6 +48,58 @@ describe("gateway-smoke", () => {
1948 } ;
2049 }
2150
51+ async function listenGatewaySmokeServer ( ) {
52+ const requests : Array < { method : string ; params ?: unknown ; timeout ?: number } > = [ ] ;
53+ server = createServer ( ) ;
54+ wss = new WebSocketServer ( { server } ) ;
55+ wss . on ( "connection" , ( ws : WebSocket ) => {
56+ ws . on ( "message" , ( data ) => {
57+ const frame = JSON . parse ( data . toString ( ) ) as {
58+ id : string ;
59+ method : string ;
60+ params ?: unknown ;
61+ type : string ;
62+ } ;
63+ requests . push ( { method : frame . method , params : frame . params } ) ;
64+ if ( frame . method === "connect" ) {
65+ ws . send ( JSON . stringify ( { id : frame . id , ok : true , payload : { } , type : "res" } ) ) ;
66+ return ;
67+ }
68+ if ( frame . method === "health" ) {
69+ ws . send ( JSON . stringify ( { id : frame . id , type : "res" , ...healthResponse ( ) } ) ) ;
70+ return ;
71+ }
72+ if ( frame . method === "chat.history" ) {
73+ ws . send (
74+ JSON . stringify ( {
75+ id : frame . id ,
76+ ok : true ,
77+ payload : { messages : [ ] } ,
78+ type : "res" ,
79+ } ) ,
80+ ) ;
81+ return ;
82+ }
83+ ws . send (
84+ JSON . stringify ( {
85+ error : `unexpected method ${ frame . method } ` ,
86+ id : frame . id ,
87+ ok : false ,
88+ type : "res" ,
89+ } ) ,
90+ ) ;
91+ } ) ;
92+ } ) ;
93+ await new Promise < void > ( ( resolve ) => {
94+ server ?. listen ( 0 , "127.0.0.1" , resolve ) ;
95+ } ) ;
96+ const address = server . address ( ) ;
97+ if ( ! address || typeof address === "string" ) {
98+ throw new Error ( "test gateway smoke server did not get a TCP address" ) ;
99+ }
100+ return { requests, url : `ws://127.0.0.1:${ address . port } ` } ;
101+ }
102+
22103 function createSmokeDeps (
23104 responses : Record < string , { error ?: string ; ok : boolean } & Record < string , unknown > > ,
24105 calls : Array < { method : string ; timeout ?: number } > = [ ] ,
@@ -63,6 +144,40 @@ describe("gateway-smoke", () => {
63144 } ;
64145 }
65146
147+ it ( "passes against a loopback gateway websocket using the real client" , async ( ) => {
148+ const stdout : string [ ] = [ ] ;
149+ const stderr : string [ ] = [ ] ;
150+ const loopback = await listenGatewaySmokeServer ( ) ;
151+
152+ const code = await runGatewaySmoke (
153+ { token : "secret-token" , urlRaw : loopback . url } ,
154+ {
155+ stderr : ( message ) => {
156+ stderr . push ( message ) ;
157+ } ,
158+ stdout : ( message ) => {
159+ stdout . push ( message ) ;
160+ } ,
161+ } ,
162+ ) ;
163+
164+ expect ( code ) . toBe ( 0 ) ;
165+ expect ( loopback . requests . map ( ( request ) => request . method ) ) . toEqual ( [
166+ "connect" ,
167+ "health" ,
168+ "chat.history" ,
169+ ] ) ;
170+ expect ( loopback . requests [ 0 ] ?. params ) . toMatchObject ( {
171+ auth : { token : "secret-token" } ,
172+ client : { id : "openclaw-ios" } ,
173+ role : "operator" ,
174+ scopes : [ "operator.read" , "operator.write" , "operator.admin" ] ,
175+ } ) ;
176+ expect ( loopback . requests [ 2 ] ?. params ) . toEqual ( { sessionKey : "main" } ) ;
177+ expect ( stdout ) . toEqual ( [ "ok: connected + health + chat.history" ] ) ;
178+ expect ( stderr ) . toEqual ( [ ] ) ;
179+ } ) ;
180+
66181 it ( "closes the websocket client when connect fails" , async ( ) => {
67182 const stderr : string [ ] = [ ] ;
68183 const methods : string [ ] = [ ] ;
0 commit comments