@@ -764,7 +764,7 @@ describe("onCallHandler", () => {
764764 "application/json" ,
765765 { } ,
766766 { accept : "text/event-stream" }
767- ) as any ;
767+ ) ;
768768 const fn = https . onCallHandler (
769769 {
770770 cors : { origin : true , methods : "POST" } ,
@@ -776,7 +776,7 @@ describe("onCallHandler", () => {
776776 "gcfv2"
777777 ) ;
778778
779- const resp = await runHandler ( fn , mockReq ) ;
779+ const resp = await runHandler ( fn , mockReq as any ) ;
780780 const data = [ `data: {"message":"hello"}` , `data: {"result":"world"}` ] ;
781781 expect ( resp . body ) . to . equal ( [ ...data , "" ] . join ( "\n" ) ) ;
782782 } ) ;
@@ -787,7 +787,7 @@ describe("onCallHandler", () => {
787787 "application/json" ,
788788 { } ,
789789 { accept : "text/event-stream" }
790- ) as any ;
790+ ) ;
791791 const fn = https . onCallHandler (
792792 {
793793 cors : { origin : true , methods : "POST" } ,
@@ -798,10 +798,75 @@ describe("onCallHandler", () => {
798798 "gcfv2"
799799 ) ;
800800
801- const resp = await runHandler ( fn , mockReq ) ;
801+ const resp = await runHandler ( fn , mockReq as any ) ;
802802 const data = [ `data: {"error":{"message":"INTERNAL","status":"INTERNAL"}}` ] ;
803803 expect ( resp . body ) . to . equal ( [ ...data , "" ] . join ( "\n" ) ) ;
804804 } ) ;
805+
806+ describe ( "Heartbeats" , ( ) => {
807+ let clock : sinon . SinonFakeTimers ;
808+
809+ beforeEach ( ( ) => {
810+ clock = sinon . useFakeTimers ( ) ;
811+ } ) ;
812+
813+ afterEach ( ( ) => {
814+ clock . restore ( ) ;
815+ } ) ;
816+
817+ it ( "sends heartbeat messages at specified interval" , async ( ) => {
818+ const mockReq = mockRequest (
819+ { message : "test heartbeat" } ,
820+ "application/json" ,
821+ { } ,
822+ { accept : "text/event-stream" }
823+ ) ;
824+
825+ const fn = https . onCallHandler (
826+ {
827+ cors : { origin : true , methods : "POST" } ,
828+ heartbeatSeconds : 5
829+ } ,
830+ async ( ) => {
831+ // Simulate long-running operation
832+ await new Promise ( resolve => setTimeout ( resolve , 11_000 ) ) ;
833+ return "done" ;
834+ } ,
835+ "gcfv2"
836+ ) ;
837+
838+ const handlerPromise = runHandler ( fn , mockReq as any ) ;
839+ clock . tick ( 11_000 ) ;
840+ const resp = await handlerPromise ;
841+ expect ( resp . body ) . to . include ( ': ping\n: ping\ndata: {"result":"done"}' ) ;
842+ } ) ;
843+
844+ it ( "respects null heartbeatSeconds option" , async ( ) => {
845+ const mockReq = mockRequest (
846+ { message : "test no heartbeat" } ,
847+ "application/json" ,
848+ { } ,
849+ { accept : "text/event-stream" }
850+ ) ;
851+
852+ const fn = https . onCallHandler (
853+ {
854+ cors : { origin : true , methods : "POST" } ,
855+ heartbeatSeconds : null
856+ } ,
857+ async ( ) => {
858+ await new Promise ( resolve => setTimeout ( resolve , 31_000 ) ) ;
859+ return "done" ;
860+ } ,
861+ "gcfv2"
862+ ) ;
863+
864+ const handlerPromise = runHandler ( fn , mockReq as any ) ;
865+ clock . tick ( 31_000 ) ;
866+ const resp = await handlerPromise ;
867+ expect ( resp . body ) . to . include ( 'data: {"result":"done"}' ) ;
868+ } ) ;
869+ } ) ;
805870 } ) ;
806871} ) ;
807872
0 commit comments