1+ import type { Request , Response } from 'express' ;
2+ import type { RedisCredential } from '../nodes/HttpForwardAuth/types' ;
3+ import type {
4+ IExecuteFunctions ,
5+ INode ,
6+ IWebhookFunctions ,
7+ IWorkflowDataProxyData ,
8+ NodeTypeAndVersion ,
9+ } from 'n8n-workflow' ;
10+
111import { createClient } from 'redis' ;
12+ import { mock } from 'jest-mock-extended' ;
213import { getPoolManagerInstance } from '../nodes/HttpForwardAuth/transport' ;
3- import type { RedisCredential } from '../nodes/HttpForwardAuth/types' ;
14+ import { TRIGGER_NAME } from '../nodes/HttpForwardAuth/constants' ;
15+
16+ type TriggerOpts = {
17+ request : {
18+ headers ?: Record < string , unknown > ;
19+ body ?: Record < string , unknown > ;
20+ } ;
21+ params : {
22+ authURL ?: string ;
23+ loginRedirectURL ?: string ;
24+ logoutRedirectURL ?: string ;
25+ rateLimit ?: boolean ;
26+ enableHTTP ?: boolean ;
27+ rateLimitErrorMessage ?: string ;
28+ loginTemplate ?: string ;
29+ } ;
30+ webhookName : 'setup' | 'logoutPage' | 'logout' | 'check' | 'default' ;
31+ redisStore : Record < string , string | null > ;
32+ redisEvalShaFunc ?: ( ) => [ 0 | 1 ] ;
33+ } ;
34+
35+ type ResponseOpts = {
36+ params : {
37+ userID ?: string ;
38+ validationErrorMessage ?: string ;
39+ } ;
40+ parentNodes : NodeTypeAndVersion [ ] ;
41+ triggerData : {
42+ data ?: Record < string , unknown > ,
43+ params ?: TriggerOpts [ 'params' ]
44+ }
45+ } ;
446
547export const setupRedis = ( mockOverrides ?: Record < string , unknown > ) => {
648 ( createClient as jest . Mock ) . mockImplementation ( ( ) => ( {
@@ -24,6 +66,169 @@ export const resetRedis = async () => {
2466export const resetJest = ( ) => {
2567 jest . resetAllMocks ( ) ;
2668 jest . useRealTimers ( ) ;
27- }
69+ } ;
2870
2971export const credentialsMock : RedisCredential = { host : 'redis' , port : 6379 , database : 0 } ;
72+
73+ const defaultTriggerOpts : TriggerOpts = {
74+ request : {
75+ headers : {
76+ cookie : [ ] ,
77+ } ,
78+ body : { } ,
79+ } ,
80+ params : {
81+ authURL : 'http://localhost:8080' ,
82+ loginRedirectURL : 'http://localhost:8080/protected' ,
83+ logoutRedirectURL : 'http://localhost:8080/login' ,
84+ rateLimit : false ,
85+ enableHTTP : false ,
86+ rateLimitErrorMessage : 'Rate Limit Error' ,
87+ loginTemplate : '#LOGIN_URL#|#ERROR_MESSAGE#' ,
88+ } ,
89+ webhookName : 'setup' ,
90+ redisStore : { } ,
91+ redisEvalShaFunc : ( ) => [ 1 ] ,
92+ } ;
93+
94+ export const setupTrigger = ( opts ?: Partial < TriggerOpts > ) => {
95+ const store : TriggerOpts = {
96+ request : {
97+ headers : {
98+ ...defaultTriggerOpts . request . headers ,
99+ ...( opts ?. request ?. headers ?? { } ) ,
100+ } ,
101+ body : opts ?. request ?. body ?? { } ,
102+ } ,
103+ params : {
104+ ...defaultTriggerOpts . params ,
105+ ...( opts ?. params ?? { } ) ,
106+ } ,
107+ webhookName : opts ?. webhookName ?? defaultTriggerOpts . webhookName ,
108+ redisStore : opts ?. redisStore ?? { } ,
109+ } ;
110+ const redisEvalShaMock = jest . fn ( opts ?. redisEvalShaFunc ?? defaultTriggerOpts . redisEvalShaFunc ) ;
111+ setupRedis ( {
112+ get : async ( key : string ) => store . redisStore [ key ] ,
113+ set : async ( key : string , value : string ) => {
114+ store . redisStore [ key ] = value ;
115+ } ,
116+ evalSha : redisEvalShaMock ,
117+ } ) ;
118+
119+ const resEndMock = jest . fn ( ) ;
120+ const [ resSetHeaderMock , resRedirectMock , resSendMock ] = [
121+ jest . fn ( ) ,
122+ jest . fn ( ) ,
123+ jest . fn ( ( ) =>
124+ mock < Response > ( {
125+ end : resEndMock ,
126+ } ) ,
127+ ) ,
128+ ] ;
129+ const resStatusMock = jest . fn ( ( ) =>
130+ mock < Response > ( {
131+ redirect : resRedirectMock ,
132+ end : resEndMock ,
133+ send : resSendMock ,
134+ } ) ,
135+ ) ;
136+
137+ const mocks = {
138+ redisEvalShaMock,
139+ resSetHeaderMock,
140+ resRedirectMock,
141+ resSendMock,
142+ resStatusMock,
143+ resEndMock,
144+ } ;
145+
146+ const context = mock < IWebhookFunctions > ( {
147+ getRequestObject : ( ) =>
148+ mock < Request > ( {
149+ // biome-ignore lint/suspicious/noExplicitAny: remove error for test
150+ headers : store . request . headers as any ,
151+ body : store . request . body ,
152+ } ) ,
153+ getResponseObject : ( ) =>
154+ mock < Response > ( {
155+ setHeader : resSetHeaderMock ,
156+ status : resStatusMock ,
157+ } ) ,
158+ getCredentials : async < ICredentialsDecrypted > ( ) =>
159+ credentialsMock as unknown as ICredentialsDecrypted ,
160+ // @ts -ignore
161+ getNodeParameter : ( name : string ) => store . params [ name ] ,
162+ getWebhookName : ( ) => store . webhookName ,
163+ } ) ;
164+
165+ return { context, mocks } ;
166+ } ;
167+
168+ const defaultResponseOpts : ResponseOpts = {
169+ params : {
170+ userID : '' ,
171+ validationErrorMessage : 'Validation Error' ,
172+ } ,
173+ parentNodes : [ {
174+ type : `custom.${ TRIGGER_NAME } ` ,
175+ name : 'Trigger Node' ,
176+ typeVersion : 1
177+ } ] ,
178+ triggerData : {
179+ params : {
180+ authURL : 'http://localhost:8080' ,
181+ enableHTTP : false ,
182+ loginRedirectURL : 'http://localhost:8080/protected' ,
183+ loginTemplate : '#LOGIN_URL#|#ERROR_MESSAGE#'
184+ } ,
185+ data : { remoteIp : 'REMOTE_IP' }
186+ }
187+ } ;
188+
189+ export const setupResponse = ( opts ?: Partial < ResponseOpts > ) => {
190+ setupRedis ( ) ;
191+ const sendResponseMock = jest . fn ( ) ;
192+ const store : ResponseOpts = {
193+ params : {
194+ ...defaultResponseOpts . params ,
195+ ...( opts ?. params ?? { } ) ,
196+ } ,
197+ parentNodes : [ ...( opts ?. parentNodes ?? [ ] ) ] ,
198+ triggerData : {
199+ params : {
200+ ...defaultResponseOpts . triggerData . params ,
201+ ...( opts ?. triggerData ?. params ?? { } )
202+ } ,
203+ data : {
204+ ...defaultResponseOpts . triggerData . data ,
205+ ...( opts ?. triggerData ?. data ?? { } )
206+ }
207+ }
208+ } ;
209+
210+ const mocks = {
211+ sendResponseMock,
212+ } ;
213+
214+ const context = mock < IExecuteFunctions > ( {
215+ getCredentials : async < ICredentialsDecrypted > ( ) =>
216+ credentialsMock as unknown as ICredentialsDecrypted ,
217+ // @ts -ignore
218+ getNodeParameter : jest . fn ( ( name : string ) => store . params [ name ] ) ,
219+ getNode : ( ) => mock < INode > ( ) ,
220+ getParentNodes : ( ) => store . parentNodes ,
221+ getWorkflowDataProxy : ( ) => mock < IWorkflowDataProxyData > ( {
222+ $node : {
223+ 'Trigger Node' : {
224+ parameter : store . triggerData . params ,
225+ data : store . triggerData . data
226+ }
227+ }
228+ } ) ,
229+ sendResponse : sendResponseMock ,
230+ continueOnFail : ( ) => false ,
231+ } ) ;
232+
233+ return { context, mocks } ;
234+ } ;
0 commit comments