@@ -5,6 +5,49 @@ import crypto from 'crypto'
55import { createMockRequest } from '@sim/testing'
66import { afterEach , describe , expect , it , vi } from 'vitest'
77import { ashbyHandler } from '@/lib/webhooks/providers/ashby'
8+ import type {
9+ AuthContext ,
10+ EventMatchContext ,
11+ FormatInputContext ,
12+ } from '@/lib/webhooks/providers/types'
13+
14+ function authContext (
15+ request : AuthContext [ 'request' ] ,
16+ rawBody : string ,
17+ providerConfig : Record < string , unknown >
18+ ) : AuthContext {
19+ return {
20+ request,
21+ rawBody,
22+ requestId : 'r1' ,
23+ providerConfig,
24+ webhook : { } ,
25+ workflow : { } ,
26+ }
27+ }
28+
29+ function eventMatchContext ( body : unknown , triggerId : string ) : EventMatchContext {
30+ return {
31+ webhook : { id : 'w1' } ,
32+ workflow : { } ,
33+ body,
34+ request : createMockRequest ( 'POST' , body ) ,
35+ requestId : 'r1' ,
36+ providerConfig : { triggerId } ,
37+ }
38+ }
39+
40+ function formatInputContext ( body : unknown ) : FormatInputContext {
41+ return {
42+ webhook : { id : 'w1' } ,
43+ workflow : { id : 'workflow-1' , userId : 'user-1' } ,
44+ body,
45+ headers : { } ,
46+ query : { } ,
47+ method : 'POST' ,
48+ requestId : 'r1' ,
49+ }
50+ }
851
952describe ( 'ashbyHandler' , ( ) => {
1053 describe ( 'verifyAuth' , ( ) => {
@@ -16,99 +59,65 @@ describe('ashbyHandler', () => {
1659 const request = createMockRequest ( 'POST' , JSON . parse ( rawBody ) , {
1760 'ashby-signature' : signature ,
1861 } )
19- const res = ashbyHandler . verifyAuth ! ( {
20- request : request as any ,
21- rawBody,
22- requestId : 'r1' ,
23- providerConfig : { } ,
24- webhook : { } ,
25- workflow : { } ,
26- } )
62+ const res = ashbyHandler . verifyAuth ! ( authContext ( request , rawBody , { } ) )
2763 expect ( res ?. status ) . toBe ( 401 )
2864 } )
2965
3066 it ( 'returns 401 when signature header is missing' , ( ) => {
3167 const request = createMockRequest ( 'POST' , JSON . parse ( rawBody ) , { } )
32- const res = ashbyHandler . verifyAuth ! ( {
33- request : request as any ,
34- rawBody,
35- requestId : 'r1' ,
36- providerConfig : { secretToken : secret } ,
37- webhook : { } ,
38- workflow : { } ,
39- } )
68+ const res = ashbyHandler . verifyAuth ! ( authContext ( request , rawBody , { secretToken : secret } ) )
4069 expect ( res ?. status ) . toBe ( 401 )
4170 } )
4271
4372 it ( 'returns 401 when signature is invalid' , ( ) => {
4473 const request = createMockRequest ( 'POST' , JSON . parse ( rawBody ) , {
4574 'ashby-signature' : 'sha256=deadbeef' ,
4675 } )
47- const res = ashbyHandler . verifyAuth ! ( {
48- request : request as any ,
49- rawBody,
50- requestId : 'r1' ,
51- providerConfig : { secretToken : secret } ,
52- webhook : { } ,
53- workflow : { } ,
54- } )
76+ const res = ashbyHandler . verifyAuth ! ( authContext ( request , rawBody , { secretToken : secret } ) )
5577 expect ( res ?. status ) . toBe ( 401 )
5678 } )
5779
5880 it ( 'returns null when signature is valid' , ( ) => {
5981 const request = createMockRequest ( 'POST' , JSON . parse ( rawBody ) , {
6082 'ashby-signature' : signature ,
6183 } )
62- const res = ashbyHandler . verifyAuth ! ( {
63- request : request as any ,
64- rawBody,
65- requestId : 'r1' ,
66- providerConfig : { secretToken : secret } ,
67- webhook : { } ,
68- workflow : { } ,
69- } )
84+ const res = ashbyHandler . verifyAuth ! ( authContext ( request , rawBody , { secretToken : secret } ) )
7085 expect ( res ) . toBeNull ( )
7186 } )
7287 } )
7388
7489 describe ( 'matchEvent' , ( ) => {
7590 it ( 'rejects ping events' , async ( ) => {
76- const matched = await ashbyHandler . matchEvent ! ( {
77- webhook : { id : 'w1' } as any ,
78- body : { action : 'ping' , data : { webhookActionType : 'ping' } } ,
79- requestId : 'r1' ,
80- providerConfig : { triggerId : 'ashby_application_submit' } ,
81- } as any )
91+ const matched = await ashbyHandler . matchEvent ! (
92+ eventMatchContext (
93+ { action : 'ping' , data : { webhookActionType : 'ping' } } ,
94+ 'ashby_application_submit'
95+ )
96+ )
8297 expect ( matched ) . toBe ( false )
8398 } )
8499
85100 it ( 'matches when action equals the configured trigger event' , async ( ) => {
86- const matched = await ashbyHandler . matchEvent ! ( {
87- webhook : { id : 'w1' } as any ,
88- body : { action : 'applicationSubmit' , data : { } } ,
89- requestId : 'r1' ,
90- providerConfig : { triggerId : 'ashby_application_submit' } ,
91- } as any )
101+ const matched = await ashbyHandler . matchEvent ! (
102+ eventMatchContext ( { action : 'applicationSubmit' , data : { } } , 'ashby_application_submit' )
103+ )
92104 expect ( matched ) . toBe ( true )
93105 } )
94106
95107 it ( 'rejects when action does not match the configured trigger event' , async ( ) => {
96- const matched = await ashbyHandler . matchEvent ! ( {
97- webhook : { id : 'w1' } as any ,
98- body : { action : 'jobCreate' , data : { } } ,
99- requestId : 'r1' ,
100- providerConfig : { triggerId : 'ashby_application_submit' } ,
101- } as any )
108+ const matched = await ashbyHandler . matchEvent ! (
109+ eventMatchContext ( { action : 'jobCreate' , data : { } } , 'ashby_application_submit' )
110+ )
102111 expect ( matched ) . toBe ( false )
103112 } )
104113
105114 it ( 'matches newly supported Ashby events' , async ( ) => {
106- const matched = await ashbyHandler . matchEvent ! ( {
107- webhook : { id : 'w1' } as any ,
108- body : { action : 'signatureRequestUpdate' , data : { } } ,
109- requestId : 'r1' ,
110- providerConfig : { triggerId : 'ashby_signature_request_update' } ,
111- } as any )
115+ const matched = await ashbyHandler . matchEvent ! (
116+ eventMatchContext (
117+ { action : 'signatureRequestUpdate' , data : { } } ,
118+ 'ashby_signature_request_update'
119+ )
120+ )
112121 expect ( matched ) . toBe ( true )
113122 } )
114123 } )
@@ -126,30 +135,30 @@ describe('ashbyHandler', () => {
126135
127136 describe ( 'formatInput' , ( ) => {
128137 it ( 'spreads data fields to the top level alongside action' , async ( ) => {
129- const result = await ashbyHandler . formatInput ! ( {
130- body : {
138+ const result = await ashbyHandler . formatInput ! (
139+ formatInputContext ( {
131140 action : 'applicationSubmit' ,
132141 data : { application : { id : 'app-1' , status : 'Active' } } ,
133- } ,
134- } as any )
142+ } )
143+ )
135144 expect ( result . input ) . toEqual ( {
136145 action : 'applicationSubmit' ,
137146 application : { id : 'app-1' , status : 'Active' } ,
138147 } )
139148 } )
140149
141150 it ( 'renames currentInterviewStage.type to stageType, matching the trigger output schema' , async ( ) => {
142- const result = await ashbyHandler . formatInput ! ( {
143- body : {
151+ const result = await ashbyHandler . formatInput ! (
152+ formatInputContext ( {
144153 action : 'candidateStageChange' ,
145154 data : {
146155 application : {
147156 id : 'app-1' ,
148157 currentInterviewStage : { id : 'stage-1' , title : 'Offer' , type : 'Offer' } ,
149158 } ,
150159 } ,
151- } ,
152- } as any )
160+ } )
161+ )
153162 expect ( result . input . application ) . toEqual ( {
154163 id : 'app-1' ,
155164 currentInterviewStage : { id : 'stage-1' , title : 'Offer' , stageType : 'Offer' } ,
0 commit comments