@@ -38,6 +38,7 @@ describe('Agent Reply - /agents/:agentId/reply #novu-v2', () => {
3838 . resolves ( { messageId : 'platform-msg-1' , platformThreadId : 'platform-thread-1' } ) ;
3939 sinon . stub ( outboundGateway , 'reactToMessage' ) . resolves ( ) ;
4040 sinon . stub ( outboundGateway , 'removeReaction' ) . resolves ( ) ;
41+ sinon . stub ( outboundGateway , 'startTypingInConversation' ) . resolves ( ) ;
4142 } ) ;
4243
4344 function postReply ( body : Record < string , unknown > ) {
@@ -325,6 +326,84 @@ describe('Agent Reply - /agents/:agentId/reply #novu-v2', () => {
325326 } ) ;
326327 } ) ;
327328
329+ describe ( 'Typing' , ( ) => {
330+ it ( 'should set a typing status from a typing-only request' , async ( ) => {
331+ const conversationId = await seedConversation ( ctx ) ;
332+ const outboundGateway = testServer . getService ( OutboundGateway ) ;
333+
334+ const res = await postReply ( {
335+ conversationId,
336+ integrationIdentifier : ctx . integrationIdentifier ,
337+ typing : { status : 'Searching the docs…' } ,
338+ } ) ;
339+
340+ expect ( res . status ) . to . equal ( 200 ) ;
341+ expect ( res . body . data ) . to . be . null ;
342+
343+ const stub = outboundGateway . startTypingInConversation as sinon . SinonStub ;
344+ expect ( stub . callCount ) . to . equal ( 1 ) ;
345+ expect ( stub . getCall ( 0 ) . args [ 3 ] ) . to . equal ( 'Searching the docs…' ) ;
346+ } ) ;
347+
348+ it ( 'should default the status text when typing has no status' , async ( ) => {
349+ const conversationId = await seedConversation ( ctx ) ;
350+ const outboundGateway = testServer . getService ( OutboundGateway ) ;
351+
352+ const res = await postReply ( {
353+ conversationId,
354+ integrationIdentifier : ctx . integrationIdentifier ,
355+ typing : { } ,
356+ } ) ;
357+
358+ expect ( res . status ) . to . equal ( 200 ) ;
359+
360+ const stub = outboundGateway . startTypingInConversation as sinon . SinonStub ;
361+ expect ( stub . getCall ( 0 ) . args [ 3 ] ) . to . equal ( 'Thinking...' ) ;
362+ } ) ;
363+
364+ it ( 'should clear the status with an empty string for typing "stop"' , async ( ) => {
365+ const conversationId = await seedConversation ( ctx ) ;
366+ const outboundGateway = testServer . getService ( OutboundGateway ) ;
367+
368+ const res = await postReply ( {
369+ conversationId,
370+ integrationIdentifier : ctx . integrationIdentifier ,
371+ typing : 'stop' ,
372+ } ) ;
373+
374+ expect ( res . status ) . to . equal ( 200 ) ;
375+
376+ const stub = outboundGateway . startTypingInConversation as sinon . SinonStub ;
377+ expect ( stub . getCall ( 0 ) . args [ 3 ] ) . to . equal ( '' ) ;
378+ } ) ;
379+
380+ it ( 'should not fail the turn when the typing call throws' , async ( ) => {
381+ const conversationId = await seedConversation ( ctx ) ;
382+ const outboundGateway = testServer . getService ( OutboundGateway ) ;
383+ ( outboundGateway . startTypingInConversation as sinon . SinonStub ) . rejects ( new Error ( 'platform down' ) ) ;
384+
385+ const res = await postReply ( {
386+ conversationId,
387+ integrationIdentifier : ctx . integrationIdentifier ,
388+ typing : { status : 'Working…' } ,
389+ } ) ;
390+
391+ expect ( res . status ) . to . equal ( 200 ) ;
392+ } ) ;
393+
394+ it ( 'should reject an invalid typing op' , async ( ) => {
395+ const conversationId = await seedConversation ( ctx ) ;
396+
397+ const res = await postReply ( {
398+ conversationId,
399+ integrationIdentifier : ctx . integrationIdentifier ,
400+ typing : 'go' ,
401+ } ) ;
402+
403+ expect ( res . status ) . to . equal ( 422 ) ;
404+ } ) ;
405+ } ) ;
406+
328407 describe ( 'Inactive agent' , ( ) => {
329408 it ( 'should return 422 when agent is inactive' , async ( ) => {
330409 const conversationId = await seedConversation ( ctx ) ;
0 commit comments