@scality/data-browser-library 1.0.0-preview.2

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 (176) hide show
  1. package/dist/components/Editor.d.ts +12 -0
  2. package/dist/components/Editor.js +28 -0
  3. package/dist/components/__tests__/BucketList.test.d.ts +1 -0
  4. package/dist/components/__tests__/BucketList.test.js +225 -0
  5. package/dist/components/__tests__/BucketOverview.test.d.ts +1 -0
  6. package/dist/components/__tests__/BucketOverview.test.js +479 -0
  7. package/dist/components/__tests__/BucketPolicyPage.test.d.ts +1 -0
  8. package/dist/components/__tests__/BucketPolicyPage.test.js +213 -0
  9. package/dist/components/__tests__/CreateFolderButton.test.d.ts +1 -0
  10. package/dist/components/__tests__/CreateFolderButton.test.js +147 -0
  11. package/dist/components/__tests__/DeleteBucketButton.test.d.ts +1 -0
  12. package/dist/components/__tests__/DeleteBucketButton.test.js +272 -0
  13. package/dist/components/__tests__/DeleteObjectButton.test.d.ts +1 -0
  14. package/dist/components/__tests__/DeleteObjectButton.test.js +302 -0
  15. package/dist/components/__tests__/MetadataSearch.test.d.ts +1 -0
  16. package/dist/components/__tests__/MetadataSearch.test.js +201 -0
  17. package/dist/components/__tests__/ObjectList.test.d.ts +1 -0
  18. package/dist/components/__tests__/ObjectList.test.js +283 -0
  19. package/dist/components/__tests__/UploadButton.test.d.ts +1 -0
  20. package/dist/components/__tests__/UploadButton.test.js +144 -0
  21. package/dist/components/buckets/BucketDetails.d.ts +1 -0
  22. package/dist/components/buckets/BucketDetails.js +51 -0
  23. package/dist/components/buckets/BucketList.d.ts +12 -0
  24. package/dist/components/buckets/BucketList.js +136 -0
  25. package/dist/components/buckets/BucketLocation.d.ts +3 -0
  26. package/dist/components/buckets/BucketLocation.js +16 -0
  27. package/dist/components/buckets/BucketOverview.d.ts +14 -0
  28. package/dist/components/buckets/BucketOverview.js +209 -0
  29. package/dist/components/buckets/BucketPage.d.ts +2 -0
  30. package/dist/components/buckets/BucketPage.js +47 -0
  31. package/dist/components/buckets/BucketPolicyButton.d.ts +7 -0
  32. package/dist/components/buckets/BucketPolicyButton.js +18 -0
  33. package/dist/components/buckets/BucketPolicyPage.d.ts +1 -0
  34. package/dist/components/buckets/BucketPolicyPage.js +205 -0
  35. package/dist/components/buckets/DeleteBucketButton.d.ts +8 -0
  36. package/dist/components/buckets/DeleteBucketButton.js +78 -0
  37. package/dist/components/index.d.ts +12 -0
  38. package/dist/components/index.js +13 -0
  39. package/dist/components/layouts/BrowserPageLayout.d.ts +9 -0
  40. package/dist/components/layouts/BrowserPageLayout.js +46 -0
  41. package/dist/components/objects/CreateFolderButton.d.ts +29 -0
  42. package/dist/components/objects/CreateFolderButton.js +118 -0
  43. package/dist/components/objects/DeleteObjectButton.d.ts +8 -0
  44. package/dist/components/objects/DeleteObjectButton.js +191 -0
  45. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -0
  46. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +323 -0
  47. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +3 -0
  48. package/dist/components/objects/ObjectDetails/ObjectSummary.js +193 -0
  49. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +3 -0
  50. package/dist/components/objects/ObjectDetails/ObjectTags.js +300 -0
  51. package/dist/components/objects/ObjectDetails/index.d.ts +9 -0
  52. package/dist/components/objects/ObjectDetails/index.js +49 -0
  53. package/dist/components/objects/ObjectList.d.ts +40 -0
  54. package/dist/components/objects/ObjectList.js +407 -0
  55. package/dist/components/objects/ObjectPage.d.ts +1 -0
  56. package/dist/components/objects/ObjectPage.js +43 -0
  57. package/dist/components/objects/UploadButton.d.ts +34 -0
  58. package/dist/components/objects/UploadButton.js +229 -0
  59. package/dist/components/providers/DataBrowserProvider.d.ts +20 -0
  60. package/dist/components/providers/DataBrowserProvider.js +42 -0
  61. package/dist/components/search/MetadataSearch.d.ts +5 -0
  62. package/dist/components/search/MetadataSearch.js +162 -0
  63. package/dist/components/search/SearchHints.d.ts +8 -0
  64. package/dist/components/search/SearchHints.js +21 -0
  65. package/dist/components/ui/DeleteObjectModalContent.d.ts +5 -0
  66. package/dist/components/ui/DeleteObjectModalContent.js +71 -0
  67. package/dist/components/ui/Search.elements.d.ts +17 -0
  68. package/dist/components/ui/Search.elements.js +59 -0
  69. package/dist/components/ui/Table.elements.d.ts +36 -0
  70. package/dist/components/ui/Table.elements.js +87 -0
  71. package/dist/config/factory.d.ts +52 -0
  72. package/dist/config/factory.js +70 -0
  73. package/dist/config/types.d.ts +46 -0
  74. package/dist/config/types.js +0 -0
  75. package/dist/hooks/__tests__/useIsBucketEmpty.test.d.ts +1 -0
  76. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +122 -0
  77. package/dist/hooks/bucketConfiguration.d.ts +147 -0
  78. package/dist/hooks/bucketConfiguration.js +59 -0
  79. package/dist/hooks/bucketOperations.d.ts +36 -0
  80. package/dist/hooks/bucketOperations.js +12 -0
  81. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.d.ts +1 -0
  82. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +276 -0
  83. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.d.ts +1 -0
  84. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +259 -0
  85. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.d.ts +1 -0
  86. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +166 -0
  87. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.d.ts +1 -0
  88. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +200 -0
  89. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.d.ts +1 -0
  90. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +136 -0
  91. package/dist/hooks/factories/index.d.ts +18 -0
  92. package/dist/hooks/factories/index.js +5 -0
  93. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +13 -0
  94. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +76 -0
  95. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +8 -0
  96. package/dist/hooks/factories/useCreateS3LoginHook.js +22 -0
  97. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +5 -0
  98. package/dist/hooks/factories/useCreateS3MutationHook.js +50 -0
  99. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +3 -0
  100. package/dist/hooks/factories/useCreateS3QueryHook.js +30 -0
  101. package/dist/hooks/index.d.ts +8 -0
  102. package/dist/hooks/index.js +8 -0
  103. package/dist/hooks/loginOperations.d.ts +21 -0
  104. package/dist/hooks/loginOperations.js +9 -0
  105. package/dist/hooks/objectOperations.d.ts +190 -0
  106. package/dist/hooks/objectOperations.js +66 -0
  107. package/dist/hooks/presignedOperations.d.ts +73 -0
  108. package/dist/hooks/presignedOperations.js +72 -0
  109. package/dist/hooks/useIsBucketEmpty.d.ts +7 -0
  110. package/dist/hooks/useIsBucketEmpty.js +36 -0
  111. package/dist/hooks/useLoginMutation.d.ts +21 -0
  112. package/dist/hooks/useLoginMutation.js +9 -0
  113. package/dist/hooks/useS3Client.d.ts +1 -0
  114. package/dist/hooks/useS3Client.js +13 -0
  115. package/dist/index.d.ts +6 -0
  116. package/dist/index.js +6 -0
  117. package/dist/schemas/bucketPolicySchema.json +321 -0
  118. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -0
  119. package/dist/test/msw/handlers/deleteBucket.js +14 -0
  120. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -0
  121. package/dist/test/msw/handlers/getBucketAcl.js +96 -0
  122. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -0
  123. package/dist/test/msw/handlers/getBucketLocation.js +23 -0
  124. package/dist/test/msw/handlers/getBucketPolicy.d.ts +11 -0
  125. package/dist/test/msw/handlers/getBucketPolicy.js +72 -0
  126. package/dist/test/msw/handlers/headObject.d.ts +1 -0
  127. package/dist/test/msw/handlers/headObject.js +17 -0
  128. package/dist/test/msw/handlers/listBuckets.d.ts +1 -0
  129. package/dist/test/msw/handlers/listBuckets.js +24 -0
  130. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -0
  131. package/dist/test/msw/handlers/listObjectVersions.js +83 -0
  132. package/dist/test/msw/handlers/listObjects.d.ts +1 -0
  133. package/dist/test/msw/handlers/listObjects.js +66 -0
  134. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -0
  135. package/dist/test/msw/handlers/objectLegalHold.js +24 -0
  136. package/dist/test/msw/handlers/objectRetention.d.ts +1 -0
  137. package/dist/test/msw/handlers/objectRetention.js +27 -0
  138. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -0
  139. package/dist/test/msw/handlers/putBucketAcl.js +18 -0
  140. package/dist/test/msw/handlers/putObject.d.ts +1 -0
  141. package/dist/test/msw/handlers/putObject.js +16 -0
  142. package/dist/test/msw/handlers.d.ts +4 -0
  143. package/dist/test/msw/handlers.js +109 -0
  144. package/dist/test/msw/index.d.ts +2 -0
  145. package/dist/test/msw/index.js +3 -0
  146. package/dist/test/msw/server.d.ts +4 -0
  147. package/dist/test/msw/server.js +20 -0
  148. package/dist/test/msw/utils.d.ts +2 -0
  149. package/dist/test/msw/utils.js +13 -0
  150. package/dist/test/setup.d.ts +1 -0
  151. package/dist/test/setup.js +82 -0
  152. package/dist/test/testUtils.d.ts +82 -0
  153. package/dist/test/testUtils.js +236 -0
  154. package/dist/test/utils/errorHandling.test.d.ts +1 -0
  155. package/dist/test/utils/errorHandling.test.js +385 -0
  156. package/dist/types/index.d.ts +48 -0
  157. package/dist/types/index.js +0 -0
  158. package/dist/utils/deletion/index.d.ts +2 -0
  159. package/dist/utils/deletion/index.js +2 -0
  160. package/dist/utils/deletion/messages.d.ts +5 -0
  161. package/dist/utils/deletion/messages.js +29 -0
  162. package/dist/utils/deletion/types.d.ts +11 -0
  163. package/dist/utils/deletion/types.js +0 -0
  164. package/dist/utils/errorHandling.d.ts +54 -0
  165. package/dist/utils/errorHandling.js +79 -0
  166. package/dist/utils/hooks.d.ts +2 -0
  167. package/dist/utils/hooks.js +26 -0
  168. package/dist/utils/index.d.ts +2 -0
  169. package/dist/utils/index.js +2 -0
  170. package/dist/utils/proxyMiddleware.d.ts +18 -0
  171. package/dist/utils/proxyMiddleware.js +56 -0
  172. package/dist/utils/s3Client.d.ts +5 -0
  173. package/dist/utils/s3Client.js +35 -0
  174. package/dist/utils/useFeatures.d.ts +1 -0
  175. package/dist/utils/useFeatures.js +7 -0
  176. package/package.json +79 -0
@@ -0,0 +1,276 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { useCreateS3FunctionMutationHook } from "../useCreateS3MutationHook.js";
3
+ import { useS3Client } from "../../useS3Client.js";
4
+ import { createS3OperationError } from "../../../utils/errorHandling.js";
5
+ import { createQueryWrapper, validateFactoryHook, validateHookResult } from "../../../test/testUtils.js";
6
+ jest.mock("../../useS3Client");
7
+ jest.mock("../../../utils/errorHandling");
8
+ const mockUseS3Client = useS3Client;
9
+ const mockCreateS3OperationError = createS3OperationError;
10
+ const mockS3Client = {
11
+ config: {}
12
+ };
13
+ const mockOperation = jest.fn();
14
+ describe("useCreateS3FunctionMutationHook - Factory Specific", ()=>{
15
+ beforeEach(()=>{
16
+ jest.clearAllMocks();
17
+ mockUseS3Client.mockReturnValue(mockS3Client);
18
+ mockOperation.mockReset();
19
+ });
20
+ it("should create a functioning mutation hook", ()=>{
21
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
22
+ validateFactoryHook(useMutation, "function-based mutation");
23
+ const { result } = renderHook(()=>useMutation(), {
24
+ wrapper: createQueryWrapper()
25
+ });
26
+ validateHookResult(result.current, "mutation");
27
+ });
28
+ it("should accept invalidation keys parameter", ()=>{
29
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation, [
30
+ "PresignedUrls",
31
+ "TestQuery"
32
+ ]);
33
+ validateFactoryHook(useMutation, "function-based mutation");
34
+ const { result } = renderHook(()=>useMutation(), {
35
+ wrapper: createQueryWrapper()
36
+ });
37
+ validateHookResult(result.current, "mutation");
38
+ });
39
+ it("should execute function operation successfully", async ()=>{
40
+ const mockResponse = {
41
+ Url: "https://presigned.url",
42
+ ExpiresAt: new Date(),
43
+ Bucket: "test-bucket",
44
+ Key: "test-key"
45
+ };
46
+ mockOperation.mockResolvedValue(mockResponse);
47
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
48
+ const { result } = renderHook(()=>useMutation(), {
49
+ wrapper: createQueryWrapper()
50
+ });
51
+ const inputParams = {
52
+ Bucket: "test-bucket",
53
+ Key: "test-key",
54
+ expiresIn: 3600
55
+ };
56
+ result.current.mutate(inputParams);
57
+ await waitFor(()=>{
58
+ expect(result.current.isSuccess).toBe(true);
59
+ });
60
+ expect(result.current.data).toEqual(mockResponse);
61
+ expect(mockOperation).toHaveBeenCalledWith(mockS3Client, inputParams);
62
+ expect(mockOperation).toHaveBeenCalledTimes(1);
63
+ });
64
+ it("should handle function operation errors", async ()=>{
65
+ const mockError = new Error("Presigned URL generation failed");
66
+ mockOperation.mockRejectedValue(mockError);
67
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
68
+ const { result } = renderHook(()=>useMutation(), {
69
+ wrapper: createQueryWrapper()
70
+ });
71
+ result.current.mutate({
72
+ Bucket: "test-bucket",
73
+ Key: "test-key"
74
+ });
75
+ await waitFor(()=>{
76
+ expect(result.current.isError).toBe(true);
77
+ });
78
+ expect(result.current.error).toBe(mockError);
79
+ expect(mockOperation).toHaveBeenCalledWith(mockS3Client, {
80
+ Bucket: "test-bucket",
81
+ Key: "test-key"
82
+ });
83
+ expect(mockCreateS3OperationError).not.toHaveBeenCalled();
84
+ });
85
+ it("should handle function operation with internal error wrapping", async ()=>{
86
+ const mockInternalError = new Error("Internal operation error");
87
+ const mockWrappedError = new Error("Wrapped operation error");
88
+ const mockOperationWithErrorHandling = jest.fn().mockImplementation(async ()=>{
89
+ try {
90
+ throw mockInternalError;
91
+ } catch (error) {
92
+ const wrappedError = mockWrappedError;
93
+ throw wrappedError;
94
+ }
95
+ });
96
+ const useMutation = useCreateS3FunctionMutationHook(mockOperationWithErrorHandling);
97
+ const { result } = renderHook(()=>useMutation(), {
98
+ wrapper: createQueryWrapper()
99
+ });
100
+ result.current.mutate({
101
+ Bucket: "test-bucket",
102
+ Key: "test-key"
103
+ });
104
+ await waitFor(()=>{
105
+ expect(result.current.isError).toBe(true);
106
+ });
107
+ expect(result.current.error).toBe(mockWrappedError);
108
+ expect(mockOperationWithErrorHandling).toHaveBeenCalledWith(mockS3Client, {
109
+ Bucket: "test-bucket",
110
+ Key: "test-key"
111
+ });
112
+ });
113
+ it("should handle mutation callbacks correctly", async ()=>{
114
+ const mockResponse = {
115
+ Url: "https://presigned.url",
116
+ ExpiresAt: new Date()
117
+ };
118
+ const onSuccess = jest.fn();
119
+ const onError = jest.fn();
120
+ const onSettled = jest.fn();
121
+ mockOperation.mockResolvedValue(mockResponse);
122
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
123
+ const { result } = renderHook(()=>useMutation({
124
+ onSuccess,
125
+ onError,
126
+ onSettled
127
+ }), {
128
+ wrapper: createQueryWrapper()
129
+ });
130
+ const variables = {
131
+ Bucket: "test-bucket",
132
+ Key: "test-key"
133
+ };
134
+ result.current.mutate(variables);
135
+ await waitFor(()=>{
136
+ expect(result.current.isSuccess).toBe(true);
137
+ });
138
+ expect(onSuccess).toHaveBeenCalledWith(mockResponse, variables, void 0, expect.any(Object));
139
+ expect(onError).not.toHaveBeenCalled();
140
+ expect(onSettled).toHaveBeenCalledWith(mockResponse, null, variables, void 0, expect.any(Object));
141
+ });
142
+ it("should handle function operation with invalidation keys", async ()=>{
143
+ const mockResponse = {
144
+ success: true
145
+ };
146
+ mockOperation.mockResolvedValue(mockResponse);
147
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation, [
148
+ "PresignedUrls",
149
+ "ObjectList"
150
+ ]);
151
+ const { result } = renderHook(()=>useMutation(), {
152
+ wrapper: createQueryWrapper()
153
+ });
154
+ result.current.mutate({
155
+ Bucket: "test-bucket",
156
+ Key: "test-key"
157
+ });
158
+ await waitFor(()=>{
159
+ expect(result.current.isSuccess).toBe(true);
160
+ });
161
+ expect(result.current.data).toEqual(mockResponse);
162
+ expect(mockOperation).toHaveBeenCalledWith(mockS3Client, {
163
+ Bucket: "test-bucket",
164
+ Key: "test-key"
165
+ });
166
+ });
167
+ it("should handle concurrent function operations correctly", async ()=>{
168
+ const mockResponse1 = {
169
+ Url: "https://presigned1.url",
170
+ ExpiresAt: new Date()
171
+ };
172
+ const mockResponse2 = {
173
+ Url: "https://presigned2.url",
174
+ ExpiresAt: new Date()
175
+ };
176
+ let callCount = 0;
177
+ mockOperation.mockImplementation(()=>{
178
+ callCount++;
179
+ return Promise.resolve(1 === callCount ? mockResponse1 : mockResponse2);
180
+ });
181
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
182
+ const { result: result1 } = renderHook(()=>useMutation(), {
183
+ wrapper: createQueryWrapper()
184
+ });
185
+ const { result: result2 } = renderHook(()=>useMutation(), {
186
+ wrapper: createQueryWrapper()
187
+ });
188
+ result1.current.mutate({
189
+ Bucket: "test-bucket",
190
+ Key: "file1.txt"
191
+ });
192
+ result2.current.mutate({
193
+ Bucket: "test-bucket",
194
+ Key: "file2.txt"
195
+ });
196
+ await waitFor(()=>{
197
+ expect(result1.current.isSuccess).toBe(true);
198
+ expect(result2.current.isSuccess).toBe(true);
199
+ });
200
+ expect(result1.current.data).toEqual(mockResponse1);
201
+ expect(result2.current.data).toEqual(mockResponse2);
202
+ expect(mockOperation).toHaveBeenCalledTimes(2);
203
+ });
204
+ it("should pass correct parameters to function operation", async ()=>{
205
+ const mockResponse = {
206
+ success: true
207
+ };
208
+ let capturedClient;
209
+ let capturedParams;
210
+ mockOperation.mockImplementation((client, params)=>{
211
+ capturedClient = client;
212
+ capturedParams = params;
213
+ return Promise.resolve(mockResponse);
214
+ });
215
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
216
+ const { result } = renderHook(()=>useMutation(), {
217
+ wrapper: createQueryWrapper()
218
+ });
219
+ const inputParams = {
220
+ Bucket: "test-bucket",
221
+ Key: "test-key",
222
+ ContentType: "text/plain",
223
+ expiresIn: 1800
224
+ };
225
+ result.current.mutate(inputParams);
226
+ await waitFor(()=>{
227
+ expect(result.current.isSuccess).toBe(true);
228
+ });
229
+ expect(capturedClient).toBe(mockS3Client);
230
+ expect(capturedParams).toEqual(inputParams);
231
+ });
232
+ it("should handle complex function operations with metadata", async ()=>{
233
+ const mockResponse = {
234
+ Url: "https://complex-presigned.url",
235
+ ExpiresAt: new Date("2024-01-01T12:00:00Z"),
236
+ Bucket: "complex-bucket",
237
+ Key: "complex/path/file.txt",
238
+ VersionId: "version123"
239
+ };
240
+ mockOperation.mockResolvedValue(mockResponse);
241
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
242
+ const { result } = renderHook(()=>useMutation(), {
243
+ wrapper: createQueryWrapper()
244
+ });
245
+ const complexParams = {
246
+ Bucket: "complex-bucket",
247
+ Key: "complex/path/file.txt",
248
+ VersionId: "version123",
249
+ ResponseContentType: "application/json",
250
+ ResponseContentDisposition: "attachment; filename=data.json",
251
+ expiresIn: 7200
252
+ };
253
+ result.current.mutate(complexParams);
254
+ await waitFor(()=>{
255
+ expect(result.current.isSuccess).toBe(true);
256
+ });
257
+ expect(result.current.data).toEqual(mockResponse);
258
+ expect(mockOperation).toHaveBeenCalledWith(mockS3Client, complexParams);
259
+ });
260
+ it("should handle function operations without parameters", async ()=>{
261
+ const mockResponse = {
262
+ status: "operation completed"
263
+ };
264
+ mockOperation.mockResolvedValue(mockResponse);
265
+ const useMutation = useCreateS3FunctionMutationHook(mockOperation);
266
+ const { result } = renderHook(()=>useMutation(), {
267
+ wrapper: createQueryWrapper()
268
+ });
269
+ result.current.mutate(void 0);
270
+ await waitFor(()=>{
271
+ expect(result.current.isSuccess).toBe(true);
272
+ });
273
+ expect(result.current.data).toEqual(mockResponse);
274
+ expect(mockOperation).toHaveBeenCalledWith(mockS3Client, void 0);
275
+ });
276
+ });
@@ -0,0 +1,259 @@
1
+ import { renderHook, waitFor } from "@testing-library/react";
2
+ import { useCreateS3InfiniteQueryHook } from "../useCreateS3InfiniteQueryHook.js";
3
+ import { useS3Client } from "../../useS3Client.js";
4
+ import { createS3OperationError } from "../../../utils/errorHandling.js";
5
+ import { createQueryWrapper, validateFactoryHook, validateHookResult } from "../../../test/testUtils.js";
6
+ jest.mock("../../useS3Client");
7
+ jest.mock("../../../utils/errorHandling");
8
+ const mockUseS3Client = useS3Client;
9
+ const mockCreateS3OperationError = createS3OperationError;
10
+ class MockCommand {
11
+ input;
12
+ constructor(input){
13
+ this.input = input;
14
+ }
15
+ }
16
+ const mockS3Client = {
17
+ send: jest.fn()
18
+ };
19
+ describe("useCreateS3InfiniteQueryHook - Pagination Logic", ()=>{
20
+ beforeEach(()=>{
21
+ jest.clearAllMocks();
22
+ mockUseS3Client.mockReturnValue(mockS3Client);
23
+ });
24
+ it("should create a functioning infinite query hook", ()=>{
25
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
26
+ validateFactoryHook(useInfiniteQuery, "ListObjects");
27
+ const { result } = renderHook(()=>useInfiniteQuery({
28
+ Bucket: "test-bucket"
29
+ }), {
30
+ wrapper: createQueryWrapper()
31
+ });
32
+ validateHookResult(result.current, "infiniteQuery");
33
+ });
34
+ it("should handle getPaginationParams for different operations", async ()=>{
35
+ const mockResponse = {
36
+ IsTruncated: false
37
+ };
38
+ mockS3Client.send.mockResolvedValue(mockResponse);
39
+ const useListObjects = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
40
+ const { result: listResult } = renderHook(()=>useListObjects({
41
+ Bucket: "test-bucket"
42
+ }), {
43
+ wrapper: createQueryWrapper()
44
+ });
45
+ const useListVersions = useCreateS3InfiniteQueryHook(MockCommand, "ListObjectVersions");
46
+ const { result: versionsResult } = renderHook(()=>useListVersions({
47
+ Bucket: "test-bucket"
48
+ }), {
49
+ wrapper: createQueryWrapper()
50
+ });
51
+ await waitFor(()=>{
52
+ expect(listResult.current.fetchStatus).not.toBe("idle");
53
+ expect(versionsResult.current.fetchStatus).not.toBe("idle");
54
+ });
55
+ expect(typeof listResult.current.fetchNextPage).toBe("function");
56
+ expect(typeof versionsResult.current.fetchNextPage).toBe("function");
57
+ });
58
+ it("should handle Prefix parameter in enabled logic correctly", ()=>{
59
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
60
+ const { result: undefinedResult } = renderHook(()=>useInfiniteQuery({
61
+ Bucket: "test-bucket",
62
+ Prefix: void 0
63
+ }), {
64
+ wrapper: createQueryWrapper()
65
+ });
66
+ expect(undefinedResult.current.fetchStatus).toBe("idle");
67
+ const { result: definedResult } = renderHook(()=>useInfiniteQuery({
68
+ Bucket: "test-bucket",
69
+ Prefix: "folder/"
70
+ }), {
71
+ wrapper: createQueryWrapper()
72
+ });
73
+ expect(definedResult.current.fetchStatus).not.toBe("idle");
74
+ });
75
+ it("should handle pagination data correctly", async ()=>{
76
+ const mockFirstPage = {
77
+ Contents: [
78
+ {
79
+ Key: "file1.txt"
80
+ },
81
+ {
82
+ Key: "file2.txt"
83
+ }
84
+ ],
85
+ IsTruncated: true,
86
+ NextContinuationToken: "token123"
87
+ };
88
+ const mockSecondPage = {
89
+ Contents: [
90
+ {
91
+ Key: "file3.txt"
92
+ },
93
+ {
94
+ Key: "file4.txt"
95
+ }
96
+ ],
97
+ IsTruncated: false
98
+ };
99
+ let callCount = 0;
100
+ mockS3Client.send.mockImplementation(()=>{
101
+ callCount++;
102
+ return Promise.resolve(1 === callCount ? mockFirstPage : mockSecondPage);
103
+ });
104
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
105
+ const { result } = renderHook(()=>useInfiniteQuery({
106
+ Bucket: "test-bucket"
107
+ }), {
108
+ wrapper: createQueryWrapper()
109
+ });
110
+ await waitFor(()=>{
111
+ expect(result.current.isSuccess).toBe(true);
112
+ });
113
+ const firstPageData = result.current.data;
114
+ expect(firstPageData?.pages).toHaveLength(1);
115
+ expect(firstPageData?.pages?.[0]).toEqual(mockFirstPage);
116
+ expect(result.current.hasNextPage).toBe(true);
117
+ result.current.fetchNextPage();
118
+ await waitFor(()=>{
119
+ const data = result.current.data;
120
+ expect(data?.pages).toHaveLength(2);
121
+ });
122
+ const finalData = result.current.data;
123
+ expect(finalData?.pages?.[1]).toEqual(mockSecondPage);
124
+ expect(result.current.hasNextPage).toBe(false);
125
+ });
126
+ it("should handle ListObjectVersions pagination patterns", async ()=>{
127
+ const mockVersionsResponse = {
128
+ Versions: [
129
+ {
130
+ Key: "file1.txt",
131
+ VersionId: "v1"
132
+ }
133
+ ],
134
+ DeleteMarkers: [
135
+ {
136
+ Key: "file2.txt",
137
+ VersionId: "v2"
138
+ }
139
+ ],
140
+ IsTruncated: true,
141
+ NextKeyMarker: "file1.txt",
142
+ NextVersionIdMarker: "v1"
143
+ };
144
+ mockS3Client.send.mockResolvedValue(mockVersionsResponse);
145
+ const useVersionsQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjectVersions");
146
+ const { result } = renderHook(()=>useVersionsQuery({
147
+ Bucket: "test-bucket"
148
+ }), {
149
+ wrapper: createQueryWrapper()
150
+ });
151
+ await waitFor(()=>{
152
+ expect(result.current.isSuccess).toBe(true);
153
+ });
154
+ const data = result.current.data;
155
+ expect(data?.pages).toHaveLength(1);
156
+ expect(data?.pages?.[0]).toEqual(mockVersionsResponse);
157
+ expect(result.current.hasNextPage).toBe(true);
158
+ expect(mockVersionsResponse.NextKeyMarker).toBe("file1.txt");
159
+ expect(mockVersionsResponse.NextVersionIdMarker).toBe("v1");
160
+ });
161
+ it("should handle infinite query errors with context", async ()=>{
162
+ const mockError = new Error("S3 List Error");
163
+ const enhancedError = new Error("Enhanced S3 List Error");
164
+ mockS3Client.send.mockRejectedValue(mockError);
165
+ mockCreateS3OperationError.mockReturnValue(enhancedError);
166
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
167
+ const { result } = renderHook(()=>useInfiniteQuery({
168
+ Bucket: "test-bucket"
169
+ }), {
170
+ wrapper: createQueryWrapper()
171
+ });
172
+ await waitFor(()=>{
173
+ expect(result.current.isError).toBe(true);
174
+ });
175
+ expect(result.current.error).toBe(enhancedError);
176
+ expect(mockCreateS3OperationError).toHaveBeenCalledWith(mockError, "ListObjects", "test-bucket");
177
+ });
178
+ it("should handle fetchNextPage correctly", async ()=>{
179
+ const mockFirstPage = {
180
+ Contents: [
181
+ {
182
+ Key: "file1.txt"
183
+ }
184
+ ],
185
+ IsTruncated: true,
186
+ NextContinuationToken: "token123"
187
+ };
188
+ mockS3Client.send.mockResolvedValue(mockFirstPage);
189
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
190
+ const { result } = renderHook(()=>useInfiniteQuery({
191
+ Bucket: "test-bucket"
192
+ }), {
193
+ wrapper: createQueryWrapper()
194
+ });
195
+ await waitFor(()=>{
196
+ expect(result.current.isSuccess).toBe(true);
197
+ });
198
+ expect(typeof result.current.fetchNextPage).toBe("function");
199
+ expect(result.current.isFetchingNextPage).toBe(false);
200
+ expect(result.current.hasNextPage).toBe(true);
201
+ expect(()=>result.current.fetchNextPage()).not.toThrow();
202
+ });
203
+ it("should handle infinite query options correctly", ()=>{
204
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
205
+ const customOptions = {
206
+ enabled: false,
207
+ staleTime: 10000,
208
+ refetchOnWindowFocus: false
209
+ };
210
+ const { result } = renderHook(()=>useInfiniteQuery({
211
+ Bucket: "test-bucket"
212
+ }, customOptions), {
213
+ wrapper: createQueryWrapper()
214
+ });
215
+ expect(result.current.fetchStatus).toBe("idle");
216
+ expect(result.current.isLoading).toBe(false);
217
+ });
218
+ it("should pass AbortSignal correctly for infinite queries", async ()=>{
219
+ let capturedAbortSignal;
220
+ mockS3Client.send.mockImplementation((_command, options)=>{
221
+ capturedAbortSignal = options?.abortSignal;
222
+ return Promise.resolve({
223
+ Contents: [],
224
+ IsTruncated: false
225
+ });
226
+ });
227
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
228
+ const { result } = renderHook(()=>useInfiniteQuery({
229
+ Bucket: "test-bucket"
230
+ }), {
231
+ wrapper: createQueryWrapper()
232
+ });
233
+ await waitFor(()=>{
234
+ expect(result.current.isSuccess).toBe(true);
235
+ });
236
+ expect(capturedAbortSignal).toBeInstanceOf(AbortSignal);
237
+ expect(capturedAbortSignal?.aborted).toBe(false);
238
+ });
239
+ it("should handle empty result sets correctly", async ()=>{
240
+ const mockEmptyResponse = {
241
+ Contents: [],
242
+ IsTruncated: false
243
+ };
244
+ mockS3Client.send.mockResolvedValue(mockEmptyResponse);
245
+ const useInfiniteQuery = useCreateS3InfiniteQueryHook(MockCommand, "ListObjects");
246
+ const { result } = renderHook(()=>useInfiniteQuery({
247
+ Bucket: "test-bucket"
248
+ }), {
249
+ wrapper: createQueryWrapper()
250
+ });
251
+ await waitFor(()=>{
252
+ expect(result.current.isSuccess).toBe(true);
253
+ });
254
+ const data = result.current.data;
255
+ expect(data?.pages).toHaveLength(1);
256
+ expect(data?.pages?.[0]).toEqual(mockEmptyResponse);
257
+ expect(result.current.hasNextPage).toBe(false);
258
+ });
259
+ });