@@ -99,4 +99,92 @@ describe("Http/App", () => {
9999 foo : "baz"
100100 } )
101101 } )
102+
103+ describe ( "fromWebHandler" , ( ) => {
104+ test ( "basic GET request" , async ( ) => {
105+ const webHandler = async ( request : Request ) => {
106+ return new Response ( `Hello from ${ request . url } ` , {
107+ status : 200 ,
108+ headers : { "Content-Type" : "text/plain" }
109+ } )
110+ }
111+ const app = HttpApp . fromWebHandler ( webHandler )
112+ const handler = HttpApp . toWebHandler ( app )
113+ const response = await handler ( new Request ( "http://localhost:3000/hello" ) )
114+ strictEqual ( response . status , 200 )
115+ strictEqual ( await response . text ( ) , "Hello from http://localhost:3000/hello" )
116+ } )
117+
118+ test ( "POST with JSON body" , async ( ) => {
119+ const webHandler = async ( request : Request ) => {
120+ const body = await request . json ( )
121+ return Response . json ( { received : body } )
122+ }
123+ const app = HttpApp . fromWebHandler ( webHandler )
124+ const handler = HttpApp . toWebHandler ( app )
125+ const response = await handler (
126+ new Request ( "http://localhost:3000/" , {
127+ method : "POST" ,
128+ body : JSON . stringify ( { message : "hello" } ) ,
129+ headers : { "Content-Type" : "application/json" }
130+ } )
131+ )
132+ deepStrictEqual ( await response . json ( ) , {
133+ received : { message : "hello" }
134+ } )
135+ } )
136+
137+ test ( "preserves request headers" , async ( ) => {
138+ const webHandler = async ( request : Request ) => {
139+ return Response . json ( {
140+ authorization : request . headers . get ( "Authorization" ) ,
141+ custom : request . headers . get ( "X-Custom-Header" )
142+ } )
143+ }
144+ const app = HttpApp . fromWebHandler ( webHandler )
145+ const handler = HttpApp . toWebHandler ( app )
146+ const response = await handler (
147+ new Request ( "http://localhost:3000/" , {
148+ headers : {
149+ "Authorization" : "Bearer token123" ,
150+ "X-Custom-Header" : "custom-value"
151+ }
152+ } )
153+ )
154+ deepStrictEqual ( await response . json ( ) , {
155+ authorization : "Bearer token123" ,
156+ custom : "custom-value"
157+ } )
158+ } )
159+
160+ test ( "preserves response status and headers" , async ( ) => {
161+ const webHandler = async ( _request : Request ) => {
162+ return new Response ( "Not Found" , {
163+ status : 404 ,
164+ statusText : "Not Found" ,
165+ headers : {
166+ "X-Error-Code" : "RESOURCE_NOT_FOUND" ,
167+ "Content-Type" : "text/plain"
168+ }
169+ } )
170+ }
171+ const app = HttpApp . fromWebHandler ( webHandler )
172+ const handler = HttpApp . toWebHandler ( app )
173+ const response = await handler ( new Request ( "http://localhost:3000/missing" ) )
174+ strictEqual ( response . status , 404 )
175+ strictEqual ( response . headers . get ( "X-Error-Code" ) , "RESOURCE_NOT_FOUND" )
176+ strictEqual ( await response . text ( ) , "Not Found" )
177+ } )
178+
179+ test ( "round-trip with toWebHandler" , async ( ) => {
180+ // Create an Effect app, convert to web handler, then back to Effect app
181+ const originalApp = HttpServerResponse . json ( { source : "effect" } )
182+ const webHandler = HttpApp . toWebHandler ( originalApp )
183+ const wrappedApp = HttpApp . fromWebHandler ( webHandler )
184+ const finalHandler = HttpApp . toWebHandler ( wrappedApp )
185+
186+ const response = await finalHandler ( new Request ( "http://localhost:3000/" ) )
187+ deepStrictEqual ( await response . json ( ) , { source : "effect" } )
188+ } )
189+ } )
102190} )
0 commit comments