@scality/data-browser-library 1.0.0-preview.13 → 1.0.0-preview.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/components/DataBrowserUI.d.ts +15 -8
  2. package/dist/components/DataBrowserUI.js +79 -55
  3. package/dist/components/Editor.d.ts +1 -1
  4. package/dist/components/Editor.js +3 -3
  5. package/dist/components/__tests__/BucketCreate.test.js +102 -102
  6. package/dist/components/__tests__/BucketDetails.test.js +121 -122
  7. package/dist/components/__tests__/BucketLifecycleFormPage.test.js +177 -177
  8. package/dist/components/__tests__/BucketLifecycleList.test.js +85 -85
  9. package/dist/components/__tests__/BucketList.test.js +175 -176
  10. package/dist/components/__tests__/BucketNotificationCreatePage.test.js +84 -84
  11. package/dist/components/__tests__/BucketOverview.test.js +256 -200
  12. package/dist/components/__tests__/BucketPolicyPage.test.js +62 -62
  13. package/dist/components/__tests__/BucketReplicationFormPage.test.js +542 -542
  14. package/dist/components/__tests__/BucketReplicationList.test.js +106 -106
  15. package/dist/components/__tests__/CreateFolderButton.test.js +56 -56
  16. package/dist/components/__tests__/DeleteBucketButton.test.js +62 -62
  17. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +47 -47
  18. package/dist/components/__tests__/DeleteObjectButton.test.js +63 -63
  19. package/dist/components/__tests__/EmptyBucketButton.test.js +56 -56
  20. package/dist/components/__tests__/MetadataSearch.test.js +65 -65
  21. package/dist/components/__tests__/ObjectList.test.js +251 -250
  22. package/dist/components/__tests__/UploadButton.test.js +45 -45
  23. package/dist/components/buckets/BucketCreate.d.ts +2 -2
  24. package/dist/components/buckets/BucketCreate.js +41 -41
  25. package/dist/components/buckets/BucketDetails.d.ts +2 -2
  26. package/dist/components/buckets/BucketDetails.js +48 -36
  27. package/dist/components/buckets/BucketLifecycleFormPage.js +161 -160
  28. package/dist/components/buckets/BucketLifecycleList.d.ts +2 -2
  29. package/dist/components/buckets/BucketLifecycleList.js +46 -46
  30. package/dist/components/buckets/BucketList.d.ts +2 -2
  31. package/dist/components/buckets/BucketList.js +28 -27
  32. package/dist/components/buckets/BucketLocation.js +3 -3
  33. package/dist/components/buckets/BucketOverview.d.ts +1 -1
  34. package/dist/components/buckets/BucketOverview.js +62 -62
  35. package/dist/components/buckets/BucketPage.js +19 -11
  36. package/dist/components/buckets/BucketPolicyButton.js +2 -2
  37. package/dist/components/buckets/BucketPolicyPage.js +27 -25
  38. package/dist/components/buckets/BucketReplicationFormPage.js +133 -132
  39. package/dist/components/buckets/BucketReplicationList.d.ts +2 -2
  40. package/dist/components/buckets/BucketReplicationList.js +41 -41
  41. package/dist/components/buckets/BucketVersioning.js +11 -11
  42. package/dist/components/buckets/DeleteBucketButton.js +5 -5
  43. package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +2 -2
  44. package/dist/components/buckets/DeleteBucketConfigRuleButton.js +1 -1
  45. package/dist/components/buckets/EmptyBucketButton.js +19 -19
  46. package/dist/components/buckets/EmptyBucketSummary.d.ts +1 -1
  47. package/dist/components/buckets/EmptyBucketSummary.js +1 -1
  48. package/dist/components/buckets/EmptyBucketSummaryList.js +22 -22
  49. package/dist/components/buckets/__tests__/BucketVersioning.test.js +45 -45
  50. package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +34 -33
  51. package/dist/components/buckets/notifications/EventsSection.js +144 -28
  52. package/dist/components/buckets/notifications/__tests__/events.test.d.ts +1 -0
  53. package/dist/components/buckets/notifications/__tests__/events.test.js +56 -0
  54. package/dist/components/buckets/notifications/events.d.ts +71 -7
  55. package/dist/components/buckets/notifications/events.js +98 -16
  56. package/dist/components/index.d.ts +23 -22
  57. package/dist/components/index.js +3 -2
  58. package/dist/components/layouts/ArrowNavigation.d.ts +1 -2
  59. package/dist/components/layouts/ArrowNavigation.js +3 -3
  60. package/dist/components/layouts/BrowserPageLayout.d.ts +2 -3
  61. package/dist/components/layouts/BrowserPageLayout.js +1 -1
  62. package/dist/components/objects/CreateFolderButton.d.ts +2 -2
  63. package/dist/components/objects/CreateFolderButton.js +9 -9
  64. package/dist/components/objects/DeleteObjectButton.d.ts +1 -1
  65. package/dist/components/objects/DeleteObjectButton.js +20 -20
  66. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +1 -1
  67. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +56 -56
  68. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +1 -1
  69. package/dist/components/objects/ObjectDetails/ObjectSummary.js +39 -39
  70. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +1 -1
  71. package/dist/components/objects/ObjectDetails/ObjectTags.js +25 -25
  72. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.js +119 -119
  73. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.js +211 -211
  74. package/dist/components/objects/ObjectDetails/index.d.ts +1 -1
  75. package/dist/components/objects/ObjectDetails/index.js +30 -30
  76. package/dist/components/objects/ObjectList.d.ts +5 -5
  77. package/dist/components/objects/ObjectList.js +112 -111
  78. package/dist/components/objects/ObjectLock/EditRetentionButton.js +3 -3
  79. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +14 -14
  80. package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +1 -1
  81. package/dist/components/objects/ObjectLock/ObjectLockSettings.js +29 -28
  82. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +1 -1
  83. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +6 -6
  84. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +50 -50
  85. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +77 -77
  86. package/dist/components/objects/ObjectPage.js +5 -4
  87. package/dist/components/objects/UploadButton.d.ts +3 -3
  88. package/dist/components/objects/UploadButton.js +5 -5
  89. package/dist/components/providers/DataBrowserProvider.d.ts +15 -4
  90. package/dist/components/providers/DataBrowserProvider.js +33 -11
  91. package/dist/components/search/MetadataSearch.js +26 -25
  92. package/dist/components/search/SearchHints.js +1 -1
  93. package/dist/components/ui/ArrayFieldActions.js +4 -4
  94. package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +1 -1
  95. package/dist/components/ui/ConfirmDeleteRuleModal.js +1 -1
  96. package/dist/components/ui/DeleteObjectModalContent.d.ts +1 -1
  97. package/dist/components/ui/DeleteObjectModalContent.js +12 -12
  98. package/dist/components/ui/FilterFormSection.d.ts +2 -2
  99. package/dist/components/ui/FilterFormSection.js +29 -29
  100. package/dist/components/ui/Search.elements.d.ts +1 -1
  101. package/dist/components/ui/Search.elements.js +7 -7
  102. package/dist/components/ui/Table.elements.js +5 -5
  103. package/dist/config/factory.d.ts +23 -10
  104. package/dist/config/factory.js +22 -7
  105. package/dist/config/types.d.ts +20 -3
  106. package/dist/contexts/DataBrowserUICustomizationContext.d.ts +2 -2
  107. package/dist/hooks/__tests__/useISVBucketDetection.test.js +41 -41
  108. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +25 -25
  109. package/dist/hooks/bucketConfiguration.d.ts +1 -1
  110. package/dist/hooks/bucketConfiguration.js +48 -48
  111. package/dist/hooks/bucketOperations.d.ts +1 -1
  112. package/dist/hooks/bucketOperations.js +6 -6
  113. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +78 -78
  114. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +78 -78
  115. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +42 -42
  116. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +61 -61
  117. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +63 -63
  118. package/dist/hooks/factories/index.d.ts +4 -4
  119. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +2 -2
  120. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +15 -12
  121. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +2 -2
  122. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +3 -3
  123. package/dist/hooks/factories/useCreateS3MutationHook.js +6 -1
  124. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +2 -2
  125. package/dist/hooks/factories/useCreateS3QueryHook.js +8 -5
  126. package/dist/hooks/index.d.ts +14 -13
  127. package/dist/hooks/index.js +2 -1
  128. package/dist/hooks/loginOperations.d.ts +1 -1
  129. package/dist/hooks/loginOperations.js +1 -1
  130. package/dist/hooks/objectOperations.d.ts +2 -2
  131. package/dist/hooks/objectOperations.js +49 -49
  132. package/dist/hooks/presignedOperations.d.ts +2 -2
  133. package/dist/hooks/presignedOperations.js +3 -3
  134. package/dist/hooks/useBatchObjectLegalHold.js +7 -4
  135. package/dist/hooks/useDataBrowserNavigate.d.ts +14 -0
  136. package/dist/hooks/useDataBrowserNavigate.js +24 -0
  137. package/dist/hooks/useDeleteBucketConfigRule.d.ts +2 -2
  138. package/dist/hooks/useDeleteBucketConfigRule.js +4 -4
  139. package/dist/hooks/useEmptyBucket.js +10 -10
  140. package/dist/hooks/useISVBucketDetection.js +3 -3
  141. package/dist/hooks/useIsBucketEmpty.js +4 -4
  142. package/dist/hooks/useLoginMutation.d.ts +1 -1
  143. package/dist/hooks/useLoginMutation.js +1 -1
  144. package/dist/hooks/useS3Client.d.ts +5 -0
  145. package/dist/hooks/useS3Client.js +3 -2
  146. package/dist/hooks/useS3ConfigSwitch.d.ts +11 -0
  147. package/dist/hooks/useS3ConfigSwitch.js +37 -0
  148. package/dist/index.d.ts +6 -6
  149. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -1
  150. package/dist/test/msw/handlers/deleteBucket.js +20 -10
  151. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -1
  152. package/dist/test/msw/handlers/getBucketAcl.js +29 -17
  153. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -1
  154. package/dist/test/msw/handlers/getBucketLocation.js +29 -15
  155. package/dist/test/msw/handlers/getBucketPolicy.d.ts +1 -1
  156. package/dist/test/msw/handlers/getBucketPolicy.js +52 -32
  157. package/dist/test/msw/handlers/headObject.d.ts +1 -1
  158. package/dist/test/msw/handlers/headObject.js +31 -13
  159. package/dist/test/msw/handlers/listBuckets.d.ts +1 -1
  160. package/dist/test/msw/handlers/listBuckets.js +5 -3
  161. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -1
  162. package/dist/test/msw/handlers/listObjectVersions.js +38 -26
  163. package/dist/test/msw/handlers/listObjects.d.ts +1 -1
  164. package/dist/test/msw/handlers/listObjects.js +35 -23
  165. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -1
  166. package/dist/test/msw/handlers/objectLegalHold.js +31 -16
  167. package/dist/test/msw/handlers/objectRetention.d.ts +1 -1
  168. package/dist/test/msw/handlers/objectRetention.js +31 -17
  169. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -1
  170. package/dist/test/msw/handlers/putBucketAcl.js +29 -14
  171. package/dist/test/msw/handlers/putObject.d.ts +1 -1
  172. package/dist/test/msw/handlers/putObject.js +27 -12
  173. package/dist/test/msw/handlers.d.ts +3 -3
  174. package/dist/test/msw/handlers.js +72 -49
  175. package/dist/test/msw/index.d.ts +2 -2
  176. package/dist/test/msw/server.d.ts +1 -1
  177. package/dist/test/msw/server.js +1 -1
  178. package/dist/test/msw/utils.js +2 -2
  179. package/dist/test/setup.d.ts +1 -1
  180. package/dist/test/setup.js +19 -19
  181. package/dist/test/testUtils.d.ts +9 -15
  182. package/dist/test/testUtils.js +78 -92
  183. package/dist/test/utils/errorHandling.test.js +119 -119
  184. package/dist/types/index.d.ts +6 -31
  185. package/dist/utils/__tests__/s3ConfigIdentifier.test.d.ts +1 -0
  186. package/dist/utils/__tests__/s3ConfigIdentifier.test.js +429 -0
  187. package/dist/utils/constants.js +8 -8
  188. package/dist/utils/deletion/index.d.ts +2 -2
  189. package/dist/utils/deletion/messages.d.ts +1 -1
  190. package/dist/utils/deletion/messages.js +4 -4
  191. package/dist/utils/errorHandling.d.ts +3 -3
  192. package/dist/utils/errorHandling.js +6 -6
  193. package/dist/utils/hooks.js +8 -8
  194. package/dist/utils/index.d.ts +5 -4
  195. package/dist/utils/index.js +2 -0
  196. package/dist/utils/proxyMiddleware.d.ts +1 -1
  197. package/dist/utils/proxyMiddleware.js +6 -11
  198. package/dist/utils/s3Client.d.ts +2 -2
  199. package/dist/utils/s3Client.js +1 -1
  200. package/dist/utils/s3ConfigIdentifier.d.ts +68 -0
  201. package/dist/utils/s3ConfigIdentifier.js +55 -0
  202. package/dist/utils/s3RuleUtils.d.ts +5 -5
  203. package/dist/utils/s3RuleUtils.js +17 -17
  204. package/dist/utils/useSupportedNotificationEvents.d.ts +6 -0
  205. package/dist/utils/useSupportedNotificationEvents.js +7 -0
  206. package/package.json +2 -2
@@ -28,52 +28,52 @@ const renderObjectList = (props = {}, customization)=>{
28
28
  })
29
29
  }));
30
30
  };
31
- describe("ObjectList", ()=>{
31
+ describe('ObjectList', ()=>{
32
32
  beforeEach(()=>{
33
33
  jest.clearAllMocks();
34
34
  mockOffsetSize(800, 600);
35
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(false);
35
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(false);
36
36
  });
37
37
  afterEach(()=>{
38
38
  jest.restoreAllMocks();
39
39
  });
40
- describe("Basic Rendering", ()=>{
41
- it("shows a table with proper headers", async ()=>{
40
+ describe('Basic Rendering', ()=>{
41
+ it('shows a table with proper headers', async ()=>{
42
42
  renderObjectList();
43
43
  await waitFor(()=>{
44
- expect(screen.getByRole("grid")).toBeInTheDocument();
44
+ expect(screen.getByRole('grid')).toBeInTheDocument();
45
45
  });
46
- expect(screen.getByText("Name")).toBeInTheDocument();
47
- expect(screen.getByText("Modified on")).toBeInTheDocument();
48
- expect(screen.getByText("Size")).toBeInTheDocument();
49
- expect(screen.getByText("Storage Location")).toBeInTheDocument();
46
+ expect(screen.getByText('Name')).toBeInTheDocument();
47
+ expect(screen.getByText('Modified on')).toBeInTheDocument();
48
+ expect(screen.getByText('Size')).toBeInTheDocument();
49
+ expect(screen.getByText('Storage Location')).toBeInTheDocument();
50
50
  });
51
- it("renders empty state for empty bucket", async ()=>{
51
+ it('renders empty state for empty bucket', async ()=>{
52
52
  renderObjectList({
53
- bucketName: "empty-bucket"
53
+ bucketName: 'empty-bucket'
54
54
  });
55
55
  await waitFor(()=>{
56
- expect(screen.getByRole("grid")).toBeInTheDocument();
56
+ expect(screen.getByRole('grid')).toBeInTheDocument();
57
57
  });
58
- expect(screen.getByText("Name")).toBeInTheDocument();
59
- const rows = screen.getAllByRole("row");
58
+ expect(screen.getByText('Name')).toBeInTheDocument();
59
+ const rows = screen.getAllByRole('row');
60
60
  expect(rows.length).toBe(1);
61
- expect(screen.queryByText("file1.txt")).not.toBeInTheDocument();
62
- expect(screen.queryByText("folder1/")).not.toBeInTheDocument();
61
+ expect(screen.queryByText('file1.txt')).not.toBeInTheDocument();
62
+ expect(screen.queryByText('folder1/')).not.toBeInTheDocument();
63
63
  });
64
- it("handles loading states correctly", async ()=>{
64
+ it('handles loading states correctly', async ()=>{
65
65
  renderObjectList();
66
- expect(screen.getByRole("grid")).toBeInTheDocument();
66
+ expect(screen.getByRole('grid')).toBeInTheDocument();
67
67
  await waitFor(()=>{
68
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
68
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
69
69
  });
70
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
71
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
72
- expect(screen.getByText("folder1/")).toBeInTheDocument();
70
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
71
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
72
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
73
73
  });
74
74
  });
75
- describe("Content Display", ()=>{
76
- it("renders content and handles interactions", async ()=>{
75
+ describe('Content Display', ()=>{
76
+ it('renders content and handles interactions', async ()=>{
77
77
  const onObjectSelect = jest.fn();
78
78
  const onPrefixChange = jest.fn();
79
79
  renderObjectList({
@@ -81,122 +81,123 @@ describe("ObjectList", ()=>{
81
81
  onPrefixChange
82
82
  });
83
83
  await waitFor(()=>{
84
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
84
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
85
85
  });
86
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
87
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
88
- expect(screen.getByText("folder1/")).toBeInTheDocument();
89
- fireEvent.click(screen.getByText("folder1/"));
90
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
91
- const rows = screen.getAllByRole("row");
86
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
87
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
88
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
89
+ fireEvent.click(screen.getByText('folder1/'));
90
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
91
+ const rows = screen.getAllByRole('row');
92
92
  expect(rows.length).toBe(4);
93
93
  });
94
- it("displays data formatting correctly", async ()=>{
94
+ it('displays data formatting correctly', async ()=>{
95
95
  renderObjectList();
96
96
  await waitFor(()=>{
97
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
97
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
98
98
  });
99
- const gridElement = screen.getByRole("grid");
100
- expect(gridElement).toHaveTextContent("2023");
99
+ const gridElement = screen.getByRole('grid');
100
+ expect(gridElement).toHaveTextContent('2023');
101
101
  const dateElements = screen.getAllByText(/2023/);
102
102
  expect(dateElements.length).toBeGreaterThanOrEqual(2);
103
- expect(screen.getByText("1 KB")).toBeInTheDocument();
104
- expect(screen.getByText("512 B")).toBeInTheDocument();
105
- const defaultElements = screen.getAllByText("default");
103
+ expect(screen.getByText('1 KB')).toBeInTheDocument();
104
+ expect(screen.getByText('512 B')).toBeInTheDocument();
105
+ const defaultElements = screen.getAllByText('default');
106
106
  expect(defaultElements.length).toBeGreaterThan(0);
107
- const dashes = screen.getAllByText("-");
107
+ const dashes = screen.getAllByText('-');
108
108
  expect(dashes.length).toBeGreaterThanOrEqual(2);
109
109
  });
110
- it("displays correct icons for folders and files", async ()=>{
110
+ it('displays correct icons for folders and files', async ()=>{
111
111
  renderObjectList();
112
112
  await waitFor(()=>{
113
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
113
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
114
114
  });
115
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
116
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
117
- expect(screen.getByText("folder1/")).toBeInTheDocument();
118
- const nameCells = screen.getAllByRole("gridcell").filter((cell)=>cell.textContent?.includes("folder1/") || cell.textContent?.includes("file1.txt") || cell.textContent?.includes("file2.txt"));
115
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
116
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
117
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
118
+ const nameCells = screen.getAllByRole('gridcell').filter((cell)=>cell.textContent?.includes('folder1/') || cell.textContent?.includes('file1.txt') || cell.textContent?.includes('file2.txt'));
119
119
  expect(nameCells.length).toBe(3);
120
120
  nameCells.forEach((cell)=>{
121
- const iconElement = cell.querySelector("svg, img, i");
122
- const linkElement = cell.querySelector("a");
121
+ const iconElement = cell.querySelector('svg, img, i');
122
+ const linkElement = cell.querySelector('a');
123
123
  expect(iconElement).toBeInTheDocument();
124
124
  expect(linkElement).toBeInTheDocument();
125
125
  });
126
126
  });
127
- it("removes prefix from displayed names correctly", async ()=>{
127
+ it('removes prefix from displayed names correctly', async ()=>{
128
128
  renderObjectList({
129
- prefix: "my-prefix/subfolder/",
130
- bucketName: "test-bucket"
129
+ prefix: 'my-prefix/subfolder/',
130
+ bucketName: 'test-bucket'
131
131
  });
132
132
  await waitFor(()=>{
133
- expect(screen.getByRole("grid")).toBeInTheDocument();
133
+ expect(screen.getByRole('grid')).toBeInTheDocument();
134
134
  });
135
- expect(screen.getByText("Name")).toBeInTheDocument();
135
+ expect(screen.getByText('Name')).toBeInTheDocument();
136
136
  });
137
137
  });
138
- describe("Interaction Behaviors", ()=>{
139
- it("prevents event propagation when clicking links", async ()=>{
138
+ describe('Interaction Behaviors', ()=>{
139
+ it('prevents event propagation when clicking links', async ()=>{
140
140
  const onPrefixChange = jest.fn();
141
141
  renderObjectList({
142
142
  onPrefixChange
143
143
  });
144
144
  await waitFor(()=>{
145
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
146
- expect(screen.getByText("folder1/")).toBeInTheDocument();
145
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
146
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
147
147
  });
148
- fireEvent.click(screen.getByText("folder1/"));
149
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
148
+ fireEvent.click(screen.getByText('folder1/'));
149
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
150
150
  expect(onPrefixChange).toHaveBeenCalledTimes(1);
151
151
  });
152
- it("supports prefix-based navigation", async ()=>{
152
+ it('supports prefix-based navigation', async ()=>{
153
153
  const onPrefixChange = jest.fn();
154
154
  renderObjectList({
155
155
  onPrefixChange
156
156
  });
157
157
  await waitFor(()=>{
158
- expect(screen.getByText("folder1/")).toBeInTheDocument();
158
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
159
159
  });
160
- fireEvent.click(screen.getByText("folder1/"));
161
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
160
+ fireEvent.click(screen.getByText('folder1/'));
161
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
162
162
  expect(onPrefixChange).toHaveBeenCalledTimes(1);
163
163
  });
164
- it("handles folder navigation correctly", async ()=>{
164
+ it('handles folder navigation correctly', async ()=>{
165
165
  const onPrefixChange = jest.fn();
166
166
  renderObjectList({
167
167
  onPrefixChange
168
168
  });
169
169
  await waitFor(()=>{
170
- expect(screen.getByText("folder1/")).toBeInTheDocument();
170
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
171
171
  });
172
- fireEvent.click(screen.getByText("folder1/"));
173
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
172
+ fireEvent.click(screen.getByText('folder1/'));
173
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
174
174
  });
175
175
  });
176
- describe("Pagination and Infinite Scroll", ()=>{
177
- it("handles infinite scroll pagination correctly", async ()=>{
176
+ describe('Pagination and Infinite Scroll', ()=>{
177
+ it('handles infinite scroll pagination correctly', async ()=>{
178
178
  renderObjectList({
179
- bucketName: "paginated-bucket"
179
+ bucketName: 'paginated-bucket'
180
180
  });
181
181
  await waitFor(()=>{
182
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
182
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
183
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
184
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
183
185
  });
184
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
185
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
186
- expect(screen.getByText("folder1/")).toBeInTheDocument();
187
- expect(screen.queryByText("file3.txt")).not.toBeInTheDocument();
188
- const table = screen.getByRole("grid");
186
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
187
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
188
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
189
+ const table = screen.getByRole('grid');
189
190
  expect(table).toBeInTheDocument();
190
- const rows = screen.getAllByRole("row");
191
- expect(rows.length).toBe(4);
192
- expect(screen.getByText("1 KB")).toBeInTheDocument();
193
- expect(screen.getByText("512 B")).toBeInTheDocument();
191
+ const rows = screen.getAllByRole('row');
192
+ expect(rows.length).toBeGreaterThanOrEqual(4);
193
+ expect(screen.getByText('1 KB')).toBeInTheDocument();
194
+ expect(screen.getByText('512 B')).toBeInTheDocument();
194
195
  });
195
- it("integrates with infinite query hook for data loading", async ()=>{
196
+ it('integrates with infinite query hook for data loading', async ()=>{
196
197
  const { result } = renderHook(()=>useListObjects({
197
- Bucket: "paginated-bucket",
198
+ Bucket: 'paginated-bucket',
198
199
  MaxKeys: 20,
199
- Delimiter: "/"
200
+ Delimiter: '/'
200
201
  }), {
201
202
  wrapper: createTestWrapper()
202
203
  });
@@ -205,7 +206,7 @@ describe("ObjectList", ()=>{
205
206
  });
206
207
  expect(result.current.data).toBeDefined();
207
208
  expect(result.current.hasNextPage).toBe(true);
208
- expect(typeof result.current.fetchNextPage).toBe("function");
209
+ expect(typeof result.current.fetchNextPage).toBe('function');
209
210
  expect(result.current.isFetchingNextPage).toBe(false);
210
211
  const firstPage = result.current.data?.pages[0];
211
212
  expect(firstPage).toBeDefined();
@@ -222,41 +223,41 @@ describe("ObjectList", ()=>{
222
223
  expect(result.current.hasNextPage).toBe(false);
223
224
  });
224
225
  });
225
- describe("Version Management", ()=>{
226
- it("renders List Versions toggle", async ()=>{
226
+ describe('Version Management', ()=>{
227
+ it('renders List Versions toggle', async ()=>{
227
228
  renderObjectList();
228
229
  await waitFor(()=>{
229
- expect(screen.getByText("List Versions")).toBeInTheDocument();
230
+ expect(screen.getByText('List Versions')).toBeInTheDocument();
230
231
  });
231
232
  const toggleLabel = screen.getByText(/list versions/i);
232
- const toggle = toggleLabel.closest("label")?.querySelector('input[type="checkbox"]');
233
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
233
234
  expect(toggle).toBeInTheDocument();
234
235
  expect(toggle).not.toBeChecked();
235
236
  });
236
- it("shows Version ID column when toggle is enabled", async ()=>{
237
+ it('shows Version ID column when toggle is enabled', async ()=>{
237
238
  renderObjectList();
238
239
  await waitFor(()=>{
239
- expect(screen.getByText("List Versions")).toBeInTheDocument();
240
+ expect(screen.getByText('List Versions')).toBeInTheDocument();
240
241
  });
241
242
  const toggleLabel = screen.getByText(/list versions/i);
242
- const toggle = toggleLabel.closest("label")?.querySelector('input[type="checkbox"]');
243
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
243
244
  fireEvent.click(toggle);
244
245
  await waitFor(()=>{
245
- expect(screen.getByText("Version ID")).toBeInTheDocument();
246
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
246
247
  });
247
248
  });
248
- it("does not show Version ID column by default", async ()=>{
249
+ it('does not show Version ID column by default', async ()=>{
249
250
  renderObjectList();
250
251
  await waitFor(()=>{
251
- expect(screen.getByText("Name")).toBeInTheDocument();
252
+ expect(screen.getByText('Name')).toBeInTheDocument();
252
253
  });
253
- expect(screen.queryByText("Version ID")).not.toBeInTheDocument();
254
+ expect(screen.queryByText('Version ID')).not.toBeInTheDocument();
254
255
  });
255
- it("integrates with version listing hook", async ()=>{
256
+ it('integrates with version listing hook', async ()=>{
256
257
  const { result } = renderHook(()=>useListObjectVersions({
257
- Bucket: "test-bucket",
258
+ Bucket: 'test-bucket',
258
259
  MaxKeys: 20,
259
- Delimiter: "/"
260
+ Delimiter: '/'
260
261
  }), {
261
262
  wrapper: createTestWrapper()
262
263
  });
@@ -264,66 +265,66 @@ describe("ObjectList", ()=>{
264
265
  expect(result.current.isSuccess).toBe(true);
265
266
  });
266
267
  expect(result.current.data).toBeDefined();
267
- expect(typeof result.current.fetchNextPage).toBe("function");
268
+ expect(typeof result.current.fetchNextPage).toBe('function');
268
269
  const firstPage = result.current.data?.pages[0];
269
270
  expect(firstPage).toBeDefined();
270
271
  });
271
- it("clears selections when toggling versions", async ()=>{
272
+ it('clears selections when toggling versions', async ()=>{
272
273
  renderObjectList();
273
274
  await waitFor(()=>{
274
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
275
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
275
276
  });
276
277
  const toggleLabel = screen.getByText(/list versions/i);
277
- const toggle = toggleLabel.closest("label")?.querySelector('input[type="checkbox"]');
278
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
278
279
  fireEvent.click(toggle);
279
280
  await waitFor(()=>{
280
- expect(screen.getByText("Version ID")).toBeInTheDocument();
281
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
281
282
  });
282
283
  });
283
284
  });
284
- describe("Search Features", ()=>{
285
- it("renders table search when metadata-search feature is disabled", async ()=>{
286
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(false);
285
+ describe('Search Features', ()=>{
286
+ it('renders table search when metadata-search feature is disabled', async ()=>{
287
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(false);
287
288
  renderObjectList();
288
289
  await waitFor(()=>{
289
- expect(screen.getByRole("grid")).toBeInTheDocument();
290
+ expect(screen.getByRole('grid')).toBeInTheDocument();
290
291
  });
291
292
  expect(screen.queryByPlaceholderText(/Metadata Search/i)).not.toBeInTheDocument();
292
293
  });
293
- it("renders MetadataSearch component when metadata-search feature is enabled", async ()=>{
294
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(true);
294
+ it('renders MetadataSearch component when metadata-search feature is enabled', async ()=>{
295
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(true);
295
296
  renderObjectList();
296
297
  await waitFor(()=>{
297
- expect(screen.getByRole("grid")).toBeInTheDocument();
298
+ expect(screen.getByRole('grid')).toBeInTheDocument();
298
299
  });
299
300
  expect(screen.getByPlaceholderText(/Metadata Search/i)).toBeInTheDocument();
300
301
  });
301
302
  });
302
- describe("Multi-Selection", ()=>{
303
- it("integrates with MultiSelectableContent", async ()=>{
303
+ describe('Multi-Selection', ()=>{
304
+ it('integrates with MultiSelectableContent', async ()=>{
304
305
  renderObjectList();
305
306
  await waitFor(()=>{
306
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
307
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
307
308
  });
308
- expect(screen.getByRole("grid")).toBeInTheDocument();
309
- const rows = screen.getAllByRole("row");
309
+ expect(screen.getByRole('grid')).toBeInTheDocument();
310
+ const rows = screen.getAllByRole('row');
310
311
  expect(rows.length).toBe(4);
311
- const checkboxes = screen.getAllByRole("checkbox");
312
+ const checkboxes = screen.getAllByRole('checkbox');
312
313
  expect(checkboxes.length).toBeGreaterThan(0);
313
314
  });
314
- it("handles multi-selection state changes", async ()=>{
315
+ it('handles multi-selection state changes', async ()=>{
315
316
  renderObjectList();
316
317
  await waitFor(()=>{
317
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
318
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
318
319
  });
319
- const checkboxes = screen.getAllByRole("checkbox");
320
+ const checkboxes = screen.getAllByRole('checkbox');
320
321
  expect(checkboxes.length).toBeGreaterThan(0);
321
322
  const firstCheckbox = checkboxes[0];
322
323
  expect(firstCheckbox).not.toBeChecked();
323
324
  fireEvent.click(firstCheckbox);
324
325
  expect(firstCheckbox).toBeChecked();
325
326
  });
326
- it("clears selections when prefix changes", async ()=>{
327
+ it('clears selections when prefix changes', async ()=>{
327
328
  const { rerender } = render(/*#__PURE__*/ jsx(MemoryRouter, {
328
329
  children: (()=>{
329
330
  const Wrapper = createTestWrapper();
@@ -345,9 +346,9 @@ describe("ObjectList", ()=>{
345
346
  })()
346
347
  }));
347
348
  await waitFor(()=>{
348
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
349
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
349
350
  });
350
- const checkboxesBefore = screen.getAllByRole("checkbox");
351
+ const checkboxesBefore = screen.getAllByRole('checkbox');
351
352
  expect(checkboxesBefore.length).toBeGreaterThan(0);
352
353
  const firstCheckbox = checkboxesBefore[1];
353
354
  fireEvent.click(firstCheckbox);
@@ -373,74 +374,74 @@ describe("ObjectList", ()=>{
373
374
  })()
374
375
  }));
375
376
  await waitFor(()=>{
376
- expect(screen.getByRole("grid")).toBeInTheDocument();
377
+ expect(screen.getByRole('grid')).toBeInTheDocument();
377
378
  });
378
- const checkboxesAfter = screen.getAllByRole("checkbox");
379
+ const checkboxesAfter = screen.getAllByRole('checkbox');
379
380
  checkboxesAfter.forEach((checkbox)=>{
380
381
  expect(checkbox).not.toBeChecked();
381
382
  });
382
383
  });
383
384
  });
384
- describe("Action Buttons", ()=>{
385
- it("renders upload and create folder buttons", async ()=>{
385
+ describe('Action Buttons', ()=>{
386
+ it('renders upload and create folder buttons', async ()=>{
386
387
  renderObjectList();
387
388
  await waitFor(()=>{
388
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
389
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
389
390
  });
390
- expect(screen.getByText("Upload")).toBeInTheDocument();
391
- expect(screen.getByRole("button", {
391
+ expect(screen.getByText('Upload')).toBeInTheDocument();
392
+ expect(screen.getByRole('button', {
392
393
  name: /folder/i
393
394
  })).toBeInTheDocument();
394
395
  });
395
- it("renders delete button", async ()=>{
396
+ it('renders delete button', async ()=>{
396
397
  renderObjectList();
397
398
  await waitFor(()=>{
398
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
399
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
399
400
  });
400
- expect(screen.getByText("Delete")).toBeInTheDocument();
401
+ expect(screen.getByText('Delete')).toBeInTheDocument();
401
402
  });
402
403
  });
403
- describe("Error Handling", ()=>{
404
- it("handles errors gracefully", async ()=>{
405
- const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
404
+ describe('Error Handling', ()=>{
405
+ it('handles errors gracefully', async ()=>{
406
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
406
407
  expect(()=>{
407
408
  renderObjectList();
408
409
  }).not.toThrow();
409
410
  await waitFor(()=>{
410
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
411
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
411
412
  });
412
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
413
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
413
414
  consoleErrorSpy.mockRestore();
414
415
  });
415
416
  });
416
- describe("Column Sorting", ()=>{
417
- it("sorts folders before files", async ()=>{
417
+ describe('Column Sorting', ()=>{
418
+ it('sorts folders before files', async ()=>{
418
419
  renderObjectList();
419
420
  await waitFor(()=>{
420
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
421
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
421
422
  });
422
- const rows = screen.getAllByRole("row");
423
+ const rows = screen.getAllByRole('row');
423
424
  const dataRows = rows.slice(1);
424
- const firstRowText = dataRows[0]?.textContent || "";
425
- expect(firstRowText).toContain("folder1/");
425
+ const firstRowText = dataRows[0]?.textContent || '';
426
+ expect(firstRowText).toContain('folder1/');
426
427
  });
427
- it("sorts items alphabetically within their type", async ()=>{
428
+ it('sorts items alphabetically within their type', async ()=>{
428
429
  renderObjectList();
429
430
  await waitFor(()=>{
430
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
431
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
431
432
  });
432
- const rows = screen.getAllByRole("row");
433
+ const rows = screen.getAllByRole('row');
433
434
  const dataRows = rows.slice(1);
434
- const fileRows = dataRows.filter((row)=>row.textContent?.includes("file") && !row.textContent?.includes("folder"));
435
+ const fileRows = dataRows.filter((row)=>row.textContent?.includes('file') && !row.textContent?.includes('folder'));
435
436
  expect(fileRows.length).toBeGreaterThanOrEqual(2);
436
- const firstFileName = fileRows[0]?.textContent || "";
437
- const secondFileName = fileRows[1]?.textContent || "";
438
- expect(firstFileName.includes("file1")).toBe(true);
439
- expect(secondFileName.includes("file2")).toBe(true);
437
+ const firstFileName = fileRows[0]?.textContent || '';
438
+ const secondFileName = fileRows[1]?.textContent || '';
439
+ expect(firstFileName.includes('file1')).toBe(true);
440
+ expect(secondFileName.includes('file2')).toBe(true);
440
441
  });
441
442
  });
442
- describe("Customization", ()=>{
443
- it("supports custom columns", async ()=>{
443
+ describe('Customization', ()=>{
444
+ it('supports custom columns', async ()=>{
444
445
  const CustomCell = ({ data })=>/*#__PURE__*/ jsxs("div", {
445
446
  children: [
446
447
  "Custom: ",
@@ -450,20 +451,20 @@ describe("ObjectList", ()=>{
450
451
  const customization = {
451
452
  extraObjectListColumns: [
452
453
  {
453
- id: "custom",
454
- header: "Custom Column",
454
+ id: 'custom',
455
+ header: 'Custom Column',
455
456
  render: CustomCell,
456
- width: "200px"
457
+ width: '200px'
457
458
  }
458
459
  ],
459
460
  extraObjectListActions: []
460
461
  };
461
462
  renderObjectList({}, customization);
462
463
  await waitFor(()=>{
463
- expect(screen.getByText("Custom Column")).toBeInTheDocument();
464
+ expect(screen.getByText('Custom Column')).toBeInTheDocument();
464
465
  });
465
466
  });
466
- it("supports custom actions", async ()=>{
467
+ it('supports custom actions', async ()=>{
467
468
  const CustomAction = ()=>/*#__PURE__*/ jsx("button", {
468
469
  children: "Custom Action"
469
470
  });
@@ -471,17 +472,17 @@ describe("ObjectList", ()=>{
471
472
  extraObjectListColumns: [],
472
473
  extraObjectListActions: [
473
474
  {
474
- id: "customAction",
475
+ id: 'customAction',
475
476
  render: CustomAction
476
477
  }
477
478
  ]
478
479
  };
479
480
  renderObjectList({}, customization);
480
481
  await waitFor(()=>{
481
- expect(screen.getByText("Custom Action")).toBeInTheDocument();
482
+ expect(screen.getByText('Custom Action')).toBeInTheDocument();
482
483
  });
483
484
  });
484
- it("allows overriding default columns", async ()=>{
485
+ it('allows overriding default columns', async ()=>{
485
486
  const CustomNameCell = ({ data })=>/*#__PURE__*/ jsxs("div", {
486
487
  children: [
487
488
  "Override: ",
@@ -491,8 +492,8 @@ describe("ObjectList", ()=>{
491
492
  const customization = {
492
493
  extraObjectListColumns: [
493
494
  {
494
- id: "name",
495
- header: "Custom Name",
495
+ id: 'name',
496
+ header: 'Custom Name',
496
497
  render: CustomNameCell
497
498
  }
498
499
  ],
@@ -500,27 +501,27 @@ describe("ObjectList", ()=>{
500
501
  };
501
502
  renderObjectList({}, customization);
502
503
  await waitFor(()=>{
503
- expect(screen.getByText("Custom Name")).toBeInTheDocument();
504
+ expect(screen.getByText('Custom Name')).toBeInTheDocument();
504
505
  });
505
506
  });
506
507
  });
507
- describe("Edge Cases", ()=>{
508
- it("handles edge cases gracefully", async ()=>{
508
+ describe('Edge Cases', ()=>{
509
+ it('handles edge cases gracefully', async ()=>{
509
510
  const mockOnPrefixChange = jest.fn();
510
511
  renderObjectList({
511
512
  onPrefixChange: mockOnPrefixChange
512
513
  });
513
514
  await waitFor(()=>{
514
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
515
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
515
516
  });
516
517
  expect(()=>{
517
- fireEvent.click(screen.getByText("folder1/"));
518
+ fireEvent.click(screen.getByText('folder1/'));
518
519
  }).not.toThrow();
519
520
  expect(mockOnPrefixChange).toHaveBeenCalled();
520
521
  });
521
522
  });
522
- describe("Callback Stability", ()=>{
523
- it("maintains stable callback references", async ()=>{
523
+ describe('Callback Stability', ()=>{
524
+ it('maintains stable callback references', async ()=>{
524
525
  const onPrefixChange = jest.fn();
525
526
  const { rerender } = render(/*#__PURE__*/ jsx(MemoryRouter, {
526
527
  children: (()=>{
@@ -543,9 +544,9 @@ describe("ObjectList", ()=>{
543
544
  })()
544
545
  }));
545
546
  await waitFor(()=>{
546
- expect(screen.getByText("folder1/")).toBeInTheDocument();
547
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
547
548
  });
548
- fireEvent.click(screen.getByText("folder1/"));
549
+ fireEvent.click(screen.getByText('folder1/'));
549
550
  expect(onPrefixChange).toHaveBeenCalledTimes(1);
550
551
  const firstCallArgs = onPrefixChange.mock.calls[0];
551
552
  rerender(/*#__PURE__*/ jsx(MemoryRouter, {
@@ -569,215 +570,215 @@ describe("ObjectList", ()=>{
569
570
  })()
570
571
  }));
571
572
  await waitFor(()=>{
572
- expect(screen.getByText("folder1/")).toBeInTheDocument();
573
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
573
574
  });
574
- fireEvent.click(screen.getByText("folder1/"));
575
+ fireEvent.click(screen.getByText('folder1/'));
575
576
  expect(onPrefixChange).toHaveBeenCalledTimes(2);
576
577
  const secondCallArgs = onPrefixChange.mock.calls[1];
577
578
  expect(secondCallArgs[0]).toEqual(firstCallArgs[0]);
578
579
  });
579
580
  });
580
- describe("File Download", ()=>{
581
+ describe('File Download', ()=>{
581
582
  beforeEach(()=>{
582
583
  mockOffsetSize(800, 600);
583
584
  });
584
- it("triggers download when clicking on file name without errors", async ()=>{
585
+ it('triggers download when clicking on file name without errors', async ()=>{
585
586
  renderObjectList();
586
587
  await waitFor(()=>{
587
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
588
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
588
589
  });
589
- const fileLink = screen.getByText("file1.txt");
590
+ const fileLink = screen.getByText('file1.txt');
590
591
  expect(()=>{
591
592
  fireEvent.click(fileLink);
592
593
  }).not.toThrow();
593
594
  });
594
- it("does not download folders - navigates to prefix instead", async ()=>{
595
+ it('does not download folders - navigates to prefix instead', async ()=>{
595
596
  const onPrefixChange = jest.fn();
596
597
  renderObjectList({
597
598
  onPrefixChange
598
599
  });
599
600
  await waitFor(()=>{
600
- expect(screen.getByText("folder1/")).toBeInTheDocument();
601
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
601
602
  });
602
- const folderLink = screen.getByText("folder1/");
603
+ const folderLink = screen.getByText('folder1/');
603
604
  fireEvent.click(folderLink);
604
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
605
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
605
606
  });
606
- it("supports clicking on different files independently", async ()=>{
607
+ it('supports clicking on different files independently', async ()=>{
607
608
  renderObjectList();
608
609
  await waitFor(()=>{
609
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
610
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
610
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
611
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
611
612
  });
612
- const file1Link = screen.getByText("file1.txt");
613
- const file2Link = screen.getByText("file2.txt");
613
+ const file1Link = screen.getByText('file1.txt');
614
+ const file2Link = screen.getByText('file2.txt');
614
615
  expect(()=>{
615
616
  fireEvent.click(file1Link);
616
617
  fireEvent.click(file2Link);
617
618
  }).not.toThrow();
618
619
  });
619
- it("renders file and folder names as clickable links", async ()=>{
620
+ it('renders file and folder names as clickable links', async ()=>{
620
621
  renderObjectList();
621
622
  await waitFor(()=>{
622
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
623
- expect(screen.getByText("folder1/")).toBeInTheDocument();
623
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
624
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
624
625
  });
625
- const fileLink = screen.getByText("file1.txt");
626
- const folderLink = screen.getByText("folder1/");
627
- expect(fileLink.closest("a")).toBeInTheDocument();
628
- expect(folderLink.closest("a")).toBeInTheDocument();
626
+ const fileLink = screen.getByText('file1.txt');
627
+ const folderLink = screen.getByText('folder1/');
628
+ expect(fileLink.closest('a')).toBeInTheDocument();
629
+ expect(folderLink.closest('a')).toBeInTheDocument();
629
630
  });
630
- it("handles download errors gracefully", async ()=>{
631
- const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
631
+ it('handles download errors gracefully', async ()=>{
632
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
632
633
  renderObjectList();
633
634
  await waitFor(()=>{
634
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
635
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
635
636
  });
636
637
  expect(()=>{
637
- fireEvent.click(screen.getByText("file1.txt"));
638
+ fireEvent.click(screen.getByText('file1.txt'));
638
639
  }).not.toThrow();
639
640
  consoleErrorSpy.mockRestore();
640
641
  });
641
642
  });
642
- describe("Accessibility", ()=>{
643
- it("renders file and folder names as clickable links", async ()=>{
643
+ describe('Accessibility', ()=>{
644
+ it('renders file and folder names as clickable links', async ()=>{
644
645
  renderObjectList();
645
646
  await waitFor(()=>{
646
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
647
- expect(screen.getByText("folder1/")).toBeInTheDocument();
647
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
648
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
648
649
  });
649
- const fileLink = screen.getByText("file1.txt").closest("a");
650
- const folderLink = screen.getByText("folder1/").closest("a");
650
+ const fileLink = screen.getByText('file1.txt').closest('a');
651
+ const folderLink = screen.getByText('folder1/').closest('a');
651
652
  expect(fileLink).toBeInTheDocument();
652
653
  expect(folderLink).toBeInTheDocument();
653
654
  });
654
- it("provides focusable links for keyboard navigation", async ()=>{
655
+ it('provides focusable links for keyboard navigation', async ()=>{
655
656
  renderObjectList();
656
657
  await waitFor(()=>{
657
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
658
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
658
659
  });
659
- const fileLink = screen.getByText("file1.txt").closest("a");
660
+ const fileLink = screen.getByText('file1.txt').closest('a');
660
661
  expect(fileLink).toBeInTheDocument();
661
- expect(fileLink?.tagName.toLowerCase()).toBe("a");
662
+ expect(fileLink?.tagName.toLowerCase()).toBe('a');
662
663
  });
663
- it("ensures interactive elements are keyboard accessible", async ()=>{
664
+ it('ensures interactive elements are keyboard accessible', async ()=>{
664
665
  renderObjectList();
665
666
  await waitFor(()=>{
666
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
667
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
667
668
  });
668
- const fileLink = screen.getByText("file1.txt").closest("a");
669
- const folderLink = screen.getByText("folder1/").closest("a");
669
+ const fileLink = screen.getByText('file1.txt').closest('a');
670
+ const folderLink = screen.getByText('folder1/').closest('a');
670
671
  expect(fileLink).toBeInTheDocument();
671
672
  expect(folderLink).toBeInTheDocument();
672
673
  if (fileLink) {
673
- const tabIndex = fileLink.getAttribute("tabindex");
674
+ const tabIndex = fileLink.getAttribute('tabindex');
674
675
  if (null !== tabIndex) expect(parseInt(tabIndex, 10)).toBeGreaterThanOrEqual(-1);
675
676
  }
676
677
  if (folderLink) {
677
- const tabIndex = folderLink.getAttribute("tabindex");
678
+ const tabIndex = folderLink.getAttribute('tabindex');
678
679
  if (null !== tabIndex) expect(parseInt(tabIndex, 10)).toBeGreaterThanOrEqual(-1);
679
680
  }
680
681
  });
681
- it("provides keyboard interaction for Enter key on file links", async ()=>{
682
+ it('provides keyboard interaction for Enter key on file links', async ()=>{
682
683
  renderObjectList();
683
684
  await waitFor(()=>{
684
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
685
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
685
686
  });
686
- const fileLink = screen.getByText("file1.txt").closest("a");
687
- if (!fileLink) throw new Error("File link not found");
687
+ const fileLink = screen.getByText('file1.txt').closest('a');
688
+ if (!fileLink) throw new Error('File link not found');
688
689
  expect(()=>{
689
690
  fireEvent.keyDown(fileLink, {
690
- key: "Enter",
691
- code: "Enter"
691
+ key: 'Enter',
692
+ code: 'Enter'
692
693
  });
693
694
  }).not.toThrow();
694
695
  });
695
- it("provides keyboard interaction for Space key on folder links", async ()=>{
696
+ it('provides keyboard interaction for Space key on folder links', async ()=>{
696
697
  const onPrefixChange = jest.fn();
697
698
  renderObjectList({
698
699
  onPrefixChange
699
700
  });
700
701
  await waitFor(()=>{
701
- expect(screen.getByText("folder1/")).toBeInTheDocument();
702
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
702
703
  });
703
- const folderLink = screen.getByText("folder1/").closest("a");
704
- if (!folderLink) throw new Error("Folder link not found");
704
+ const folderLink = screen.getByText('folder1/').closest('a');
705
+ if (!folderLink) throw new Error('Folder link not found');
705
706
  fireEvent.keyDown(folderLink, {
706
- key: " ",
707
- code: "Space"
707
+ key: ' ',
708
+ code: 'Space'
708
709
  });
709
710
  fireEvent.click(folderLink);
710
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
711
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
711
712
  });
712
- it("has proper ARIA roles for the table structure", async ()=>{
713
+ it('has proper ARIA roles for the table structure', async ()=>{
713
714
  renderObjectList();
714
715
  await waitFor(()=>{
715
- expect(screen.getByRole("grid")).toBeInTheDocument();
716
+ expect(screen.getByRole('grid')).toBeInTheDocument();
716
717
  });
717
- const gridElement = screen.getByRole("grid");
718
+ const gridElement = screen.getByRole('grid');
718
719
  expect(gridElement).toBeInTheDocument();
719
- const rows = screen.getAllByRole("row");
720
+ const rows = screen.getAllByRole('row');
720
721
  expect(rows.length).toBeGreaterThan(0);
721
722
  });
722
723
  });
723
- describe("Error Scenarios", ()=>{
724
+ describe('Error Scenarios', ()=>{
724
725
  let consoleErrorSpy;
725
726
  beforeEach(()=>{
726
- consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
727
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
727
728
  });
728
729
  afterEach(()=>{
729
730
  consoleErrorSpy.mockRestore();
730
731
  });
731
- it("continues to function when download initiation fails", async ()=>{
732
+ it('continues to function when download initiation fails', async ()=>{
732
733
  renderObjectList();
733
734
  await waitFor(()=>{
734
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
735
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
735
736
  });
736
- const fileLink = screen.getByText("file1.txt");
737
+ const fileLink = screen.getByText('file1.txt');
737
738
  fireEvent.click(fileLink);
738
739
  fireEvent.click(fileLink);
739
740
  expect(()=>{
740
741
  fireEvent.click(fileLink);
741
742
  }).not.toThrow();
742
743
  await waitFor(()=>{
743
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
744
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
744
745
  });
745
746
  });
746
- it("handles rapid clicking without breaking the UI", async ()=>{
747
+ it('handles rapid clicking without breaking the UI', async ()=>{
747
748
  renderObjectList();
748
749
  await waitFor(()=>{
749
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
750
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
750
751
  });
751
- const fileLink = screen.getByText("file1.txt");
752
+ const fileLink = screen.getByText('file1.txt');
752
753
  for(let i = 0; i < 10; i++)fireEvent.click(fileLink);
753
754
  await waitFor(()=>{
754
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
755
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
755
756
  });
756
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
757
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
757
758
  });
758
- it("properly invokes navigation callbacks", async ()=>{
759
+ it('properly invokes navigation callbacks', async ()=>{
759
760
  const onPrefixChange = jest.fn();
760
761
  renderObjectList({
761
762
  onPrefixChange
762
763
  });
763
764
  await waitFor(()=>{
764
- expect(screen.getByText("folder1/")).toBeInTheDocument();
765
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
765
766
  });
766
- const folderLink = screen.getByText("folder1/");
767
+ const folderLink = screen.getByText('folder1/');
767
768
  fireEvent.click(folderLink);
768
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
769
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
769
770
  expect(onPrefixChange).toHaveBeenCalledTimes(1);
770
771
  });
771
- it("recovers gracefully from failed async operations", async ()=>{
772
+ it('recovers gracefully from failed async operations', async ()=>{
772
773
  renderObjectList();
773
774
  await waitFor(()=>{
774
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
775
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
775
776
  });
776
- fireEvent.click(screen.getByText("file1.txt"));
777
+ fireEvent.click(screen.getByText('file1.txt'));
777
778
  await waitFor(()=>{
778
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
779
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
779
780
  });
780
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
781
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
781
782
  });
782
783
  });
783
784
  });