@@ -83,6 +83,61 @@ describe('InvalidParams', () => {
8383 } ) ;
8484} ) ;
8585
86+ describe ( 'MethodCallTimeout' , ( ) => {
87+ it ( 'constructs objects which are instances of MethodCallTimeout' , ( ) => {
88+ const obj = new peer . MethodCallTimeout ( 'foo' ) ;
89+ expect ( obj ) . toBeInstanceOf ( Error ) ;
90+ expect ( obj ) . toBeInstanceOf ( peer . MethodCallError ) ;
91+ expect ( obj ) . toBeInstanceOf ( peer . MethodCallTimeout ) ;
92+ } ) ;
93+
94+ it ( 'sets the message and method' , ( ) => {
95+ const method = 'some.method.name' ;
96+ expect ( new peer . MethodCallTimeout ( method ) ) . toMatchObject ( {
97+ method,
98+ message : `No response received for RPC call to '${ method } '` ,
99+ } ) ;
100+ } ) ;
101+ } ) ;
102+
103+ describe ( 'RPCStreamClosed' , ( ) => {
104+ it ( 'constructs objects which are instances of RPCStreamClosed' , ( ) => {
105+ const obj = new peer . RPCStreamClosed ( 'foo' ) ;
106+ expect ( obj ) . toBeInstanceOf ( Error ) ;
107+ expect ( obj ) . toBeInstanceOf ( peer . MethodCallError ) ;
108+ expect ( obj ) . toBeInstanceOf ( peer . RPCStreamClosed ) ;
109+ } ) ;
110+
111+ it ( 'sets the error message and method' , ( ) => {
112+ const method = 'some.method.name' ;
113+ expect ( new peer . RPCStreamClosed ( method ) ) . toMatchObject ( {
114+ method,
115+ message : `RPC call to '${ method } ' could not be completed as the RPC stream is closed` ,
116+ } ) ;
117+ } ) ;
118+ } ) ;
119+
120+ describe ( 'UnexpectedResponse' , ( ) => {
121+ it ( 'constructs objects which are instances of UnexpectedResponse' , ( ) => {
122+ const obj = new peer . UnexpectedResponse ( 0 ) ;
123+ expect ( obj ) . toBeInstanceOf ( Error ) ;
124+ expect ( obj ) . toBeInstanceOf ( peer . UnexpectedResponse ) ;
125+ } ) ;
126+
127+ it ( 'sets the error message, kind and id' , ( ) => {
128+ expect ( new peer . UnexpectedResponse ( 'eye dee' , 'error' ) ) . toMatchObject ( {
129+ id : 'eye dee' ,
130+ kind : 'error' ,
131+ // tslint:disable-next-line:max-line-length
132+ message : 'Received error with id \'"eye dee"\', which does not correspond to any outstanding RPC call' ,
133+ } ) ;
134+ } ) ;
135+
136+ it ( 'defaults to kind "response"' , ( ) => {
137+ expect ( new peer . UnexpectedResponse ( 0 ) ) . toHaveProperty ( 'kind' , 'response' ) ;
138+ } ) ;
139+ } ) ;
140+
86141describe ( 'numeric request id iterator' , ( ) => {
87142 it ( 'does not repeat values' , ( ) => {
88143 // Not quite true; values will repeat when it wraps around.
@@ -145,9 +200,14 @@ describe('Peer', () => {
145200 } ) ;
146201 } ) ;
147202
148- it ( 'handles an unexpected response by emitting an error' , ( done ) => {
203+ it ( 'handles an unexpected response by emitting an UnexpectedResponse error' , ( done ) => {
149204 uut . once ( 'error' , ( err : Error ) => {
150- expect ( err . message ) . toMatch ( / R e c e i v e d r e s p o n s e w i t h i d ' 5 5 ' / ) ;
205+ expect ( err ) . toMatchObject ( {
206+ message : expect . stringContaining ( "Received response with id \'55\'" ) ,
207+ kind : 'response' ,
208+ id : 55 ,
209+ } ) ;
210+ expect ( err ) . toBeInstanceOf ( peer . UnexpectedResponse ) ;
151211 done ( ) ;
152212 } ) ;
153213 uut . write ( jrpc . response ( 55 ) ) ;
@@ -168,11 +228,16 @@ describe('Peer', () => {
168228 } ) ;
169229
170230 it (
171- 'handles an error with an id not matching any outstanding request ' +
172- 'by emitting an error' ,
231+ // tslint:disable-next-line:max-line-length
232+ 'handles an error with an id not matching any outstanding request by emitting an UnexpectedResponse error' ,
173233 ( done ) => {
174234 uut . once ( 'error' , ( err : Error ) => {
175- expect ( err . message ) . toMatch ( / R e c e i v e d e r r o r w i t h i d ' y e l l o w ' / ) ;
235+ expect ( err ) . toMatchObject ( {
236+ message : expect . stringContaining ( 'Received error with id \'"yellow"\'' ) ,
237+ kind : 'error' ,
238+ id : 'yellow' ,
239+ } ) ;
240+ expect ( err ) . toBeInstanceOf ( peer . UnexpectedResponse ) ;
176241 done ( ) ;
177242 } ) ;
178243 uut . write ( jrpc . error ( { id : 'yellow' , message : '' , code : 1 } ) ) ;
@@ -361,6 +426,26 @@ describe('Peer', () => {
361426 uut . write ( jrpc . request ( 'foo' , '' , [ 5 , 4 , 3 ] ) ) ;
362427 } ) ;
363428
429+ it ( 'sends a response after the Writable side is closed' , ( done ) => {
430+ uut . onRequest = ( ) => {
431+ uut . end ( ) ;
432+ return new Promise ( resolve => setImmediate ( resolve ) ) ;
433+ } ;
434+ uut . on ( 'data' , ( value ) => {
435+ try {
436+ const message = jrpc . parse ( value ) ;
437+ expect ( message ) . toMatchObject ( {
438+ kind : 'response' ,
439+ id : 'bar' ,
440+ } ) ;
441+ done ( ) ;
442+ } catch ( e ) {
443+ done . fail ( e ) ;
444+ }
445+ } ) ;
446+ uut . write ( jrpc . request ( 'bar' , '' ) ) ;
447+ } ) ;
448+
364449 describe ( 'sends an internal error response' , ( ) => {
365450 function testInternalError ( onRequest : peer . RequestHandler ) {
366451 uut . onRequest = onRequest ;
@@ -433,6 +518,15 @@ describe('Peer', () => {
433518 return Promise . reject ( new peer . RPCError ( 'You dun goofed' , 5555 ) ) ;
434519 } ) ;
435520 } ) ;
521+
522+ test ( 'after the Writable side is closed' , ( done ) => {
523+ testErrorResponse ( done , ( ) => {
524+ uut . end ( ) ;
525+ return new Promise ( ( resolve , reject ) => {
526+ setImmediate ( ( ) => reject ( new peer . RPCError ( 'You dun goofed' , 5555 ) ) ) ;
527+ } ) ;
528+ } ) ;
529+ } ) ;
436530 } ) ;
437531
438532 it ( 'forwards a parse error from the deserializer to the remote peer' , ( done ) => {
@@ -480,28 +574,23 @@ describe('Peer', () => {
480574 const methodCalls = [ uut . callMethod ( 'foo' ) , uut . callMethod ( 'bar' ) ] ;
481575 uut . end ( ) ;
482576 return Promise . all ( methodCalls . map ( ( call ) => {
483- return expect ( call ) . rejects . toEqual (
484- expect . objectContaining ( {
485- message : expect . stringMatching ( / R P C s t r e a m c l o s e d / ) ,
486- } ) ,
487- ) ;
577+ return expect ( call ) . rejects . toThrow ( peer . RPCStreamClosed ) ;
488578 } ) ) ;
489579 } ) ;
490580
491581 describe ( 'after the stream ends' , ( ) => {
492582 beforeEach ( ( ) => uut . end ( ) ) ;
493583
494- it ( 'throws an error when attempting to call a method' , ( ) => {
495- expect ( ( ) => uut . callMethod ( 'foo' ) ) . toThrow ( / R P C s t r e a m c l o s e d / ) ;
584+ it ( 'rejects when attempting to call a method' , ( ) => {
585+ return expect ( uut . callMethod ( 'foo' ) ) . rejects . toThrow ( peer . RPCStreamClosed ) ;
496586 } ) ;
497587
498- it ( 'throws an error when attempting to send a notification' , ( ) => {
499- expect ( ( ) => uut . sendNotification ( 'foo' ) ) . toThrow ( / R P C s t r e a m c l o s e d / ) ;
588+ it ( 'does not throw when attempting to send a notification' , ( ) => {
589+ expect ( ( ) => uut . sendNotification ( 'foo' ) ) . not . toThrow ( ) ;
500590 } ) ;
501591
502- it ( 'throws an error when attempting to push an error' , ( ) => {
503- expect ( ( ) => uut . pushError ( { code : 0 , message : 'foo' } ) )
504- . toThrow ( / R P C s t r e a m c l o s e d / ) ;
592+ it ( 'does not throw when attempting to push an error' , ( ) => {
593+ expect ( ( ) => uut . pushError ( { code : 0 , message : 'foo' } ) ) . not . toThrow ( ) ;
505594 } ) ;
506595 } ) ;
507596
@@ -555,7 +644,7 @@ describe('Peer', () => {
555644 beforeEach ( ( ) => uut . end ( ) ) ;
556645
557646 it ( 'rejects with an error' , ( ) => expect ( methodCall ) . rejects . toThrow (
558- / R P C s t r e a m c l o s e d / ,
647+ peer . RPCStreamClosed ,
559648 ) ) ;
560649 it ( 'clears the timeout timer' , ( ) => expect ( clearTimeout ) . toBeCalled ( ) ) ;
561650 } ) ;
0 commit comments