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