@@ -153,4 +153,126 @@ describe('setupOperationsHandlers', () => {
153153 expect . objectContaining ( { operationId : 'op-1' , serverTimestamp : expect . any ( Number ) } )
154154 )
155155 } )
156+
157+ it ( 'broadcasts generic side-effect edge syncs to the initiating client' , async ( ) => {
158+ mockPersistWorkflowOperation . mockResolvedValue ( {
159+ removedEdgeIds : [ 'edge-removed' ] ,
160+ addedEdges : [
161+ {
162+ id : 'edge-added' ,
163+ source : 'container-1' ,
164+ target : 'block-1' ,
165+ sourceHandle : 'loop-start-source' ,
166+ targetHandle : 'target' ,
167+ type : 'workflowEdge' ,
168+ } ,
169+ ] ,
170+ } )
171+
172+ const socketEmit = vi . fn ( )
173+ const socketRoomEmit = vi . fn ( )
174+ const emitToWorkflow = vi . fn ( )
175+ const socketHandlers = new Map < string , ( data : unknown ) => Promise < void > > ( )
176+
177+ const socket = {
178+ id : 'socket-1' ,
179+ on : vi . fn ( ( event : string , handler : ( data : unknown ) => Promise < void > ) => {
180+ socketHandlers . set ( event , handler )
181+ } ) ,
182+ emit : socketEmit ,
183+ to : vi . fn ( ( ) => ( {
184+ emit : socketRoomEmit ,
185+ } ) ) ,
186+ }
187+
188+ const roomManager = {
189+ io : { } as never ,
190+ initialize : vi . fn ( ) ,
191+ isReady : vi . fn ( ( ) => true ) ,
192+ shutdown : vi . fn ( ) ,
193+ addUserToRoom : vi . fn ( ) ,
194+ removeUserFromRoom : vi . fn ( ) ,
195+ getWorkflowIdForSocket : vi . fn ( ) . mockResolvedValue ( 'workflow-1' ) ,
196+ getUserSession : vi . fn ( ) . mockResolvedValue ( { userId : 'user-1' , userName : 'Test User' } ) ,
197+ getWorkflowUsers : vi . fn ( ) . mockResolvedValue ( [
198+ {
199+ socketId : 'socket-1' ,
200+ userId : 'user-1' ,
201+ workflowId : 'workflow-1' ,
202+ userName : 'Test User' ,
203+ joinedAt : Date . now ( ) ,
204+ lastActivity : Date . now ( ) ,
205+ role : 'admin' ,
206+ } ,
207+ ] ) ,
208+ hasWorkflowRoom : vi . fn ( ) . mockResolvedValue ( true ) ,
209+ updateUserActivity : vi . fn ( ) ,
210+ updateRoomLastModified : vi . fn ( ) ,
211+ broadcastPresenceUpdate : vi . fn ( ) ,
212+ emitToWorkflow,
213+ getUniqueUserCount : vi . fn ( ) ,
214+ getTotalActiveConnections : vi . fn ( ) ,
215+ handleWorkflowDeletion : vi . fn ( ) ,
216+ handleWorkflowRevert : vi . fn ( ) ,
217+ handleWorkflowUpdate : vi . fn ( ) ,
218+ }
219+
220+ setupOperationsHandlers ( socket as never , roomManager )
221+
222+ const workflowOperationHandler = socketHandlers . get ( 'workflow-operation' )
223+
224+ expect ( workflowOperationHandler ) . toBeDefined ( )
225+
226+ await workflowOperationHandler ?.( {
227+ operationId : 'op-2' ,
228+ operation : BLOCKS_OPERATIONS . BATCH_TOGGLE_LOCKED ,
229+ target : OPERATION_TARGETS . BLOCKS ,
230+ payload : {
231+ ids : [ 'block-1' ] ,
232+ locked : true ,
233+ } ,
234+ timestamp : 456 ,
235+ } )
236+
237+ expect ( socketRoomEmit ) . toHaveBeenCalledWith (
238+ 'workflow-operation' ,
239+ expect . objectContaining ( {
240+ operation : BLOCKS_OPERATIONS . BATCH_TOGGLE_LOCKED ,
241+ target : OPERATION_TARGETS . BLOCKS ,
242+ payload : { ids : [ 'block-1' ] , locked : true } ,
243+ } )
244+ )
245+ expect ( emitToWorkflow ) . toHaveBeenNthCalledWith (
246+ 1 ,
247+ 'workflow-1' ,
248+ 'workflow-operation' ,
249+ expect . objectContaining ( {
250+ operation : EDGES_OPERATIONS . BATCH_REMOVE_EDGES ,
251+ target : OPERATION_TARGETS . EDGES ,
252+ payload : { ids : [ 'edge-removed' ] } ,
253+ } )
254+ )
255+ expect ( emitToWorkflow ) . toHaveBeenNthCalledWith (
256+ 2 ,
257+ 'workflow-1' ,
258+ 'workflow-operation' ,
259+ expect . objectContaining ( {
260+ operation : EDGES_OPERATIONS . BATCH_ADD_EDGES ,
261+ target : OPERATION_TARGETS . EDGES ,
262+ payload : {
263+ edges : [
264+ expect . objectContaining ( {
265+ id : 'edge-added' ,
266+ source : 'container-1' ,
267+ target : 'block-1' ,
268+ } ) ,
269+ ] ,
270+ } ,
271+ } )
272+ )
273+ expect ( socketEmit ) . toHaveBeenCalledWith (
274+ 'operation-confirmed' ,
275+ expect . objectContaining ( { operationId : 'op-2' , serverTimestamp : expect . any ( Number ) } )
276+ )
277+ } )
156278} )
0 commit comments