@@ -7,17 +7,22 @@ import {
77 auditMock ,
88 authMockFns ,
99 createMockRequest ,
10+ dbChainMock ,
11+ dbChainMockFns ,
1012 type MockUser ,
1113 permissionsMock ,
1214 permissionsMockFns ,
15+ queueTableRows ,
16+ resetDbChainMock ,
17+ schemaMock ,
1318 workflowsOrchestrationMock ,
1419 workflowsOrchestrationMockFns ,
1520 workflowsUtilsMock ,
1621 workflowsUtilsMockFns ,
1722} from '@sim/testing'
18- import { beforeEach , describe , expect , it , vi } from 'vitest'
23+ import { afterAll , beforeEach , describe , expect , it , vi } from 'vitest'
1924
20- const { mockLogger, mockDbRef } = vi . hoisted ( ( ) => {
25+ const { mockLogger } = vi . hoisted ( ( ) => {
2126 const logger = {
2227 info : vi . fn ( ) ,
2328 warn : vi . fn ( ) ,
@@ -29,7 +34,6 @@ const { mockLogger, mockDbRef } = vi.hoisted(() => {
2934 }
3035 return {
3136 mockLogger : logger ,
32- mockDbRef : { current : null as any } ,
3337 }
3438} )
3539
@@ -45,23 +49,12 @@ vi.mock('@sim/logger', () => ({
4549 getRequestContext : ( ) => undefined ,
4650} ) )
4751vi . mock ( '@/lib/workspaces/permissions/utils' , ( ) => permissionsMock )
48- vi . mock ( '@sim/db' , ( ) => ( {
49- get db ( ) {
50- return mockDbRef . current
51- } ,
52- } ) )
52+ vi . mock ( '@sim/db' , ( ) => dbChainMock )
5353vi . mock ( '@/lib/workflows/orchestration' , ( ) => workflowsOrchestrationMock )
5454vi . mock ( '@/lib/workflows/utils' , ( ) => workflowsUtilsMock )
5555
5656import { DELETE , PUT } from '@/app/api/folders/[id]/route'
5757
58- interface FolderDbMockOptions {
59- folderLookupResult ?: any
60- updateResult ?: any [ ]
61- throwError ?: boolean
62- circularCheckResults ?: any [ ]
63- }
64-
6558const TEST_USER : MockUser = {
6659 id : 'user-123' ,
6760 email : 'test@example.com' ,
@@ -80,57 +73,16 @@ const mockFolder = {
8073 updatedAt : new Date ( '2024-01-01T00:00:00Z' ) ,
8174}
8275
83- function createFolderDbMock ( options : FolderDbMockOptions = { } ) {
84- const {
85- folderLookupResult = mockFolder ,
86- updateResult = [ { ...mockFolder , name : 'Updated Folder' } ] ,
87- throwError = false ,
88- circularCheckResults = [ ] ,
89- } = options
90-
91- let callCount = 0
92-
93- const mockSelect = vi . fn ( ) . mockImplementation ( ( ) => ( {
94- from : vi . fn ( ) . mockImplementation ( ( ) => ( {
95- where : vi . fn ( ) . mockImplementation ( ( ) => ( {
96- then : vi . fn ( ) . mockImplementation ( ( callback ) => {
97- if ( throwError ) {
98- throw new Error ( 'Database error' )
99- }
100-
101- callCount ++
102- if ( callCount === 1 ) {
103- const result = folderLookupResult === undefined ? [ ] : [ folderLookupResult ]
104- return Promise . resolve ( callback ( result ) )
105- }
106- if ( callCount > 1 && circularCheckResults . length > 0 ) {
107- const index = callCount - 2
108- const result = circularCheckResults [ index ] ? [ circularCheckResults [ index ] ] : [ ]
109- return Promise . resolve ( callback ( result ) )
110- }
111- return Promise . resolve ( callback ( [ ] ) )
112- } ) ,
113- } ) ) ,
114- } ) ) ,
115- } ) )
116-
117- const mockUpdate = vi . fn ( ) . mockImplementation ( ( ) => ( {
118- set : vi . fn ( ) . mockImplementation ( ( ) => ( {
119- where : vi . fn ( ) . mockImplementation ( ( ) => ( {
120- returning : vi . fn ( ) . mockReturnValue ( updateResult ) ,
121- } ) ) ,
122- } ) ) ,
123- } ) )
124-
125- const mockDelete = vi . fn ( ) . mockImplementation ( ( ) => ( {
126- where : vi . fn ( ) . mockImplementation ( ( ) => Promise . resolve ( ) ) ,
127- } ) )
76+ /** Queues the folder-existence lookup the route runs before authorizing. */
77+ function queueFolderLookup ( folder : Record < string , unknown > = mockFolder ) {
78+ queueTableRows ( schemaMock . workflowFolder , [ folder ] )
79+ }
12880
129- return {
130- select : mockSelect ,
131- update : mockUpdate ,
132- delete : mockDelete ,
133- }
81+ /** Makes the next folder lookup throw, exercising the route's 500 path. */
82+ function failFolderLookup ( ) {
83+ dbChainMockFns . where . mockImplementationOnce ( ( ) => {
84+ throw new Error ( 'Database error' )
85+ } )
13486}
13587
13688function mockAuthenticatedUser ( user ?: MockUser ) {
@@ -142,11 +94,15 @@ function mockUnauthenticated() {
14294}
14395
14496describe ( 'Individual Folder API Route' , ( ) => {
97+ afterAll ( ( ) => {
98+ resetDbChainMock ( )
99+ } )
100+
145101 beforeEach ( ( ) => {
146102 vi . clearAllMocks ( )
103+ resetDbChainMock ( )
147104
148105 mockGetUserEntityPermissions . mockResolvedValue ( 'admin' )
149- mockDbRef . current = createFolderDbMock ( )
150106 mockPerformDeleteFolder . mockResolvedValue ( {
151107 success : true ,
152108 deletedItems : { folders : 1 , workflows : 0 } ,
@@ -193,6 +149,7 @@ describe('Individual Folder API Route', () => {
193149 it ( 'should update folder successfully' , async ( ) => {
194150 mockAuthenticatedUser ( )
195151
152+ queueFolderLookup ( )
196153 const req = createMockRequest ( 'PUT' , {
197154 name : 'Updated Folder Name' ,
198155 color : '#FF0000' ,
@@ -213,6 +170,7 @@ describe('Individual Folder API Route', () => {
213170 it ( 'should update parent folder successfully' , async ( ) => {
214171 mockAuthenticatedUser ( )
215172
173+ queueFolderLookup ( )
216174 const req = createMockRequest ( 'PUT' , {
217175 name : 'Updated Folder' ,
218176 parentId : 'parent-folder-1' ,
@@ -244,6 +202,7 @@ describe('Individual Folder API Route', () => {
244202 mockAuthenticatedUser ( )
245203 mockGetUserEntityPermissions . mockResolvedValue ( 'read' )
246204
205+ queueFolderLookup ( )
247206 const req = createMockRequest ( 'PUT' , {
248207 name : 'Updated Folder' ,
249208 } )
@@ -261,6 +220,7 @@ describe('Individual Folder API Route', () => {
261220 mockAuthenticatedUser ( )
262221 mockGetUserEntityPermissions . mockResolvedValue ( 'write' )
263222
223+ queueFolderLookup ( )
264224 const req = createMockRequest ( 'PUT' , {
265225 name : 'Updated Folder' ,
266226 } )
@@ -278,6 +238,7 @@ describe('Individual Folder API Route', () => {
278238 mockAuthenticatedUser ( )
279239 mockGetUserEntityPermissions . mockResolvedValue ( 'admin' )
280240
241+ queueFolderLookup ( )
281242 const req = createMockRequest ( 'PUT' , {
282243 name : 'Updated Folder' ,
283244 } )
@@ -294,6 +255,7 @@ describe('Individual Folder API Route', () => {
294255 it ( 'should return 400 when trying to set folder as its own parent' , async ( ) => {
295256 mockAuthenticatedUser ( )
296257
258+ queueFolderLookup ( )
297259 const req = createMockRequest ( 'PUT' , {
298260 name : 'Updated Folder' ,
299261 parentId : 'folder-1' ,
@@ -311,6 +273,7 @@ describe('Individual Folder API Route', () => {
311273 it ( 'should trim folder name when updating' , async ( ) => {
312274 mockAuthenticatedUser ( )
313275
276+ queueFolderLookup ( )
314277 const req = createMockRequest ( 'PUT' , {
315278 name : ' Folder With Spaces ' ,
316279 } )
@@ -325,9 +288,7 @@ describe('Individual Folder API Route', () => {
325288 it ( 'should handle database errors gracefully' , async ( ) => {
326289 mockAuthenticatedUser ( )
327290
328- mockDbRef . current = createFolderDbMock ( {
329- throwError : true ,
330- } )
291+ failFolderLookup ( )
331292
332293 const req = createMockRequest ( 'PUT' , {
333294 name : 'Updated Folder' ,
@@ -350,6 +311,7 @@ describe('Individual Folder API Route', () => {
350311 it ( 'should handle empty folder name' , async ( ) => {
351312 mockAuthenticatedUser ( )
352313
314+ queueFolderLookup ( )
353315 const req = createMockRequest ( 'PUT' , {
354316 name : '' ,
355317 } )
@@ -383,13 +345,11 @@ describe('Individual Folder API Route', () => {
383345 it ( 'should prevent circular references when updating parent' , async ( ) => {
384346 mockAuthenticatedUser ( )
385347
386- mockDbRef . current = createFolderDbMock ( {
387- folderLookupResult : {
388- id : 'folder-3' ,
389- parentId : null ,
390- name : 'Folder 3' ,
391- workspaceId : 'workspace-123' ,
392- } ,
348+ queueFolderLookup ( {
349+ id : 'folder-3' ,
350+ parentId : null ,
351+ name : 'Folder 3' ,
352+ workspaceId : 'workspace-123' ,
393353 } )
394354
395355 workflowsUtilsMockFns . mockCheckForCircularReference . mockResolvedValue ( true )
@@ -417,9 +377,7 @@ describe('Individual Folder API Route', () => {
417377 it ( 'should delete folder and all contents successfully' , async ( ) => {
418378 mockAuthenticatedUser ( )
419379
420- mockDbRef . current = createFolderDbMock ( {
421- folderLookupResult : mockFolder ,
422- } )
380+ queueFolderLookup ( )
423381
424382 const req = createMockRequest ( 'DELETE' )
425383 const params = Promise . resolve ( { id : 'folder-1' } )
@@ -457,6 +415,7 @@ describe('Individual Folder API Route', () => {
457415 mockAuthenticatedUser ( )
458416 mockGetUserEntityPermissions . mockResolvedValue ( 'read' )
459417
418+ queueFolderLookup ( )
460419 const req = createMockRequest ( 'DELETE' )
461420 const params = Promise . resolve ( { id : 'folder-1' } )
462421
@@ -472,9 +431,7 @@ describe('Individual Folder API Route', () => {
472431 mockAuthenticatedUser ( )
473432 mockGetUserEntityPermissions . mockResolvedValue ( 'write' )
474433
475- mockDbRef . current = createFolderDbMock ( {
476- folderLookupResult : mockFolder ,
477- } )
434+ queueFolderLookup ( )
478435
479436 const req = createMockRequest ( 'DELETE' )
480437 const params = Promise . resolve ( { id : 'folder-1' } )
@@ -492,9 +449,7 @@ describe('Individual Folder API Route', () => {
492449 mockAuthenticatedUser ( )
493450 mockGetUserEntityPermissions . mockResolvedValue ( 'admin' )
494451
495- mockDbRef . current = createFolderDbMock ( {
496- folderLookupResult : mockFolder ,
497- } )
452+ queueFolderLookup ( )
498453
499454 const req = createMockRequest ( 'DELETE' )
500455 const params = Promise . resolve ( { id : 'folder-1' } )
@@ -511,9 +466,7 @@ describe('Individual Folder API Route', () => {
511466 it ( 'should handle database errors during deletion' , async ( ) => {
512467 mockAuthenticatedUser ( )
513468
514- mockDbRef . current = createFolderDbMock ( {
515- throwError : true ,
516- } )
469+ failFolderLookup ( )
517470
518471 const req = createMockRequest ( 'DELETE' )
519472 const params = Promise . resolve ( { id : 'folder-1' } )
0 commit comments