33 */
44import { beforeEach , describe , expect , it , vi } from 'vitest'
55
6- const {
7- mockParseWebhookBody,
8- mockFindWebhooksByRoutingKey,
9- mockCheckWebhookPreprocessing,
10- mockQueueWebhookExecution,
11- mockBlockExistsInDeployment,
12- mockShouldSkip,
13- } = vi . hoisted ( ( ) => ( {
14- mockParseWebhookBody : vi . fn ( ) ,
15- mockFindWebhooksByRoutingKey : vi . fn ( ) ,
16- mockCheckWebhookPreprocessing : vi . fn ( ) ,
17- mockQueueWebhookExecution : vi . fn ( ) ,
18- mockBlockExistsInDeployment : vi . fn ( ) ,
19- mockShouldSkip : vi . fn ( ) ,
20- } ) )
6+ const { mockParseWebhookBody, mockFindWebhooksByRoutingKey, mockDispatchResolvedWebhookTarget } =
7+ vi . hoisted ( ( ) => ( {
8+ mockParseWebhookBody : vi . fn ( ) ,
9+ mockFindWebhooksByRoutingKey : vi . fn ( ) ,
10+ mockDispatchResolvedWebhookTarget : vi . fn ( ) ,
11+ } ) )
2112
2213vi . mock ( '@/lib/core/admission/gate' , ( ) => ( {
2314 tryAdmit : ( ) => ( { release : vi . fn ( ) } ) ,
@@ -31,21 +22,15 @@ vi.mock('@/lib/core/config/env', () => ({
3122vi . mock ( '@/lib/webhooks/processor' , ( ) => ( {
3223 parseWebhookBody : mockParseWebhookBody ,
3324 findWebhooksByRoutingKey : mockFindWebhooksByRoutingKey ,
34- checkWebhookPreprocessing : mockCheckWebhookPreprocessing ,
35- queueWebhookExecution : mockQueueWebhookExecution ,
25+ dispatchResolvedWebhookTarget : mockDispatchResolvedWebhookTarget ,
3626} ) )
3727
3828vi . mock ( '@/lib/webhooks/providers/slack' , ( ) => ( {
3929 handleSlackChallenge : ( ) => null ,
4030 verifySlackRequestSignature : ( ) => null ,
41- shouldSkipSlackTriggerEvent : mockShouldSkip ,
4231 resolveSlackEventKey : ( ) => null ,
4332} ) )
4433
45- vi . mock ( '@/lib/workflows/persistence/utils' , ( ) => ( {
46- blockExistsInDeployment : mockBlockExistsInDeployment ,
47- } ) )
48-
4934import { POST } from '@/app/api/webhooks/slack/route'
5035
5136function makeRequest ( ) {
@@ -61,12 +46,6 @@ function webhook(id: string) {
6146
6247async function run ( body : Record < string , unknown > ) {
6348 mockParseWebhookBody . mockResolvedValue ( { body, rawBody : JSON . stringify ( body ) } )
64- mockCheckWebhookPreprocessing . mockResolvedValue ( {
65- actorUserId : 'u1' ,
66- executionId : 'e1' ,
67- correlation : { } ,
68- } )
69- mockBlockExistsInDeployment . mockResolvedValue ( true )
7049 await POST ( makeRequest ( ) )
7150}
7251
@@ -80,22 +59,29 @@ describe('Slack app webhook route', () => {
8059 beforeEach ( ( ) => {
8160 vi . clearAllMocks ( )
8261 mockFindWebhooksByRoutingKey . mockResolvedValue ( [ webhook ( 'wh1' ) ] )
62+ mockDispatchResolvedWebhookTarget . mockResolvedValue ( {
63+ outcome : 'queued' ,
64+ response : new Response ( null , { status : 200 } ) ,
65+ reason : 'queued' ,
66+ } )
8367 } )
8468
85- it ( 'queues execution when the shared filter does not skip' , async ( ) => {
86- mockShouldSkip . mockReturnValue ( false )
69+ it ( 'dispatches each webhook resolved for the event team' , async ( ) => {
8770 await run ( messageBody )
88- expect ( mockQueueWebhookExecution ) . toHaveBeenCalledTimes ( 1 )
71+ expect ( mockDispatchResolvedWebhookTarget ) . toHaveBeenCalledTimes ( 1 )
8972 } )
9073
91- it ( 'does not queue when the shared filter skips the event' , async ( ) => {
92- mockShouldSkip . mockReturnValue ( true )
74+ it ( 'continues cleanly when the dispatcher filters the event' , async ( ) => {
75+ mockDispatchResolvedWebhookTarget . mockResolvedValue ( {
76+ outcome : 'ignored' ,
77+ response : new Response ( null , { status : 200 } ) ,
78+ reason : 'filtered' ,
79+ } )
9380 await run ( messageBody )
94- expect ( mockQueueWebhookExecution ) . not . toHaveBeenCalled ( )
81+ expect ( mockDispatchResolvedWebhookTarget ) . toHaveBeenCalledTimes ( 1 )
9582 } )
9683
9784 it ( 'routes via Slack Connect authorizations and dedups overlapping webhooks' , async ( ) => {
98- mockShouldSkip . mockReturnValue ( false )
9985 // Two candidate teams (outer + authorization) that resolve to overlapping webhooks.
10086 mockFindWebhooksByRoutingKey . mockImplementation ( async ( teamId : string ) =>
10187 teamId === 'T1' ? [ webhook ( 'wh1' ) ] : [ webhook ( 'wh1' ) , webhook ( 'wh2' ) ]
@@ -105,19 +91,17 @@ describe('Slack app webhook route', () => {
10591 authorizations : [ { team_id : 'T2' } ] ,
10692 } )
10793 expect ( mockFindWebhooksByRoutingKey ) . toHaveBeenCalledTimes ( 2 )
108- // wh1 (in both) is queued once, wh2 once — dedup by webhook id.
109- expect ( mockQueueWebhookExecution ) . toHaveBeenCalledTimes ( 2 )
94+ // wh1 (in both) is dispatched once, wh2 once — dedup by webhook id.
95+ expect ( mockDispatchResolvedWebhookTarget ) . toHaveBeenCalledTimes ( 2 )
11096 } )
11197
11298 it ( 'returns 200 with no team_id' , async ( ) => {
113- mockShouldSkip . mockReturnValue ( false )
11499 await run ( { event : { type : 'message' } } )
115100 expect ( mockFindWebhooksByRoutingKey ) . not . toHaveBeenCalled ( )
116- expect ( mockQueueWebhookExecution ) . not . toHaveBeenCalled ( )
101+ expect ( mockDispatchResolvedWebhookTarget ) . not . toHaveBeenCalled ( )
117102 } )
118103
119104 it ( 'routes an interaction payload by payload.team.id' , async ( ) => {
120- mockShouldSkip . mockReturnValue ( false )
121105 await run ( {
122106 type : 'block_actions' ,
123107 api_app_id : 'A1' ,
@@ -126,18 +110,17 @@ describe('Slack app webhook route', () => {
126110 actions : [ { action_id : 'approve_btn' } ] ,
127111 } )
128112 expect ( mockFindWebhooksByRoutingKey ) . toHaveBeenCalledWith ( 'T1' , expect . anything ( ) )
129- expect ( mockQueueWebhookExecution ) . toHaveBeenCalledTimes ( 1 )
113+ expect ( mockDispatchResolvedWebhookTarget ) . toHaveBeenCalledTimes ( 1 )
130114 } )
131115
132116 it ( 'fails closed on an interaction missing payload.team.id (never routes on user.team_id)' , async ( ) => {
133- mockShouldSkip . mockReturnValue ( false )
134117 await run ( {
135118 type : 'block_actions' ,
136119 api_app_id : 'A1' ,
137120 user : { id : 'U1' , team_id : 'T_OTHER' } ,
138121 actions : [ { action_id : 'approve_btn' } ] ,
139122 } )
140123 expect ( mockFindWebhooksByRoutingKey ) . not . toHaveBeenCalled ( )
141- expect ( mockQueueWebhookExecution ) . not . toHaveBeenCalled ( )
124+ expect ( mockDispatchResolvedWebhookTarget ) . not . toHaveBeenCalled ( )
142125 } )
143126} )
0 commit comments