@@ -6,6 +6,11 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
66const {
77 mockLimit,
88 mockUpdateSet,
9+ mockActivateWorkflowVersion,
10+ mockDeployWorkflow,
11+ mockValidateWorkflowSchedules,
12+ mockValidateTriggerWebhookConfigForDeploy,
13+ mockValidateWorkflowState,
914 mockSaveWorkflowToNormalizedTables,
1015 mockRecordAudit,
1116 mockCaptureServerEvent,
@@ -14,6 +19,11 @@ const {
1419} = vi . hoisted ( ( ) => ( {
1520 mockLimit : vi . fn ( ) ,
1621 mockUpdateSet : vi . fn ( ) ,
22+ mockActivateWorkflowVersion : vi . fn ( ) ,
23+ mockDeployWorkflow : vi . fn ( ) ,
24+ mockValidateWorkflowSchedules : vi . fn ( ) ,
25+ mockValidateTriggerWebhookConfigForDeploy : vi . fn ( ) ,
26+ mockValidateWorkflowState : vi . fn ( ) ,
1727 mockSaveWorkflowToNormalizedTables : vi . fn ( ) ,
1828 mockRecordAudit : vi . fn ( ) ,
1929 mockCaptureServerEvent : vi . fn ( ) ,
@@ -59,7 +69,11 @@ vi.mock('@sim/db', () => ({
5969} ) )
6070
6171vi . mock ( '@sim/audit' , ( ) => ( {
62- AuditAction : { WORKFLOW_DEPLOYMENT_REVERTED : 'WORKFLOW_DEPLOYMENT_REVERTED' } ,
72+ AuditAction : {
73+ WORKFLOW_DEPLOYED : 'WORKFLOW_DEPLOYED' ,
74+ WORKFLOW_DEPLOYMENT_ACTIVATED : 'WORKFLOW_DEPLOYMENT_ACTIVATED' ,
75+ WORKFLOW_DEPLOYMENT_REVERTED : 'WORKFLOW_DEPLOYMENT_REVERTED' ,
76+ } ,
6377 AuditResourceType : { WORKFLOW : 'WORKFLOW' } ,
6478 recordAudit : mockRecordAudit ,
6579} ) )
@@ -78,9 +92,9 @@ vi.mock('@/lib/posthog/server', () => ({
7892} ) )
7993
8094vi . mock ( '@/lib/workflows/persistence/utils' , ( ) => ( {
81- activateWorkflowVersion : vi . fn ( ) ,
95+ activateWorkflowVersion : mockActivateWorkflowVersion ,
8296 activateWorkflowVersionById : vi . fn ( ) ,
83- deployWorkflow : vi . fn ( ) ,
97+ deployWorkflow : mockDeployWorkflow ,
8498 loadWorkflowDeploymentSnapshot : vi . fn ( ) ,
8599 saveWorkflowToNormalizedTables : mockSaveWorkflowToNormalizedTables ,
86100 undeployWorkflow : vi . fn ( ) ,
@@ -95,15 +109,122 @@ vi.mock('@/lib/webhooks/deploy', () => ({
95109 cleanupWebhooksForWorkflow : vi . fn ( ) ,
96110 restorePreviousVersionWebhooks : vi . fn ( ) ,
97111 saveTriggerWebhooksForDeploy : vi . fn ( ) ,
112+ validateTriggerWebhookConfigForDeploy : mockValidateTriggerWebhookConfigForDeploy ,
98113} ) )
99114
100115vi . mock ( '@/lib/workflows/schedules' , ( ) => ( {
101116 cleanupDeploymentVersion : vi . fn ( ) ,
102117 createSchedulesForDeploy : vi . fn ( ) ,
103- validateWorkflowSchedules : vi . fn ( ) ,
118+ validateWorkflowSchedules : mockValidateWorkflowSchedules ,
119+ } ) )
120+
121+ vi . mock ( '@/lib/workflows/sanitization/validation' , ( ) => ( {
122+ validateWorkflowState : mockValidateWorkflowState ,
104123} ) )
105124
106- import { performRevertToVersion } from '@/lib/workflows/orchestration/deploy'
125+ import {
126+ performActivateVersion ,
127+ performFullDeploy ,
128+ performRevertToVersion ,
129+ } from '@/lib/workflows/orchestration/deploy'
130+
131+ const VALID_WORKFLOW_STATE = {
132+ blocks : { } ,
133+ edges : [ ] ,
134+ loops : { } ,
135+ parallels : { } ,
136+ }
137+
138+ describe ( 'performFullDeploy' , ( ) => {
139+ beforeEach ( ( ) => {
140+ vi . clearAllMocks ( )
141+ vi . stubGlobal ( 'fetch' , vi . fn ( ) . mockResolvedValue ( new Response ( null , { status : 200 } ) ) )
142+ mockLimit . mockResolvedValue ( [
143+ {
144+ id : 'workflow-1' ,
145+ name : 'Workflow' ,
146+ workspaceId : 'workspace-1' ,
147+ } ,
148+ ] )
149+ mockValidateWorkflowState . mockReturnValue ( { valid : true , errors : [ ] , warnings : [ ] } )
150+ mockValidateWorkflowSchedules . mockReturnValue ( { isValid : true } )
151+ mockValidateTriggerWebhookConfigForDeploy . mockResolvedValue ( { success : true } )
152+ } )
153+
154+ it ( 'rejects structurally invalid workflows before schedule or webhook deployment checks' , async ( ) => {
155+ mockValidateWorkflowState . mockReturnValue ( {
156+ valid : false ,
157+ errors : [ "Edge references non-existent source block 'missing-source'" ] ,
158+ warnings : [ ] ,
159+ } )
160+ mockDeployWorkflow . mockImplementation ( async ( { validateWorkflowState } ) => {
161+ return validateWorkflowState ( {
162+ ...VALID_WORKFLOW_STATE ,
163+ edges : [ { id : 'edge-1' , source : 'missing-source' , target : 'missing-target' } ] ,
164+ } )
165+ } )
166+
167+ const result = await performFullDeploy ( {
168+ workflowId : 'workflow-1' ,
169+ userId : 'user-1' ,
170+ workflowName : 'Workflow' ,
171+ } )
172+
173+ expect ( result ) . toEqual ( {
174+ success : false ,
175+ error :
176+ "Invalid workflow structure: Edge references non-existent source block 'missing-source'" ,
177+ errorCode : 'validation' ,
178+ } )
179+ expect ( mockValidateWorkflowSchedules ) . not . toHaveBeenCalled ( )
180+ expect ( mockValidateTriggerWebhookConfigForDeploy ) . not . toHaveBeenCalled ( )
181+ } )
182+ } )
183+
184+ describe ( 'performActivateVersion' , ( ) => {
185+ beforeEach ( ( ) => {
186+ vi . clearAllMocks ( )
187+ vi . stubGlobal ( 'fetch' , vi . fn ( ) . mockResolvedValue ( new Response ( null , { status : 200 } ) ) )
188+ mockValidateWorkflowState . mockReturnValue ( { valid : true , errors : [ ] , warnings : [ ] } )
189+ mockValidateWorkflowSchedules . mockReturnValue ( { isValid : true } )
190+ mockValidateTriggerWebhookConfigForDeploy . mockResolvedValue ( { success : true } )
191+ } )
192+
193+ it ( 'rejects invalid deployment snapshots before activation' , async ( ) => {
194+ mockLimit . mockResolvedValue ( [
195+ {
196+ id : 'deployment-version-1' ,
197+ state : {
198+ ...VALID_WORKFLOW_STATE ,
199+ edges : [ { id : 'edge-1' , source : 'missing-source' , target : 'missing-target' } ] ,
200+ } ,
201+ isActive : false ,
202+ } ,
203+ ] )
204+ mockValidateWorkflowState . mockReturnValue ( {
205+ valid : false ,
206+ errors : [ "Edge references non-existent source block 'missing-source'" ] ,
207+ warnings : [ ] ,
208+ } )
209+
210+ const result = await performActivateVersion ( {
211+ workflowId : 'workflow-1' ,
212+ version : 2 ,
213+ userId : 'user-1' ,
214+ workflow : { id : 'workflow-1' , name : 'Workflow' , workspaceId : 'workspace-1' } ,
215+ } )
216+
217+ expect ( result ) . toEqual ( {
218+ success : false ,
219+ error :
220+ "Invalid workflow structure: Edge references non-existent source block 'missing-source'" ,
221+ errorCode : 'validation' ,
222+ } )
223+ expect ( mockActivateWorkflowVersion ) . not . toHaveBeenCalled ( )
224+ expect ( mockValidateWorkflowSchedules ) . not . toHaveBeenCalled ( )
225+ expect ( mockValidateTriggerWebhookConfigForDeploy ) . not . toHaveBeenCalled ( )
226+ } )
227+ } )
107228
108229describe ( 'performRevertToVersion' , ( ) => {
109230 beforeEach ( ( ) => {
0 commit comments