@scality/data-browser-library 1.0.0-preview.9 → 1.0.1

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 (285) hide show
  1. package/dist/components/DataBrowserUI.d.ts +12 -0
  2. package/dist/components/DataBrowserUI.js +99 -0
  3. package/dist/components/Editor.d.ts +1 -1
  4. package/dist/components/Editor.js +3 -3
  5. package/dist/components/__tests__/BucketAccessor.test.js +214 -0
  6. package/dist/components/__tests__/BucketCorsPage.test.d.ts +1 -0
  7. package/dist/components/__tests__/BucketCorsPage.test.js +263 -0
  8. package/dist/components/__tests__/BucketCreate.test.js +271 -105
  9. package/dist/components/__tests__/BucketDetails.test.d.ts +1 -0
  10. package/dist/components/__tests__/BucketDetails.test.js +421 -0
  11. package/dist/components/__tests__/BucketLifecycleFormPage.test.d.ts +13 -0
  12. package/dist/components/__tests__/BucketLifecycleFormPage.test.js +178 -178
  13. package/dist/components/__tests__/BucketLifecycleList.test.js +85 -85
  14. package/dist/components/__tests__/BucketList.test.js +463 -239
  15. package/dist/components/__tests__/BucketNotificationFormPage.test.d.ts +1 -0
  16. package/dist/components/__tests__/BucketNotificationFormPage.test.js +348 -0
  17. package/dist/components/__tests__/BucketNotificationList.test.d.ts +1 -0
  18. package/dist/components/__tests__/BucketNotificationList.test.js +379 -0
  19. package/dist/components/__tests__/BucketOverview.test.js +281 -266
  20. package/dist/components/__tests__/BucketPolicyPage.test.js +151 -99
  21. package/dist/components/__tests__/BucketReplicationFormPage.test.d.ts +15 -0
  22. package/dist/components/__tests__/BucketReplicationFormPage.test.js +544 -544
  23. package/dist/components/__tests__/BucketReplicationList.test.js +106 -106
  24. package/dist/components/__tests__/CreateFolderButton.test.js +56 -56
  25. package/dist/components/__tests__/DeleteBucketButton.test.js +64 -64
  26. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +47 -47
  27. package/dist/components/__tests__/DeleteObjectButton.test.js +64 -64
  28. package/dist/components/__tests__/EmptyBucketButton.test.js +59 -59
  29. package/dist/components/__tests__/MetadataSearch.test.js +65 -65
  30. package/dist/components/__tests__/ObjectList.test.js +741 -240
  31. package/dist/components/__tests__/UploadButton.test.js +45 -45
  32. package/dist/components/breadcrumb/Breadcrumb.d.ts +6 -0
  33. package/dist/components/breadcrumb/Breadcrumb.js +37 -0
  34. package/dist/components/breadcrumb/DataBrowserBreadcrumb.d.ts +1 -0
  35. package/dist/components/breadcrumb/DataBrowserBreadcrumb.js +10 -0
  36. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.d.ts +1 -0
  37. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.js +196 -0
  38. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.d.ts +1 -0
  39. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.js +153 -0
  40. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.d.ts +1 -0
  41. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.js +134 -0
  42. package/dist/components/breadcrumb/index.d.ts +8 -0
  43. package/dist/components/breadcrumb/index.js +4 -0
  44. package/dist/components/breadcrumb/useBreadcrumbPaths.d.ts +2 -0
  45. package/dist/components/breadcrumb/useBreadcrumbPaths.js +82 -0
  46. package/dist/components/buckets/BucketAccessor.d.ts +2 -0
  47. package/dist/components/buckets/BucketAccessor.js +125 -0
  48. package/dist/components/buckets/BucketConfigEditButton.d.ts +8 -0
  49. package/dist/components/buckets/{BucketPolicyButton.js → BucketConfigEditButton.js} +9 -5
  50. package/dist/components/buckets/BucketCorsPage.d.ts +1 -0
  51. package/dist/components/buckets/BucketCorsPage.js +234 -0
  52. package/dist/components/buckets/BucketCreate.d.ts +3 -2
  53. package/dist/components/buckets/BucketCreate.js +89 -47
  54. package/dist/components/buckets/BucketDetails.d.ts +42 -0
  55. package/dist/components/buckets/BucketDetails.js +249 -85
  56. package/dist/components/buckets/BucketLifecycleFormPage.js +206 -190
  57. package/dist/components/buckets/BucketLifecycleList.d.ts +2 -2
  58. package/dist/components/buckets/BucketLifecycleList.js +47 -47
  59. package/dist/components/buckets/BucketList.d.ts +7 -8
  60. package/dist/components/buckets/BucketList.js +158 -101
  61. package/dist/components/buckets/BucketLocation.js +4 -4
  62. package/dist/components/buckets/BucketOverview.d.ts +22 -2
  63. package/dist/components/buckets/BucketOverview.js +394 -187
  64. package/dist/components/buckets/BucketPage.js +43 -21
  65. package/dist/components/buckets/BucketPolicyPage.js +155 -127
  66. package/dist/components/buckets/BucketReplicationFormPage.js +134 -133
  67. package/dist/components/buckets/BucketReplicationList.d.ts +2 -2
  68. package/dist/components/buckets/BucketReplicationList.js +42 -42
  69. package/dist/components/buckets/BucketVersioning.d.ts +4 -0
  70. package/dist/components/buckets/BucketVersioning.js +76 -0
  71. package/dist/components/buckets/DeleteBucketButton.js +8 -8
  72. package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +2 -2
  73. package/dist/components/buckets/DeleteBucketConfigRuleButton.js +2 -2
  74. package/dist/components/buckets/EmptyBucketButton.js +24 -24
  75. package/dist/components/buckets/EmptyBucketSummary.d.ts +2 -2
  76. package/dist/components/buckets/EmptyBucketSummary.js +1 -1
  77. package/dist/components/buckets/EmptyBucketSummaryList.d.ts +1 -1
  78. package/dist/components/buckets/EmptyBucketSummaryList.js +22 -22
  79. package/dist/components/buckets/__tests__/BucketVersioning.test.d.ts +1 -0
  80. package/dist/components/buckets/__tests__/BucketVersioning.test.js +163 -0
  81. package/dist/components/buckets/notifications/BucketNotificationFormPage.d.ts +1 -0
  82. package/dist/components/buckets/notifications/BucketNotificationFormPage.js +316 -0
  83. package/dist/components/buckets/notifications/BucketNotificationList.d.ts +10 -0
  84. package/dist/components/buckets/notifications/BucketNotificationList.js +267 -0
  85. package/dist/components/buckets/notifications/EventsSection.js +145 -29
  86. package/dist/components/buckets/notifications/__tests__/events.test.d.ts +1 -0
  87. package/dist/components/buckets/notifications/__tests__/events.test.js +56 -0
  88. package/dist/components/buckets/notifications/events.d.ts +71 -7
  89. package/dist/components/buckets/notifications/events.js +98 -16
  90. package/dist/components/index.d.ts +27 -20
  91. package/dist/components/index.js +17 -10
  92. package/dist/components/layouts/ArrowNavigation.d.ts +3 -0
  93. package/dist/components/layouts/ArrowNavigation.js +28 -0
  94. package/dist/components/layouts/BrowserPageLayout.d.ts +5 -1
  95. package/dist/components/layouts/BrowserPageLayout.js +10 -5
  96. package/dist/components/objects/CreateFolderButton.d.ts +2 -2
  97. package/dist/components/objects/CreateFolderButton.js +12 -12
  98. package/dist/components/objects/DeleteObjectButton.d.ts +1 -1
  99. package/dist/components/objects/DeleteObjectButton.js +19 -21
  100. package/dist/components/objects/GetPresignedUrlButton.d.ts +7 -0
  101. package/dist/components/objects/GetPresignedUrlButton.js +255 -0
  102. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -2
  103. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +263 -230
  104. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +2 -2
  105. package/dist/components/objects/ObjectDetails/ObjectSummary.js +540 -138
  106. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +2 -2
  107. package/dist/components/objects/ObjectDetails/ObjectTags.js +95 -123
  108. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.d.ts +1 -0
  109. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.js +516 -0
  110. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.d.ts +1 -0
  111. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.js +1064 -0
  112. package/dist/components/objects/ObjectDetails/index.d.ts +18 -2
  113. package/dist/components/objects/ObjectDetails/index.js +152 -40
  114. package/dist/components/objects/ObjectList.d.ts +12 -10
  115. package/dist/components/objects/ObjectList.js +590 -263
  116. package/dist/components/objects/ObjectLock/EditRetentionButton.js +4 -4
  117. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +15 -15
  118. package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +1 -1
  119. package/dist/components/objects/ObjectLock/ObjectLockSettings.js +32 -31
  120. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +1 -1
  121. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +6 -6
  122. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +51 -51
  123. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +78 -78
  124. package/dist/components/objects/ObjectPage.js +12 -8
  125. package/dist/components/objects/UploadButton.d.ts +3 -3
  126. package/dist/components/objects/UploadButton.js +10 -10
  127. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.d.ts +1 -0
  128. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.js +531 -0
  129. package/dist/components/providers/DataBrowserProvider.d.ts +23 -12
  130. package/dist/components/providers/DataBrowserProvider.js +60 -38
  131. package/dist/components/providers/QueryProvider.d.ts +9 -0
  132. package/dist/components/providers/QueryProvider.js +21 -0
  133. package/dist/components/search/MetadataSearch.js +29 -28
  134. package/dist/components/search/SearchHints.js +1 -1
  135. package/dist/components/ui/ArrayFieldActions.js +12 -7
  136. package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +2 -2
  137. package/dist/components/ui/ConfirmDeleteRuleModal.js +6 -1
  138. package/dist/components/ui/DeleteObjectModalContent.d.ts +1 -1
  139. package/dist/components/ui/DeleteObjectModalContent.js +12 -12
  140. package/dist/components/ui/FilterFormSection.d.ts +2 -2
  141. package/dist/components/ui/FilterFormSection.js +29 -29
  142. package/dist/components/ui/Search.elements.d.ts +2 -2
  143. package/dist/components/ui/Search.elements.js +7 -7
  144. package/dist/components/ui/Table.elements.d.ts +2 -1
  145. package/dist/components/ui/Table.elements.js +18 -12
  146. package/dist/config/__tests__/factory.test.d.ts +1 -0
  147. package/dist/config/__tests__/factory.test.js +311 -0
  148. package/dist/config/factory.d.ts +10 -56
  149. package/dist/config/factory.js +23 -71
  150. package/dist/config/types.d.ts +212 -34
  151. package/dist/contexts/DataBrowserUICustomizationContext.d.ts +27 -0
  152. package/dist/contexts/DataBrowserUICustomizationContext.js +13 -0
  153. package/dist/hooks/__tests__/useAccessibleBuckets.test.d.ts +1 -0
  154. package/dist/hooks/__tests__/useAccessibleBuckets.test.js +145 -0
  155. package/dist/hooks/__tests__/useISVBucketDetection.test.js +45 -45
  156. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +27 -27
  157. package/dist/hooks/__tests__/useLoginMutation.test.d.ts +1 -0
  158. package/dist/hooks/__tests__/useLoginMutation.test.js +194 -0
  159. package/dist/hooks/bucketConfiguration.d.ts +8 -1
  160. package/dist/hooks/bucketConfiguration.js +52 -51
  161. package/dist/hooks/bucketOperations.d.ts +10 -1
  162. package/dist/hooks/bucketOperations.js +10 -9
  163. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +80 -80
  164. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +80 -80
  165. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +44 -44
  166. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +63 -63
  167. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +65 -65
  168. package/dist/hooks/factories/index.d.ts +4 -4
  169. package/dist/hooks/factories/index.js +2 -2
  170. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +2 -2
  171. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +16 -13
  172. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +2 -2
  173. package/dist/hooks/factories/useCreateS3LoginHook.js +1 -1
  174. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +3 -3
  175. package/dist/hooks/factories/useCreateS3MutationHook.js +7 -2
  176. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +2 -2
  177. package/dist/hooks/factories/useCreateS3QueryHook.js +11 -6
  178. package/dist/hooks/index.d.ts +19 -12
  179. package/dist/hooks/index.js +16 -9
  180. package/dist/hooks/loginOperations.d.ts +1 -1
  181. package/dist/hooks/loginOperations.js +1 -1
  182. package/dist/hooks/objectOperations.d.ts +2 -2
  183. package/dist/hooks/objectOperations.js +50 -49
  184. package/dist/hooks/presignedOperations.d.ts +4 -4
  185. package/dist/hooks/presignedOperations.js +5 -5
  186. package/dist/hooks/useAccessibleBuckets.d.ts +11 -0
  187. package/dist/hooks/useAccessibleBuckets.js +115 -0
  188. package/dist/hooks/useBatchObjectLegalHold.d.ts +11 -0
  189. package/dist/hooks/useBatchObjectLegalHold.js +48 -0
  190. package/dist/hooks/useBucketConfigEditor.d.ts +31 -0
  191. package/dist/hooks/useBucketConfigEditor.js +82 -0
  192. package/dist/hooks/useDataBrowserNavigate.d.ts +28 -0
  193. package/dist/hooks/useDataBrowserNavigate.js +24 -0
  194. package/dist/hooks/useDeleteBucketConfigRule.d.ts +2 -2
  195. package/dist/hooks/useDeleteBucketConfigRule.js +4 -4
  196. package/dist/hooks/useEmptyBucket.js +11 -11
  197. package/dist/hooks/useFeatures.d.ts +7 -0
  198. package/dist/hooks/useFeatures.js +8 -0
  199. package/dist/hooks/useISVBucketDetection.js +6 -6
  200. package/dist/hooks/useIsBucketEmpty.js +4 -4
  201. package/dist/hooks/useLimitedAccessFlow.d.ts +48 -0
  202. package/dist/hooks/useLimitedAccessFlow.js +23 -0
  203. package/dist/hooks/useS3Client.d.ts +6 -0
  204. package/dist/hooks/useS3Client.js +3 -2
  205. package/dist/hooks/useS3ConfigSwitch.d.ts +11 -0
  206. package/dist/hooks/useS3ConfigSwitch.js +37 -0
  207. package/dist/hooks/useSupportedNotificationEvents.d.ts +6 -0
  208. package/dist/hooks/useSupportedNotificationEvents.js +8 -0
  209. package/dist/index.d.ts +6 -6
  210. package/dist/index.js +2 -2
  211. package/dist/schemas/bucketPolicySchema.json +3 -13
  212. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -1
  213. package/dist/test/msw/handlers/deleteBucket.js +20 -10
  214. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -1
  215. package/dist/test/msw/handlers/getBucketAcl.js +29 -17
  216. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -1
  217. package/dist/test/msw/handlers/getBucketLocation.js +29 -15
  218. package/dist/test/msw/handlers/getBucketPolicy.d.ts +1 -1
  219. package/dist/test/msw/handlers/getBucketPolicy.js +52 -32
  220. package/dist/test/msw/handlers/headObject.d.ts +1 -1
  221. package/dist/test/msw/handlers/headObject.js +31 -13
  222. package/dist/test/msw/handlers/listBuckets.d.ts +1 -1
  223. package/dist/test/msw/handlers/listBuckets.js +5 -3
  224. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -1
  225. package/dist/test/msw/handlers/listObjectVersions.js +38 -26
  226. package/dist/test/msw/handlers/listObjects.d.ts +1 -1
  227. package/dist/test/msw/handlers/listObjects.js +35 -23
  228. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -1
  229. package/dist/test/msw/handlers/objectLegalHold.js +32 -17
  230. package/dist/test/msw/handlers/objectRetention.d.ts +1 -1
  231. package/dist/test/msw/handlers/objectRetention.js +31 -17
  232. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -1
  233. package/dist/test/msw/handlers/putBucketAcl.js +29 -14
  234. package/dist/test/msw/handlers/putObject.d.ts +1 -1
  235. package/dist/test/msw/handlers/putObject.js +27 -12
  236. package/dist/test/msw/handlers.d.ts +3 -3
  237. package/dist/test/msw/handlers.js +77 -54
  238. package/dist/test/msw/index.d.ts +2 -2
  239. package/dist/test/msw/index.js +1 -1
  240. package/dist/test/msw/server.d.ts +1 -1
  241. package/dist/test/msw/server.js +1 -1
  242. package/dist/test/msw/utils.js +2 -2
  243. package/dist/test/setup.d.ts +1 -1
  244. package/dist/test/setup.js +13 -30
  245. package/dist/test/testUtils.d.ts +85 -33
  246. package/dist/test/testUtils.js +176 -111
  247. package/dist/test/utils/errorHandling.test.js +119 -119
  248. package/dist/types/index.d.ts +49 -36
  249. package/dist/types/monaco.d.ts +13 -0
  250. package/dist/types/monaco.js +0 -0
  251. package/dist/utils/__tests__/proxyMiddleware.test.d.ts +1 -0
  252. package/dist/utils/__tests__/proxyMiddleware.test.js +579 -0
  253. package/dist/utils/__tests__/s3Client.test.d.ts +1 -0
  254. package/dist/utils/__tests__/s3Client.test.js +340 -0
  255. package/dist/utils/__tests__/s3ConfigIdentifier.test.d.ts +1 -0
  256. package/dist/utils/__tests__/s3ConfigIdentifier.test.js +437 -0
  257. package/dist/utils/constants.d.ts +10 -0
  258. package/dist/utils/constants.js +19 -9
  259. package/dist/utils/deletion/index.d.ts +2 -2
  260. package/dist/utils/deletion/index.js +1 -1
  261. package/dist/utils/deletion/messages.d.ts +1 -1
  262. package/dist/utils/deletion/messages.js +4 -4
  263. package/dist/utils/errorHandling.d.ts +3 -3
  264. package/dist/utils/errorHandling.js +6 -6
  265. package/dist/utils/hooks.js +8 -8
  266. package/dist/utils/index.d.ts +5 -4
  267. package/dist/utils/index.js +4 -2
  268. package/dist/utils/proxyMiddleware.d.ts +32 -13
  269. package/dist/utils/proxyMiddleware.js +90 -36
  270. package/dist/utils/s3Client.d.ts +14 -4
  271. package/dist/utils/s3Client.js +5 -26
  272. package/dist/utils/s3ConfigIdentifier.d.ts +79 -0
  273. package/dist/utils/s3ConfigIdentifier.js +57 -0
  274. package/dist/utils/s3RuleUtils.d.ts +5 -5
  275. package/dist/utils/s3RuleUtils.js +17 -17
  276. package/package.json +10 -8
  277. package/dist/components/__tests__/BucketNotificationCreatePage.test.js +0 -316
  278. package/dist/components/buckets/BucketPolicyButton.d.ts +0 -7
  279. package/dist/components/buckets/notifications/BucketNotificationCreatePage.d.ts +0 -1
  280. package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +0 -234
  281. package/dist/hooks/useLoginMutation.d.ts +0 -21
  282. package/dist/hooks/useLoginMutation.js +0 -9
  283. package/dist/utils/useFeatures.d.ts +0 -1
  284. package/dist/utils/useFeatures.js +0 -7
  285. /package/dist/components/__tests__/{BucketNotificationCreatePage.test.d.ts → BucketAccessor.test.d.ts} +0 -0
@@ -0,0 +1,1064 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useToast } from "@scality/core-ui";
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { cleanup, render, screen, waitFor } from "@testing-library/react";
5
+ import user_event from "@testing-library/user-event";
6
+ import { DataBrowserUICustomizationProvider } from "../../../../contexts/DataBrowserUICustomizationContext.js";
7
+ import { useGetPresignedDownload, useGetPublicAccessBlock, useObjectAcl, useObjectLegalHold, useObjectMetadata, useObjectRetention, useSetObjectAcl, useSetObjectLegalHold } from "../../../../hooks/index.js";
8
+ import { findToggleByLabel } from "../../../../test/testUtils.js";
9
+ import { ObjectSummary } from "../ObjectSummary.js";
10
+ jest.mock('../../../../hooks');
11
+ jest.mock('@scality/core-ui', ()=>{
12
+ const actual = jest.requireActual('@scality/core-ui');
13
+ return {
14
+ ...actual,
15
+ useToast: jest.fn()
16
+ };
17
+ });
18
+ jest.mock('../../../providers/DataBrowserProvider', ()=>({
19
+ ...jest.requireActual('../../../providers/DataBrowserProvider'),
20
+ useDataBrowserConfig: jest.fn(()=>({
21
+ endpoint: 'https://s3.example.com',
22
+ forcePathStyle: false
23
+ }))
24
+ }));
25
+ const mockUseObjectMetadata = jest.mocked(useObjectMetadata);
26
+ const mockUseObjectLegalHold = jest.mocked(useObjectLegalHold);
27
+ const mockUseObjectRetention = jest.mocked(useObjectRetention);
28
+ const mockUseSetObjectLegalHold = jest.mocked(useSetObjectLegalHold);
29
+ const mockUseObjectAcl = jest.mocked(useObjectAcl);
30
+ const mockUseSetObjectAcl = jest.mocked(useSetObjectAcl);
31
+ const mockUseGetPublicAccessBlock = jest.mocked(useGetPublicAccessBlock);
32
+ const mockUseGetPresignedDownload = jest.mocked(useGetPresignedDownload);
33
+ const mockUseToast = jest.mocked(useToast);
34
+ const mockObjectMetadata = {
35
+ VersionId: 'test-version-id',
36
+ ContentLength: 1024,
37
+ LastModified: new Date('2024-01-01'),
38
+ ETag: '"abc123def456"'
39
+ };
40
+ const mockLegalHoldData = {
41
+ LegalHold: {
42
+ Status: 'OFF'
43
+ }
44
+ };
45
+ const mockRetentionData = {
46
+ Retention: {
47
+ Mode: 'GOVERNANCE',
48
+ RetainUntilDate: '2024-12-31T23:59:59Z'
49
+ }
50
+ };
51
+ const mockAclDataPrivate = {
52
+ Grants: [
53
+ {
54
+ Grantee: {
55
+ Type: 'CanonicalUser',
56
+ ID: 'owner-id'
57
+ },
58
+ Permission: 'FULL_CONTROL'
59
+ }
60
+ ]
61
+ };
62
+ const mockPublicAccessBlockData = {
63
+ PublicAccessBlockConfiguration: {
64
+ BlockPublicAcls: false,
65
+ IgnorePublicAcls: false
66
+ }
67
+ };
68
+ const setupMockDefaults = ()=>{
69
+ mockUseObjectMetadata.mockReturnValue({
70
+ data: mockObjectMetadata,
71
+ status: 'success'
72
+ });
73
+ mockUseObjectLegalHold.mockReturnValue({
74
+ data: mockLegalHoldData,
75
+ status: 'success'
76
+ });
77
+ mockUseObjectRetention.mockReturnValue({
78
+ data: mockRetentionData,
79
+ status: 'success'
80
+ });
81
+ mockUseSetObjectLegalHold.mockReturnValue({
82
+ mutate: jest.fn(),
83
+ isPending: false
84
+ });
85
+ mockUseObjectAcl.mockReturnValue({
86
+ data: mockAclDataPrivate,
87
+ status: 'success'
88
+ });
89
+ mockUseSetObjectAcl.mockReturnValue({
90
+ mutate: jest.fn(),
91
+ isPending: false
92
+ });
93
+ mockUseGetPublicAccessBlock.mockReturnValue({
94
+ data: mockPublicAccessBlockData,
95
+ status: 'success'
96
+ });
97
+ mockUseGetPresignedDownload.mockReturnValue({
98
+ mutateAsync: jest.fn(),
99
+ isPending: false
100
+ });
101
+ mockUseToast.mockReturnValue({
102
+ showToast: jest.fn()
103
+ });
104
+ };
105
+ const getLegalHoldToggle = ()=>findToggleByLabel('Legal Hold');
106
+ const getPublicToggle = ()=>findToggleByLabel('Public');
107
+ const expectTooltipOnHover = async (element, expectedText)=>{
108
+ const user = user_event.setup();
109
+ await user.hover(element);
110
+ await waitFor(()=>{
111
+ expect(screen.getByText(expectedText)).toBeInTheDocument();
112
+ });
113
+ };
114
+ const renderWithProviders = (ui, { customizationConfig = {} } = {})=>{
115
+ const queryClient = new QueryClient({
116
+ defaultOptions: {
117
+ queries: {
118
+ retry: false
119
+ },
120
+ mutations: {
121
+ retry: false
122
+ }
123
+ }
124
+ });
125
+ return render(/*#__PURE__*/ jsx(QueryClientProvider, {
126
+ client: queryClient,
127
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
128
+ config: customizationConfig,
129
+ children: ui
130
+ })
131
+ }));
132
+ };
133
+ describe('ObjectSummary', ()=>{
134
+ const defaultProps = {
135
+ bucketName: 'test-bucket',
136
+ objectKey: 'test-object.txt'
137
+ };
138
+ beforeEach(()=>{
139
+ jest.clearAllMocks();
140
+ setupMockDefaults();
141
+ });
142
+ describe('Default Fields', ()=>{
143
+ describe('Information Section', ()=>{
144
+ it('should render all default information fields', ()=>{
145
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
146
+ ...defaultProps
147
+ }));
148
+ expect(screen.getByText('Information')).toBeInTheDocument();
149
+ expect(screen.getByText('Name')).toBeInTheDocument();
150
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
151
+ expect(screen.getByText('Size')).toBeInTheDocument();
152
+ expect(screen.getByText('Modified On')).toBeInTheDocument();
153
+ expect(screen.getByText('ETag')).toBeInTheDocument();
154
+ expect(screen.getByText('Location')).toBeInTheDocument();
155
+ expect(screen.getByText('Access')).toBeInTheDocument();
156
+ });
157
+ it('should display object name', ()=>{
158
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
159
+ ...defaultProps
160
+ }));
161
+ expect(screen.getByText('test-object.txt')).toBeInTheDocument();
162
+ });
163
+ it('should display version ID from metadata', ()=>{
164
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
165
+ ...defaultProps
166
+ }));
167
+ expect(screen.getByText('test-version-id')).toBeInTheDocument();
168
+ });
169
+ it('should display formatted size', ()=>{
170
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
171
+ ...defaultProps
172
+ }));
173
+ expect(screen.getByText(/1 KB/i)).toBeInTheDocument();
174
+ });
175
+ it('should display formatted date', ()=>{
176
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
177
+ ...defaultProps
178
+ }));
179
+ const dateElements = screen.getAllByText(/2024/);
180
+ expect(dateElements.length).toBeGreaterThan(0);
181
+ });
182
+ it('should display ETag without quotes', ()=>{
183
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
184
+ ...defaultProps
185
+ }));
186
+ expect(screen.getByText('abc123def456')).toBeInTheDocument();
187
+ });
188
+ it('should display default location', ()=>{
189
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
190
+ ...defaultProps
191
+ }));
192
+ expect(screen.getByText('default')).toBeInTheDocument();
193
+ });
194
+ });
195
+ describe('Data Protection Section', ()=>{
196
+ it('should render data protection section', ()=>{
197
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
198
+ ...defaultProps
199
+ }));
200
+ expect(screen.getByText('Data protection')).toBeInTheDocument();
201
+ });
202
+ it('should display retention lock information', ()=>{
203
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
204
+ ...defaultProps
205
+ }));
206
+ expect(screen.getByText('Lock')).toBeInTheDocument();
207
+ expect(screen.getByText(/GOVERNANCE/)).toBeInTheDocument();
208
+ expect(screen.getByText(/until/)).toBeInTheDocument();
209
+ });
210
+ it('should display legal hold toggle when available', ()=>{
211
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
212
+ ...defaultProps
213
+ }));
214
+ expect(screen.getByText('Legal Hold')).toBeInTheDocument();
215
+ expect(getLegalHoldToggle()).toBeInTheDocument();
216
+ });
217
+ it('should show legal hold as inactive by default', ()=>{
218
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
219
+ ...defaultProps
220
+ }));
221
+ const toggle = getLegalHoldToggle();
222
+ expect(toggle).not.toBeChecked();
223
+ });
224
+ });
225
+ });
226
+ describe('Loading States', ()=>{
227
+ it('should show loader for pending metadata', ()=>{
228
+ mockUseObjectMetadata.mockReturnValueOnce({
229
+ data: void 0,
230
+ status: 'pending'
231
+ });
232
+ const { container } = renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
233
+ ...defaultProps
234
+ }));
235
+ const loaders = container.querySelectorAll('svg');
236
+ expect(loaders.length).toBeGreaterThan(0);
237
+ });
238
+ it('should show error state for failed metadata', ()=>{
239
+ mockUseObjectMetadata.mockReturnValueOnce({
240
+ data: void 0,
241
+ status: 'error'
242
+ });
243
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
244
+ ...defaultProps
245
+ }));
246
+ const errors = screen.getAllByText('Error');
247
+ expect(errors.length).toBeGreaterThan(0);
248
+ });
249
+ it('should show N/A when retention is not available', ()=>{
250
+ mockUseObjectRetention.mockReturnValueOnce({
251
+ data: void 0,
252
+ status: 'error'
253
+ });
254
+ mockUseObjectLegalHold.mockReturnValueOnce({
255
+ data: void 0,
256
+ status: 'error'
257
+ });
258
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
259
+ ...defaultProps
260
+ }));
261
+ expect(screen.getByText('No Retention')).toBeInTheDocument();
262
+ expect(screen.getAllByText('N/A').length).toBeGreaterThan(0);
263
+ });
264
+ });
265
+ describe('Version ID Handling', ()=>{
266
+ it('should prefer metadata version ID over prop', ()=>{
267
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
268
+ ...defaultProps,
269
+ versionId: "prop-version-id"
270
+ }));
271
+ expect(screen.getByText('test-version-id')).toBeInTheDocument();
272
+ expect(screen.queryByText('prop-version-id')).not.toBeInTheDocument();
273
+ });
274
+ it('should fallback to prop version ID when metadata is unavailable', ()=>{
275
+ mockUseObjectMetadata.mockReturnValueOnce({
276
+ data: {
277
+ ...mockObjectMetadata,
278
+ VersionId: void 0
279
+ },
280
+ status: 'success'
281
+ });
282
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
283
+ ...defaultProps,
284
+ versionId: "fallback-version-id"
285
+ }));
286
+ expect(screen.getByText('fallback-version-id')).toBeInTheDocument();
287
+ });
288
+ it('should show N/A when no version ID is available', ()=>{
289
+ mockUseObjectMetadata.mockReturnValueOnce({
290
+ data: {
291
+ ...mockObjectMetadata,
292
+ VersionId: void 0
293
+ },
294
+ status: 'success'
295
+ });
296
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
297
+ ...defaultProps
298
+ }));
299
+ expect(screen.getAllByText('N/A').length).toBeGreaterThan(0);
300
+ });
301
+ });
302
+ describe('ETag Handling Edge Cases', ()=>{
303
+ it('should handle null ETag gracefully', ()=>{
304
+ mockUseObjectMetadata.mockReturnValueOnce({
305
+ data: {
306
+ ...mockObjectMetadata,
307
+ ETag: null
308
+ },
309
+ status: 'success'
310
+ });
311
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
312
+ ...defaultProps
313
+ }));
314
+ expect(screen.getAllByText('N/A').length).toBeGreaterThan(0);
315
+ });
316
+ it('should handle undefined ETag gracefully', ()=>{
317
+ mockUseObjectMetadata.mockReturnValueOnce({
318
+ data: {
319
+ ...mockObjectMetadata,
320
+ ETag: void 0
321
+ },
322
+ status: 'success'
323
+ });
324
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
325
+ ...defaultProps
326
+ }));
327
+ expect(screen.getAllByText('N/A').length).toBeGreaterThan(0);
328
+ });
329
+ it('should handle metadata error state gracefully', ()=>{
330
+ mockUseObjectMetadata.mockReturnValueOnce({
331
+ data: void 0,
332
+ status: 'error'
333
+ });
334
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
335
+ ...defaultProps
336
+ }));
337
+ expect(screen.getAllByText('Error').length).toBeGreaterThan(0);
338
+ });
339
+ it('should remove quotes from ETag', ()=>{
340
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
341
+ ...defaultProps
342
+ }));
343
+ expect(screen.getByText('abc123def456')).toBeInTheDocument();
344
+ expect(screen.queryByText('"abc123def456"')).not.toBeInTheDocument();
345
+ });
346
+ it('should handle ETag without quotes', ()=>{
347
+ mockUseObjectMetadata.mockReturnValueOnce({
348
+ data: {
349
+ ...mockObjectMetadata,
350
+ ETag: 'unquoted-etag'
351
+ },
352
+ status: 'success'
353
+ });
354
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
355
+ ...defaultProps
356
+ }));
357
+ expect(screen.getByText('unquoted-etag')).toBeInTheDocument();
358
+ });
359
+ });
360
+ describe('Custom Fields', ()=>{
361
+ describe('Information Section', ()=>{
362
+ it('should render custom information fields', ()=>{
363
+ const CustomField = ({ entityName })=>/*#__PURE__*/ jsxs("div", {
364
+ children: [
365
+ "Custom Field for ",
366
+ entityName
367
+ ]
368
+ });
369
+ const customConfig = {
370
+ extraObjectSummaryInformation: [
371
+ {
372
+ id: 'custom-field',
373
+ label: 'Custom Field',
374
+ render: CustomField
375
+ }
376
+ ]
377
+ };
378
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
379
+ ...defaultProps
380
+ }), {
381
+ customizationConfig: customConfig
382
+ });
383
+ expect(screen.getByText('Custom Field')).toBeInTheDocument();
384
+ expect(screen.getByText(/custom field for test-object.txt/i)).toBeInTheDocument();
385
+ });
386
+ it('should replace default fields with same ID', ()=>{
387
+ const CustomLocationField = ()=>/*#__PURE__*/ jsx("div", {
388
+ children: "Custom Location Value"
389
+ });
390
+ const customConfig = {
391
+ extraObjectSummaryInformation: [
392
+ {
393
+ id: 'location',
394
+ label: 'Custom Location',
395
+ render: CustomLocationField
396
+ }
397
+ ]
398
+ };
399
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
400
+ ...defaultProps
401
+ }), {
402
+ customizationConfig: customConfig
403
+ });
404
+ expect(screen.getByText('Custom Location')).toBeInTheDocument();
405
+ expect(screen.getByText('Custom Location Value')).toBeInTheDocument();
406
+ expect(screen.queryByText('default')).not.toBeInTheDocument();
407
+ });
408
+ it('should add multiple custom fields', ()=>{
409
+ const Field1 = ()=>/*#__PURE__*/ jsx("div", {
410
+ children: "Field 1 Value"
411
+ });
412
+ const Field2 = ()=>/*#__PURE__*/ jsx("div", {
413
+ children: "Field 2 Value"
414
+ });
415
+ const Field3 = ()=>/*#__PURE__*/ jsx("div", {
416
+ children: "Field 3 Value"
417
+ });
418
+ const customConfig = {
419
+ extraObjectSummaryInformation: [
420
+ {
421
+ id: 'field1',
422
+ label: 'Field 1',
423
+ render: Field1
424
+ },
425
+ {
426
+ id: 'field2',
427
+ label: 'Field 2',
428
+ render: Field2
429
+ },
430
+ {
431
+ id: 'field3',
432
+ label: 'Field 3',
433
+ render: Field3
434
+ }
435
+ ]
436
+ };
437
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
438
+ ...defaultProps
439
+ }), {
440
+ customizationConfig: customConfig
441
+ });
442
+ expect(screen.getByText('Field 1')).toBeInTheDocument();
443
+ expect(screen.getByText('Field 2')).toBeInTheDocument();
444
+ expect(screen.getByText('Field 3')).toBeInTheDocument();
445
+ expect(screen.getByText('Field 1 Value')).toBeInTheDocument();
446
+ expect(screen.getByText('Field 2 Value')).toBeInTheDocument();
447
+ expect(screen.getByText('Field 3 Value')).toBeInTheDocument();
448
+ });
449
+ it('should pass entityName prop to custom field components', ()=>{
450
+ const CustomField = ({ entityName })=>/*#__PURE__*/ jsxs("div", {
451
+ "data-testid": "custom-field",
452
+ children: [
453
+ "EntityName: ",
454
+ entityName
455
+ ]
456
+ });
457
+ const customConfig = {
458
+ extraObjectSummaryInformation: [
459
+ {
460
+ id: 'test-field',
461
+ label: 'Test Field',
462
+ render: CustomField
463
+ }
464
+ ]
465
+ };
466
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
467
+ ...defaultProps,
468
+ objectKey: "my-special-file.txt"
469
+ }), {
470
+ customizationConfig: customConfig
471
+ });
472
+ expect(screen.getByTestId('custom-field')).toHaveTextContent('EntityName: my-special-file.txt');
473
+ });
474
+ });
475
+ describe('Data Protection Section', ()=>{
476
+ it('should render custom data protection fields', ()=>{
477
+ const CustomProtectionField = ()=>/*#__PURE__*/ jsx("div", {
478
+ children: "Custom Protection Info"
479
+ });
480
+ const customConfig = {
481
+ extraObjectSummaryDataProtection: [
482
+ {
483
+ id: 'custom-protection',
484
+ label: 'Custom Protection',
485
+ render: CustomProtectionField
486
+ }
487
+ ]
488
+ };
489
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
490
+ ...defaultProps
491
+ }), {
492
+ customizationConfig: customConfig
493
+ });
494
+ expect(screen.getByText('Custom Protection')).toBeInTheDocument();
495
+ expect(screen.getByText('Custom Protection Info')).toBeInTheDocument();
496
+ });
497
+ it('should replace default data protection fields', ()=>{
498
+ const CustomLockField = ()=>/*#__PURE__*/ jsx("div", {
499
+ children: "Custom Lock Status"
500
+ });
501
+ const customConfig = {
502
+ extraObjectSummaryDataProtection: [
503
+ {
504
+ id: 'lock',
505
+ label: 'Custom Lock',
506
+ render: CustomLockField
507
+ }
508
+ ]
509
+ };
510
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
511
+ ...defaultProps
512
+ }), {
513
+ customizationConfig: customConfig
514
+ });
515
+ expect(screen.getByText('Custom Lock')).toBeInTheDocument();
516
+ expect(screen.getByText('Custom Lock Status')).toBeInTheDocument();
517
+ expect(screen.queryByText(/GOVERNANCE/)).not.toBeInTheDocument();
518
+ });
519
+ });
520
+ describe('Optional Labels', ()=>{
521
+ it('should handle fields without labels', ()=>{
522
+ const FieldWithoutLabel = ()=>/*#__PURE__*/ jsx("div", {
523
+ children: "Content Only"
524
+ });
525
+ const customConfig = {
526
+ extraObjectSummaryInformation: [
527
+ {
528
+ id: 'no-label-field',
529
+ render: FieldWithoutLabel
530
+ }
531
+ ]
532
+ };
533
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
534
+ ...defaultProps
535
+ }), {
536
+ customizationConfig: customConfig
537
+ });
538
+ expect(screen.getByText('Content Only')).toBeInTheDocument();
539
+ });
540
+ });
541
+ });
542
+ describe('Legal Hold Toggle', ()=>{
543
+ it('should call mutation when toggle is clicked', async ()=>{
544
+ const user = user_event.setup();
545
+ const mockMutate = jest.fn();
546
+ mockUseObjectRetention.mockReturnValueOnce({
547
+ data: mockRetentionData,
548
+ status: 'success'
549
+ });
550
+ mockUseObjectLegalHold.mockReturnValueOnce({
551
+ data: mockLegalHoldData,
552
+ status: 'success'
553
+ });
554
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
555
+ mutate: mockMutate,
556
+ isPending: false
557
+ });
558
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
559
+ ...defaultProps
560
+ }));
561
+ const toggle = getLegalHoldToggle();
562
+ await user.click(toggle);
563
+ await waitFor(()=>{
564
+ expect(mockMutate).toHaveBeenCalled();
565
+ });
566
+ });
567
+ it('should call mutation with correct parameters', async ()=>{
568
+ const user = user_event.setup();
569
+ const mockMutate = jest.fn();
570
+ mockUseObjectRetention.mockReturnValueOnce({
571
+ data: mockRetentionData,
572
+ status: 'success'
573
+ });
574
+ mockUseObjectLegalHold.mockReturnValueOnce({
575
+ data: mockLegalHoldData,
576
+ status: 'success'
577
+ });
578
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
579
+ mutate: mockMutate,
580
+ isPending: false
581
+ });
582
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
583
+ ...defaultProps
584
+ }));
585
+ const toggle = getLegalHoldToggle();
586
+ await user.click(toggle);
587
+ await waitFor(()=>{
588
+ expect(mockMutate).toHaveBeenCalledWith(expect.objectContaining({
589
+ Bucket: 'test-bucket',
590
+ Key: 'test-object.txt',
591
+ LegalHold: {
592
+ Status: 'ON'
593
+ }
594
+ }), expect.any(Object));
595
+ });
596
+ });
597
+ it('should show success toast with correct message when enabling legal hold', async ()=>{
598
+ const user = user_event.setup();
599
+ const mockShowToast = jest.fn();
600
+ const mockMutate = jest.fn((_params, callbacks)=>{
601
+ callbacks.onSuccess();
602
+ });
603
+ mockUseToast.mockReturnValue({
604
+ showToast: mockShowToast
605
+ });
606
+ mockUseObjectRetention.mockReturnValueOnce({
607
+ data: mockRetentionData,
608
+ status: 'success'
609
+ });
610
+ mockUseObjectLegalHold.mockReturnValueOnce({
611
+ data: mockLegalHoldData,
612
+ status: 'success'
613
+ });
614
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
615
+ mutate: mockMutate,
616
+ isPending: false
617
+ });
618
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
619
+ ...defaultProps
620
+ }));
621
+ const toggle = getLegalHoldToggle();
622
+ await user.click(toggle);
623
+ await waitFor(()=>{
624
+ expect(mockShowToast).toHaveBeenCalledWith({
625
+ open: true,
626
+ message: 'Legal hold active',
627
+ status: 'success'
628
+ });
629
+ });
630
+ });
631
+ it('should show error toast when mutation fails with Error instance', async ()=>{
632
+ const user = user_event.setup();
633
+ const mockShowToast = jest.fn();
634
+ const testError = new Error('Network error');
635
+ const mockMutate = jest.fn((_params, callbacks)=>{
636
+ callbacks.onError(testError);
637
+ });
638
+ mockUseToast.mockReturnValue({
639
+ showToast: mockShowToast
640
+ });
641
+ mockUseObjectRetention.mockReturnValueOnce({
642
+ data: mockRetentionData,
643
+ status: 'success'
644
+ });
645
+ mockUseObjectLegalHold.mockReturnValueOnce({
646
+ data: mockLegalHoldData,
647
+ status: 'success'
648
+ });
649
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
650
+ mutate: mockMutate,
651
+ isPending: false
652
+ });
653
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
654
+ ...defaultProps
655
+ }));
656
+ const toggle = getLegalHoldToggle();
657
+ await user.click(toggle);
658
+ await waitFor(()=>{
659
+ expect(mockShowToast).toHaveBeenCalledWith({
660
+ open: true,
661
+ message: 'Network error',
662
+ status: 'error'
663
+ });
664
+ });
665
+ });
666
+ it('should show generic error message when mutation fails with non-Error object', async ()=>{
667
+ const user = user_event.setup();
668
+ const mockShowToast = jest.fn();
669
+ const mockMutate = jest.fn((_params, callbacks)=>{
670
+ callbacks.onError({
671
+ message: 'Custom error'
672
+ });
673
+ });
674
+ mockUseToast.mockReturnValue({
675
+ showToast: mockShowToast
676
+ });
677
+ mockUseObjectRetention.mockReturnValueOnce({
678
+ data: mockRetentionData,
679
+ status: 'success'
680
+ });
681
+ mockUseObjectLegalHold.mockReturnValueOnce({
682
+ data: mockLegalHoldData,
683
+ status: 'success'
684
+ });
685
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
686
+ mutate: mockMutate,
687
+ isPending: false
688
+ });
689
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
690
+ ...defaultProps
691
+ }));
692
+ const toggle = getLegalHoldToggle();
693
+ await user.click(toggle);
694
+ await waitFor(()=>{
695
+ expect(mockShowToast).toHaveBeenCalledWith({
696
+ open: true,
697
+ message: 'Failed to update legal hold',
698
+ status: 'error'
699
+ });
700
+ });
701
+ });
702
+ it('should disable toggle while updating', ()=>{
703
+ mockUseObjectRetention.mockReturnValueOnce({
704
+ data: mockRetentionData,
705
+ status: 'success'
706
+ });
707
+ mockUseObjectLegalHold.mockReturnValueOnce({
708
+ data: mockLegalHoldData,
709
+ status: 'success'
710
+ });
711
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
712
+ mutate: jest.fn(),
713
+ isPending: true
714
+ });
715
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
716
+ ...defaultProps
717
+ }));
718
+ const toggle = getLegalHoldToggle();
719
+ expect(toggle).toBeDisabled();
720
+ });
721
+ it('should show checked toggle when legal hold is enabled', ()=>{
722
+ mockUseObjectRetention.mockReturnValueOnce({
723
+ data: mockRetentionData,
724
+ status: 'success'
725
+ });
726
+ mockUseObjectLegalHold.mockReturnValueOnce({
727
+ data: {
728
+ LegalHold: {
729
+ Status: 'ON'
730
+ }
731
+ },
732
+ status: 'success'
733
+ });
734
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
735
+ mutate: jest.fn(),
736
+ isPending: false
737
+ });
738
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
739
+ ...defaultProps
740
+ }));
741
+ const toggle = getLegalHoldToggle();
742
+ expect(toggle).toBeChecked();
743
+ });
744
+ it('should show unchecked toggle when legal hold is disabled', ()=>{
745
+ mockUseObjectRetention.mockReturnValueOnce({
746
+ data: mockRetentionData,
747
+ status: 'success'
748
+ });
749
+ mockUseObjectLegalHold.mockReturnValueOnce({
750
+ data: {
751
+ LegalHold: {
752
+ Status: 'OFF'
753
+ }
754
+ },
755
+ status: 'success'
756
+ });
757
+ mockUseSetObjectLegalHold.mockReturnValueOnce({
758
+ mutate: jest.fn(),
759
+ isPending: false
760
+ });
761
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
762
+ ...defaultProps
763
+ }));
764
+ const toggle = getLegalHoldToggle();
765
+ expect(toggle).not.toBeChecked();
766
+ });
767
+ });
768
+ describe('Copy Buttons', ()=>{
769
+ it('should render copy buttons for version ID and ETag', ()=>{
770
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
771
+ ...defaultProps
772
+ }));
773
+ const copyButtons = screen.getAllByRole('button', {
774
+ name: /copy/i
775
+ });
776
+ expect(copyButtons.length).toBeGreaterThanOrEqual(2);
777
+ });
778
+ it('should display version ID value correctly', ()=>{
779
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
780
+ ...defaultProps
781
+ }));
782
+ expect(screen.getByText('test-version-id')).toBeInTheDocument();
783
+ const copyButtons = screen.getAllByRole('button', {
784
+ name: /copy/i
785
+ });
786
+ expect(copyButtons.length).toBeGreaterThan(0);
787
+ });
788
+ it('should display ETag value correctly', ()=>{
789
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
790
+ ...defaultProps
791
+ }));
792
+ expect(screen.getByText('abc123def456')).toBeInTheDocument();
793
+ const copyButtons = screen.getAllByRole('button', {
794
+ name: /copy/i
795
+ });
796
+ expect(copyButtons.length).toBeGreaterThan(0);
797
+ });
798
+ });
799
+ describe('Field Ordering', ()=>{
800
+ it('should maintain default field order', ()=>{
801
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
802
+ ...defaultProps
803
+ }));
804
+ expect(screen.getByText('Information')).toBeInTheDocument();
805
+ expect(screen.getByText('Name')).toBeInTheDocument();
806
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
807
+ expect(screen.getByText('Size')).toBeInTheDocument();
808
+ expect(screen.getByText('Modified On')).toBeInTheDocument();
809
+ expect(screen.getByText('ETag')).toBeInTheDocument();
810
+ expect(screen.getByText('Location')).toBeInTheDocument();
811
+ expect(screen.getByText('Data protection')).toBeInTheDocument();
812
+ expect(screen.getByText('Lock')).toBeInTheDocument();
813
+ expect(screen.getByText('Legal Hold')).toBeInTheDocument();
814
+ });
815
+ it('should append custom fields after default fields', ()=>{
816
+ const CustomField = ()=>/*#__PURE__*/ jsx("div", {
817
+ children: "Custom Field Content"
818
+ });
819
+ const customConfig = {
820
+ extraObjectSummaryInformation: [
821
+ {
822
+ id: 'custom-field',
823
+ label: 'Custom Field',
824
+ render: CustomField
825
+ }
826
+ ]
827
+ };
828
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
829
+ ...defaultProps
830
+ }), {
831
+ customizationConfig: customConfig
832
+ });
833
+ const allText = document.body.textContent || '';
834
+ const locationIndex = allText.indexOf('Location');
835
+ const customFieldIndex = allText.indexOf('Custom Field');
836
+ expect(locationIndex).toBeLessThan(customFieldIndex);
837
+ });
838
+ });
839
+ describe('Performance', ()=>{
840
+ it('should memoize information fields', ()=>{
841
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
842
+ ...defaultProps
843
+ }));
844
+ const firstRender = screen.getByText('test-object.txt');
845
+ expect(firstRender).toBeInTheDocument();
846
+ cleanup();
847
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
848
+ ...defaultProps
849
+ }));
850
+ const secondRender = screen.getByText('test-object.txt');
851
+ expect(secondRender).toBeInTheDocument();
852
+ });
853
+ it('should not recalculate fields when unrelated props change', ()=>{
854
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
855
+ ...defaultProps
856
+ }));
857
+ expect(screen.getByText('test-object.txt')).toBeInTheDocument();
858
+ cleanup();
859
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
860
+ ...defaultProps,
861
+ versionId: "new-version"
862
+ }));
863
+ expect(screen.getByText('test-object.txt')).toBeInTheDocument();
864
+ });
865
+ });
866
+ describe('Public Access Toggle', ()=>{
867
+ const mockAclDataPublic = {
868
+ Grants: [
869
+ {
870
+ Grantee: {
871
+ URI: 'http://acs.amazonaws.com/groups/global/AllUsers'
872
+ },
873
+ Permission: 'READ'
874
+ }
875
+ ]
876
+ };
877
+ const mockAclDataPublicFullControl = {
878
+ Grants: [
879
+ {
880
+ Grantee: {
881
+ URI: 'http://acs.amazonaws.com/groups/global/AllUsers'
882
+ },
883
+ Permission: 'FULL_CONTROL'
884
+ }
885
+ ]
886
+ };
887
+ it('should render public field in access section', ()=>{
888
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
889
+ ...defaultProps
890
+ }));
891
+ expect(screen.getByText('Access')).toBeInTheDocument();
892
+ expect(screen.getByText('Public')).toBeInTheDocument();
893
+ });
894
+ it('should disable toggle with tooltip when public access block fetch fails', async ()=>{
895
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
896
+ data: void 0,
897
+ status: 'error'
898
+ });
899
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
900
+ ...defaultProps
901
+ }));
902
+ const toggle = getPublicToggle();
903
+ expect(toggle).toBeDisabled();
904
+ await expectTooltipOnHover(toggle, 'Unable to check public access block settings');
905
+ });
906
+ it('should disable toggle with tooltip when BlockPublicAcls is true', async ()=>{
907
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
908
+ data: {
909
+ PublicAccessBlockConfiguration: {
910
+ BlockPublicAcls: true,
911
+ IgnorePublicAcls: false
912
+ }
913
+ },
914
+ status: 'success'
915
+ });
916
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
917
+ ...defaultProps
918
+ }));
919
+ const toggle = getPublicToggle();
920
+ expect(toggle).toBeDisabled();
921
+ await expectTooltipOnHover(toggle, 'Public access is blocked at bucket level');
922
+ });
923
+ it('should show Active label when object is public with READ permission', ()=>{
924
+ mockUseObjectAcl.mockReturnValueOnce({
925
+ data: mockAclDataPublic,
926
+ status: 'success'
927
+ });
928
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
929
+ ...defaultProps
930
+ }));
931
+ expect(screen.getByText('Active')).toBeInTheDocument();
932
+ });
933
+ it('should show Active label when object is public with FULL_CONTROL permission', ()=>{
934
+ mockUseObjectAcl.mockReturnValueOnce({
935
+ data: mockAclDataPublicFullControl,
936
+ status: 'success'
937
+ });
938
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
939
+ ...defaultProps
940
+ }));
941
+ expect(screen.getByText('Active')).toBeInTheDocument();
942
+ });
943
+ it('should show Inactive label when object is private', ()=>{
944
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
945
+ ...defaultProps
946
+ }));
947
+ const publicToggle = getPublicToggle();
948
+ expect(publicToggle).toBeInTheDocument();
949
+ expect(publicToggle).not.toBeChecked();
950
+ const inactiveLabels = screen.getAllByText('Inactive');
951
+ expect(inactiveLabels.length).toBeGreaterThanOrEqual(1);
952
+ });
953
+ it('should show public hint message when object is public', ()=>{
954
+ mockUseObjectAcl.mockReturnValueOnce({
955
+ data: mockAclDataPublic,
956
+ status: 'success'
957
+ });
958
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
959
+ ...defaultProps
960
+ }));
961
+ expect(screen.getByText('Available to anyone with the link and endpoint access')).toBeInTheDocument();
962
+ });
963
+ it('should not show public hint when object is private', ()=>{
964
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
965
+ ...defaultProps
966
+ }));
967
+ expect(screen.queryByText('Available to anyone with the link and endpoint access')).not.toBeInTheDocument();
968
+ });
969
+ it('should show external link when object is public', ()=>{
970
+ mockUseObjectAcl.mockReturnValueOnce({
971
+ data: mockAclDataPublic,
972
+ status: 'success'
973
+ });
974
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
975
+ ...defaultProps
976
+ }));
977
+ expect(screen.getByText('External link')).toBeInTheDocument();
978
+ });
979
+ it('should not show external link when object is private', ()=>{
980
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
981
+ ...defaultProps
982
+ }));
983
+ expect(screen.queryByText('External link')).not.toBeInTheDocument();
984
+ });
985
+ it('should show copy button for external link when public', ()=>{
986
+ mockUseObjectAcl.mockReturnValueOnce({
987
+ data: mockAclDataPublic,
988
+ status: 'success'
989
+ });
990
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
991
+ ...defaultProps
992
+ }));
993
+ const copyButtons = screen.getAllByRole('button', {
994
+ name: /copy/i
995
+ });
996
+ expect(copyButtons.length).toBeGreaterThanOrEqual(3);
997
+ });
998
+ it('should disable toggle with tooltip when IgnorePublicAcls is true', async ()=>{
999
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
1000
+ data: {
1001
+ PublicAccessBlockConfiguration: {
1002
+ BlockPublicAcls: false,
1003
+ IgnorePublicAcls: true
1004
+ }
1005
+ },
1006
+ status: 'success'
1007
+ });
1008
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
1009
+ ...defaultProps
1010
+ }));
1011
+ const toggle = getPublicToggle();
1012
+ expect(toggle).toBeDisabled();
1013
+ await expectTooltipOnHover(toggle, 'Public access is blocked at bucket level');
1014
+ });
1015
+ it('should hide all public access UI when GetPublicAccessBlock returns 501 Not Implemented', ()=>{
1016
+ const notImplementedError = {
1017
+ statusCode: 501
1018
+ };
1019
+ mockUseObjectAcl.mockReturnValueOnce({
1020
+ data: mockAclDataPublic,
1021
+ status: 'success'
1022
+ });
1023
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
1024
+ data: void 0,
1025
+ status: 'error',
1026
+ error: notImplementedError
1027
+ });
1028
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
1029
+ ...defaultProps
1030
+ }));
1031
+ expect(screen.queryByText('Public')).not.toBeInTheDocument();
1032
+ expect(screen.queryByText('External link')).not.toBeInTheDocument();
1033
+ expect(screen.queryByText('Available to anyone with the link and endpoint access')).not.toBeInTheDocument();
1034
+ });
1035
+ it('should hide public toggle while GetPublicAccessBlock is pending', ()=>{
1036
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
1037
+ data: void 0,
1038
+ status: 'pending',
1039
+ error: void 0
1040
+ });
1041
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
1042
+ ...defaultProps
1043
+ }));
1044
+ expect(screen.queryByText('Public')).not.toBeInTheDocument();
1045
+ });
1046
+ it('should disable toggle with tooltip when GetPublicAccessBlock returns other 5xx errors', async ()=>{
1047
+ const serverError = {
1048
+ statusCode: 500
1049
+ };
1050
+ mockUseGetPublicAccessBlock.mockReturnValueOnce({
1051
+ data: void 0,
1052
+ status: 'error',
1053
+ error: serverError
1054
+ });
1055
+ renderWithProviders(/*#__PURE__*/ jsx(ObjectSummary, {
1056
+ ...defaultProps
1057
+ }));
1058
+ const toggle = getPublicToggle();
1059
+ expect(toggle).toBeInTheDocument();
1060
+ expect(toggle).toBeDisabled();
1061
+ await expectTooltipOnHover(toggle, 'Unable to check public access block settings');
1062
+ });
1063
+ });
1064
+ });