@@ -146,4 +146,125 @@ describe("promisifiedHandler", () => {
146146
147147 expect ( result ) . toEqual ( { statusCode : 200 , body : "Sync response" } ) ;
148148 } ) ;
149+
150+ it ( "waits for callback when handler returns non-promise artifact with callback parameter" , async ( ) => {
151+ // Simulates aws-serverless-express pattern where a server instance is returned
152+ // but the actual response comes through the callback
153+ const serverArtifact = { type : "server-instance" , listen : ( ) => { } } ;
154+ const handler : Handler = ( event , context , callback ) => {
155+ // Simulate async processing that eventually calls callback
156+ setTimeout ( ( ) => {
157+ callback ( null , { statusCode : 200 , body : "Actual response from callback" } ) ;
158+ } , 10 ) ;
159+ return serverArtifact as unknown as void ;
160+ } ;
161+
162+ const promHandler = promisifiedHandler ( handler ) as any ;
163+
164+ const result = await promHandler ( { } , mockContext ) ;
165+
166+ // Should return the callback result, not the server artifact
167+ expect ( result ) . toEqual ( { statusCode : 200 , body : "Actual response from callback" } ) ;
168+ expect ( result ) . not . toBe ( serverArtifact ) ;
169+ } ) ;
170+
171+ it ( "detects http.Server-like artifact (has listen AND close)" , async ( ) => {
172+ // Detection method 1: Node.js http.Server or similar (has both listen and close)
173+ const serverArtifact = {
174+ listen : ( ) => { } ,
175+ close : ( ) => { } ,
176+ _handle : { } ,
177+ } ;
178+ const handler = ( event : any , context : Context ) => {
179+ setTimeout ( ( ) => {
180+ context . done ( undefined , { statusCode : 200 , body : "Response from context.done" } ) ;
181+ } , 10 ) ;
182+ return serverArtifact ;
183+ } ;
184+
185+ const promHandler = promisifiedHandler ( handler as any ) as any ;
186+ const result = await promHandler ( { } , mockContext ) ;
187+
188+ expect ( result ) . toEqual ( { statusCode : 200 , body : "Response from context.done" } ) ;
189+ expect ( result ) . not . toBe ( serverArtifact ) ;
190+ } ) ;
191+
192+ it ( "detects EventEmitter-like artifact (has on AND emit)" , async ( ) => {
193+ // Detection method 2: EventEmitter-like (has .on and .emit)
194+ const emitterArtifact = {
195+ on : ( ) => { } ,
196+ emit : ( ) => { } ,
197+ listeners : [ ] ,
198+ } ;
199+ const handler = ( event : any , context : Context ) => {
200+ setTimeout ( ( ) => {
201+ context . succeed ( { statusCode : 200 , body : "EventEmitter response" } ) ;
202+ } , 10 ) ;
203+ return emitterArtifact ;
204+ } ;
205+
206+ const promHandler = promisifiedHandler ( handler as any ) as any ;
207+ const result = await promHandler ( { } , mockContext ) ;
208+
209+ expect ( result ) . toEqual ( { statusCode : 200 , body : "EventEmitter response" } ) ;
210+ expect ( result ) . not . toBe ( emitterArtifact ) ;
211+ } ) ;
212+
213+ it ( "detects EventEmitter instance" , async ( ) => {
214+ // Detection method 3: Instance of EventEmitter (covers Server, Socket, etc.)
215+ const { EventEmitter } = require ( "events" ) ;
216+ const artifact = new EventEmitter ( ) ;
217+
218+ const handler = ( event : any , context : Context ) => {
219+ setTimeout ( ( ) => {
220+ context . succeed ( { statusCode : 200 , body : "From EventEmitter instance" } ) ;
221+ } , 10 ) ;
222+ return artifact ;
223+ } ;
224+
225+ const promHandler = promisifiedHandler ( handler as any ) as any ;
226+ const result = await promHandler ( { } , mockContext ) ;
227+
228+ expect ( result ) . toEqual ( { statusCode : 200 , body : "From EventEmitter instance" } ) ;
229+ expect ( result ) . not . toBe ( artifact ) ;
230+ } ) ;
231+
232+ it ( "detects artifact by constructor name (Server/Socket/Emitter)" , async ( ) => {
233+ // Detection method 4: Constructor name matches /Server|Socket|Emitter/i
234+ class CustomServer {
235+ public port = 3000 ;
236+ public start ( ) {
237+ return "started" ;
238+ }
239+ }
240+ const artifact = new CustomServer ( ) ;
241+
242+ const handler = ( event : any , context : Context ) => {
243+ setTimeout ( ( ) => {
244+ context . succeed ( { statusCode : 200 , body : "From CustomServer" } ) ;
245+ } , 10 ) ;
246+ return artifact ;
247+ } ;
248+
249+ const promHandler = promisifiedHandler ( handler as any ) as any ;
250+ const result = await promHandler ( { } , mockContext ) ;
251+
252+ expect ( result ) . toEqual ( { statusCode : 200 , body : "From CustomServer" } ) ;
253+ expect ( result ) . not . toBe ( artifact ) ;
254+ } ) ;
255+
256+ it ( "does NOT treat plain response objects as artifacts" , async ( ) => {
257+ // Plain objects that happen to have some function properties should still
258+ // be treated as artifacts to be safe, but objects without functions are not artifacts
259+ const handler = ( event : any , context : Context ) => {
260+ // This is a legitimate Lambda response
261+ return { statusCode : 200 , body : "Plain response" , headers : { "Content-Type" : "text/plain" } } ;
262+ } ;
263+
264+ const promHandler = promisifiedHandler ( handler as any ) as any ;
265+ const result = await promHandler ( { } , mockContext ) ;
266+
267+ // Should return immediately with the response object
268+ expect ( result ) . toEqual ( { statusCode : 200 , body : "Plain response" , headers : { "Content-Type" : "text/plain" } } ) ;
269+ } ) ;
149270} ) ;
0 commit comments