@@ -311,4 +311,107 @@ describe("File Upload", () => {
311311 expect ( input ) . toHaveLength ( 1 ) ;
312312 expect ( input [ 0 ] ) . toHaveAttribute ( 'aria-describedby' , `${ f . id } __longdescription ${ f . id } __shortdescription` )
313313 } )
314- } ) ;
314+
315+ test ( "should allow re-uploading same file after removal" , async ( ) => {
316+ const f = {
317+ ...field ,
318+ type : "file" ,
319+ } ;
320+ const { renderResponse } = await helper ( f ) ;
321+
322+ // Get the file input element directly (like other tests do)
323+ const input = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__widget" ) ;
324+
325+ // 1. Upload initial file
326+ const file = new File ( [ "(⌐□_□)" ] , "test-document.pdf" , { type : "application/pdf" } ) ;
327+ userEvent . upload ( input [ 0 ] as HTMLInputElement , file ) ;
328+
329+ // Verify file was uploaded
330+ expect ( renderResponse . queryByText ( "test-document.pdf" ) ) . toBeTruthy ( ) ;
331+
332+ // 2. Remove the file using the remove button
333+ const removeButton = renderResponse . getByLabelText ( "Remove file" ) ;
334+ userEvent . click ( removeButton ) ;
335+
336+ // Verify file was removed
337+ expect ( renderResponse . queryByText ( "test-document.pdf" ) ) . toBeFalsy ( ) ;
338+
339+ // 3. Re-upload the same file (this tests the bug fix)
340+ const newFile = new File ( [ "(⌐□_□)" ] , "test-document.pdf" , { type : "application/pdf" } ) ;
341+ userEvent . upload ( input [ 0 ] as HTMLInputElement , newFile ) ;
342+
343+ // 4. Verify the same file appears correctly after re-upload
344+ expect ( renderResponse . queryByText ( "test-document.pdf" ) ) . toBeTruthy ( ) ;
345+ } ) ;
346+
347+ test ( "should handle duplicate filenames correctly without removing wrong file" , async ( ) => {
348+ const f = {
349+ ...field ,
350+ type : "file[]" ,
351+ } ;
352+ const { renderResponse } = await helper ( f ) ;
353+
354+ const input = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__widget" ) ;
355+
356+ // Upload first document
357+ const largerContent = Array ( 100 ) . fill ( '(⌐□_□)' ) . join ( '' ) ;
358+ const document1 = new File ( [ largerContent ] , "document.pdf" , { type : "application/pdf" } ) ;
359+ userEvent . upload ( input [ 0 ] as HTMLInputElement , document1 ) ;
360+
361+ // Upload image file to create separation between duplicate names
362+ const imageFile = new File ( [ "image data" ] , "image.jpg" , { type : "image/jpeg" } ) ;
363+ userEvent . upload ( input [ 0 ] as HTMLInputElement , imageFile ) ;
364+
365+ // Upload second document with same filename but different content
366+ const smallerContent = '(⌐□_□)' ;
367+ const document2 = new File ( [ smallerContent ] , "document.pdf" , { type : "application/pdf" } ) ;
368+ userEvent . upload ( input [ 0 ] as HTMLInputElement , document2 ) ;
369+
370+ // Verify all files are present
371+ const fileItems = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__fileitem" ) ;
372+ expect ( fileItems ) . toHaveLength ( 3 ) ;
373+
374+ const fileSizes = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__filesize" ) ;
375+ expect ( fileSizes ) . toHaveLength ( 3 ) ;
376+ const sizeTexts = Array . from ( fileSizes ) . map ( el => el . textContent ) ;
377+ expect ( sizeTexts . filter ( size => size !== sizeTexts [ 0 ] ) ) . toHaveLength ( 2 ) ;
378+
379+ expect ( renderResponse . queryByText ( "image.jpg" ) ) . toBeTruthy ( ) ;
380+
381+ const removeButtons = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__filedelete" ) ;
382+ expect ( removeButtons ) . toHaveLength ( 3 ) ;
383+
384+ // Remove the first uploaded document
385+ userEvent . click ( removeButtons [ 0 ] as HTMLButtonElement ) ;
386+
387+ // Verify exactly 2 files remain
388+ const remainingFileItems = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__fileitem" ) ;
389+ expect ( remainingFileItems ) . toHaveLength ( 2 ) ;
390+
391+ const remainingFileSizes = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__filesize" ) ;
392+ const remainingSizeTexts = Array . from ( remainingFileSizes ) . map ( el => el . textContent ) ;
393+ expect ( remainingSizeTexts ) . toHaveLength ( 2 ) ;
394+
395+ expect ( renderResponse . queryByText ( "image.jpg" ) ) . toBeTruthy ( ) ;
396+ expect ( renderResponse . queryByText ( "document.pdf" ) ) . toBeTruthy ( ) ;
397+
398+ // Remove the image file to verify the second document remains
399+ const updatedRemoveButtons = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__filedelete" ) ;
400+ expect ( updatedRemoveButtons ) . toHaveLength ( 2 ) ;
401+
402+ const imageRemoveButton = Array . from ( updatedRemoveButtons ) . find ( ( button ) => {
403+ const fileItem = button . closest ( '.cmp-adaptiveform-fileinput__fileitem' ) ;
404+ const fileName = fileItem ?. querySelector ( '.cmp-adaptiveform-fileinput__filename' ) ?. textContent ;
405+ return fileName === 'image.jpg' ;
406+ } ) ;
407+ userEvent . click ( imageRemoveButton as HTMLButtonElement ) ;
408+
409+ // Verify only the second document remains
410+ const finalFileItems = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__fileitem" ) ;
411+ expect ( finalFileItems ) . toHaveLength ( 1 ) ;
412+
413+ const finalFileSizes = renderResponse . container . getElementsByClassName ( "cmp-adaptiveform-fileinput__filesize" ) ;
414+ expect ( finalFileSizes ) . toHaveLength ( 1 ) ;
415+ expect ( renderResponse . queryByText ( "image.jpg" ) ) . toBeFalsy ( ) ;
416+ } ) ;
417+ } ) ;
0 commit comments