@scality/data-browser-library 1.0.5 → 1.0.7
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/__tests__/BucketCreate.test.js +60 -20
- package/dist/components/__tests__/BucketLifecycleFormPage.test.js +72 -0
- package/dist/components/__tests__/BucketList.test.js +19 -7
- package/dist/components/__tests__/BucketNotificationFormPage.test.js +54 -19
- package/dist/components/__tests__/BucketPolicyPage.test.js +5 -0
- package/dist/components/__tests__/BucketReplicationFormPage.test.js +259 -61
- package/dist/components/__tests__/MetadataSearch.test.js +18 -12
- package/dist/components/buckets/BucketLifecycleFormPage.js +50 -3
- package/dist/components/buckets/BucketReplicationFormPage.js +50 -4
- package/dist/components/buckets/__tests__/BucketVersioning.test.js +2 -0
- package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +8 -0
- package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +78 -26
- package/dist/config/__tests__/factory.test.js +29 -1
- package/dist/config/factory.d.ts +2 -0
- package/dist/config/factory.js +3 -1
- package/dist/hooks/__tests__/useISVBucketDetection.test.js +22 -1
- package/dist/hooks/useISVBucketDetection.d.ts +1 -0
- package/dist/hooks/useISVBucketDetection.js +5 -3
- package/dist/test/testUtils.d.ts +1 -0
- package/dist/test/testUtils.js +1 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.js +2 -1
- package/package.json +4 -3
|
@@ -4,6 +4,7 @@ import user_event from "@testing-library/user-event";
|
|
|
4
4
|
import { MemoryRouter, Route, Routes } from "react-router";
|
|
5
5
|
import { useGetBucketReplication, useSetBucketReplication } from "../../hooks/bucketConfiguration.js";
|
|
6
6
|
import { useBuckets } from "../../hooks/bucketOperations.js";
|
|
7
|
+
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
7
8
|
import { createTestWrapper, findToggleByLabel, mockErrorSubmit, mockOffsetSize, mockSuccessSubmit, submitForm } from "../../test/testUtils.js";
|
|
8
9
|
import { BucketReplicationFormPage } from "../buckets/BucketReplicationFormPage.js";
|
|
9
10
|
jest.mock('../../hooks/bucketConfiguration', ()=>({
|
|
@@ -13,9 +14,13 @@ jest.mock('../../hooks/bucketConfiguration', ()=>({
|
|
|
13
14
|
jest.mock('../../hooks/bucketOperations', ()=>({
|
|
14
15
|
useBuckets: jest.fn()
|
|
15
16
|
}));
|
|
17
|
+
jest.mock('../../hooks/useISVBucketDetection', ()=>({
|
|
18
|
+
useISVBucketStatus: jest.fn()
|
|
19
|
+
}));
|
|
16
20
|
const mockUseGetBucketReplication = jest.mocked(useGetBucketReplication);
|
|
17
21
|
const mockUseSetBucketReplication = jest.mocked(useSetBucketReplication);
|
|
18
22
|
const mockUseBuckets = jest.mocked(useBuckets);
|
|
23
|
+
const mockUseISVBucketStatus = jest.mocked(useISVBucketStatus);
|
|
19
24
|
const mockNavigate = jest.fn();
|
|
20
25
|
const mockShowToast = jest.fn();
|
|
21
26
|
jest.mock('react-router', ()=>({
|
|
@@ -55,8 +60,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
55
60
|
const mockMutate = jest.fn();
|
|
56
61
|
const fillRequiredFields = async (options)=>{
|
|
57
62
|
const { roleArn = 'arn:aws:iam::123456789012:role/replication-role', ruleId, targetBucket = 'destination-bucket' } = options;
|
|
58
|
-
await user_event.type(screen.
|
|
59
|
-
|
|
63
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
64
|
+
name: /role arn/i
|
|
65
|
+
}), roleArn);
|
|
66
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
67
|
+
name: /rule id/i
|
|
68
|
+
}), ruleId);
|
|
60
69
|
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
61
70
|
await user_event.click(targetBucketSelect);
|
|
62
71
|
await user_event.click(screen.getByRole('option', {
|
|
@@ -92,6 +101,15 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
92
101
|
},
|
|
93
102
|
status: 'success'
|
|
94
103
|
});
|
|
104
|
+
mockUseISVBucketStatus.mockReturnValue({
|
|
105
|
+
isVeeamBucket: false,
|
|
106
|
+
isCommvaultBucket: false,
|
|
107
|
+
isKastenBucket: false,
|
|
108
|
+
isISVManaged: false,
|
|
109
|
+
isvApplication: void 0,
|
|
110
|
+
isLoading: false,
|
|
111
|
+
bucketTagsStatus: 'success'
|
|
112
|
+
});
|
|
95
113
|
});
|
|
96
114
|
describe('Page Rendering', ()=>{
|
|
97
115
|
it('renders create mode with correct title', ()=>{
|
|
@@ -147,8 +165,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
147
165
|
it('displays all form sections', async ()=>{
|
|
148
166
|
renderBucketReplicationFormPage();
|
|
149
167
|
await waitFor(()=>{
|
|
150
|
-
expect(screen.
|
|
151
|
-
|
|
168
|
+
expect(screen.getByRole('textbox', {
|
|
169
|
+
name: /role arn/i
|
|
170
|
+
})).toBeInTheDocument();
|
|
171
|
+
expect(screen.getByRole('textbox', {
|
|
172
|
+
name: /rule id/i
|
|
173
|
+
})).toBeInTheDocument();
|
|
152
174
|
expect(screen.getByText('Replicate encrypted objects')).toBeInTheDocument();
|
|
153
175
|
expect(screen.getByText('Delete marker replication')).toBeInTheDocument();
|
|
154
176
|
});
|
|
@@ -157,14 +179,20 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
157
179
|
describe('Form Fields - Initial State', ()=>{
|
|
158
180
|
it('renders required form fields in create mode', ()=>{
|
|
159
181
|
renderBucketReplicationFormPage();
|
|
160
|
-
expect(screen.
|
|
161
|
-
|
|
182
|
+
expect(screen.getByRole('textbox', {
|
|
183
|
+
name: /role arn/i
|
|
184
|
+
})).toBeInTheDocument();
|
|
185
|
+
expect(screen.getByRole('textbox', {
|
|
186
|
+
name: /rule id/i
|
|
187
|
+
})).toBeInTheDocument();
|
|
162
188
|
expect(screen.getByLabelText(/status/i)).toBeInTheDocument();
|
|
163
189
|
expect(screen.getByLabelText(/target bucket/i)).toBeInTheDocument();
|
|
164
190
|
});
|
|
165
191
|
it('shows Role ARN input when no existing rules', ()=>{
|
|
166
192
|
renderBucketReplicationFormPage();
|
|
167
|
-
const roleInput = screen.
|
|
193
|
+
const roleInput = screen.getByRole('textbox', {
|
|
194
|
+
name: /role arn/i
|
|
195
|
+
});
|
|
168
196
|
expect(roleInput).toBeInTheDocument();
|
|
169
197
|
expect(roleInput.tagName).toBe('INPUT');
|
|
170
198
|
});
|
|
@@ -194,7 +222,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
194
222
|
});
|
|
195
223
|
it('shows Rule ID input in create mode', ()=>{
|
|
196
224
|
renderBucketReplicationFormPage();
|
|
197
|
-
const ruleIdInput = screen.
|
|
225
|
+
const ruleIdInput = screen.getByRole('textbox', {
|
|
226
|
+
name: /rule id/i
|
|
227
|
+
});
|
|
198
228
|
expect(ruleIdInput).toBeInTheDocument();
|
|
199
229
|
expect(ruleIdInput.tagName).toBe('INPUT');
|
|
200
230
|
});
|
|
@@ -229,14 +259,18 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
229
259
|
it('renders Status select field', async ()=>{
|
|
230
260
|
renderBucketReplicationFormPage();
|
|
231
261
|
await waitFor(()=>{
|
|
232
|
-
expect(screen.
|
|
262
|
+
expect(screen.getByRole('textbox', {
|
|
263
|
+
name: /rule id/i
|
|
264
|
+
})).toBeInTheDocument();
|
|
233
265
|
});
|
|
234
266
|
const statusElement = document.querySelector('[id="status"]');
|
|
235
267
|
expect(statusElement).toBeInTheDocument();
|
|
236
268
|
});
|
|
237
269
|
it('renders Priority number input with auto-assigned placeholder', ()=>{
|
|
238
270
|
renderBucketReplicationFormPage();
|
|
239
|
-
const priorityInput = screen.
|
|
271
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
272
|
+
name: /rule priority/i
|
|
273
|
+
});
|
|
240
274
|
expect(priorityInput).toBeInTheDocument();
|
|
241
275
|
expect(priorityInput).toHaveAttribute('placeholder', 'Example: Auto-assigned: 0');
|
|
242
276
|
});
|
|
@@ -255,7 +289,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
255
289
|
});
|
|
256
290
|
it('renders storage class select with all options', async ()=>{
|
|
257
291
|
renderBucketReplicationFormPage();
|
|
258
|
-
const storageClassSelect = screen.getByLabelText(/storage class/i
|
|
292
|
+
const storageClassSelect = screen.getByLabelText(/storage class/i, {
|
|
293
|
+
selector: 'input'
|
|
294
|
+
});
|
|
259
295
|
await user_event.click(storageClassSelect);
|
|
260
296
|
expect(screen.getByRole('option', {
|
|
261
297
|
name: 'Same as source'
|
|
@@ -283,7 +319,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
283
319
|
describe('Form Validation', ()=>{
|
|
284
320
|
it('validates Role ARN is required for first replication rule', async ()=>{
|
|
285
321
|
renderBucketReplicationFormPage();
|
|
286
|
-
const roleInput = screen.
|
|
322
|
+
const roleInput = screen.getByRole('textbox', {
|
|
323
|
+
name: /role arn/i
|
|
324
|
+
});
|
|
287
325
|
await user_event.type(roleInput, 'test');
|
|
288
326
|
await user_event.clear(roleInput);
|
|
289
327
|
await waitFor(()=>{
|
|
@@ -310,7 +348,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
310
348
|
status: 'success'
|
|
311
349
|
});
|
|
312
350
|
renderBucketReplicationFormPage();
|
|
313
|
-
await user_event.type(screen.
|
|
351
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
352
|
+
name: /rule id/i
|
|
353
|
+
}), 'new-rule');
|
|
314
354
|
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
315
355
|
await user_event.click(targetBucketSelect);
|
|
316
356
|
await user_event.click(screen.getByRole('option', {
|
|
@@ -325,7 +365,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
325
365
|
});
|
|
326
366
|
it('validates Rule ID is required', async ()=>{
|
|
327
367
|
renderBucketReplicationFormPage();
|
|
328
|
-
const ruleIdInput = screen.
|
|
368
|
+
const ruleIdInput = screen.getByRole('textbox', {
|
|
369
|
+
name: /rule id/i
|
|
370
|
+
});
|
|
329
371
|
await user_event.type(ruleIdInput, 'test');
|
|
330
372
|
await user_event.clear(ruleIdInput);
|
|
331
373
|
await waitFor(()=>{
|
|
@@ -352,7 +394,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
352
394
|
status: 'success'
|
|
353
395
|
});
|
|
354
396
|
renderBucketReplicationFormPage();
|
|
355
|
-
const ruleIdInput = screen.
|
|
397
|
+
const ruleIdInput = screen.getByRole('textbox', {
|
|
398
|
+
name: /rule id/i
|
|
399
|
+
});
|
|
356
400
|
await user_event.type(ruleIdInput, 'existing-rule');
|
|
357
401
|
await waitFor(()=>{
|
|
358
402
|
expect(screen.getByText(/a rule with this id already exists/i)).toBeInTheDocument();
|
|
@@ -360,8 +404,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
360
404
|
});
|
|
361
405
|
it('validates Priority must be >= 0', async ()=>{
|
|
362
406
|
renderBucketReplicationFormPage();
|
|
363
|
-
await user_event.type(screen.
|
|
364
|
-
|
|
407
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
408
|
+
name: /rule id/i
|
|
409
|
+
}), 'test-rule');
|
|
410
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
411
|
+
name: /rule priority/i
|
|
412
|
+
});
|
|
365
413
|
await user_event.clear(priorityInput);
|
|
366
414
|
await user_event.type(priorityInput, '-1');
|
|
367
415
|
await user_event.tab();
|
|
@@ -371,8 +419,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
371
419
|
});
|
|
372
420
|
it('disables submit button when Target Bucket is not selected', async ()=>{
|
|
373
421
|
renderBucketReplicationFormPage();
|
|
374
|
-
await user_event.type(screen.
|
|
375
|
-
|
|
422
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
423
|
+
name: /role arn/i
|
|
424
|
+
}), 'arn:aws:iam::123456789012:role/role');
|
|
425
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
426
|
+
name: /rule id/i
|
|
427
|
+
}), 'test-rule');
|
|
376
428
|
await waitFor(()=>{
|
|
377
429
|
const createButton = screen.getByRole('button', {
|
|
378
430
|
name: /create/i
|
|
@@ -385,7 +437,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
385
437
|
const sameAccountToggle = findToggleByLabel('Same account destination');
|
|
386
438
|
await user_event.click(sameAccountToggle);
|
|
387
439
|
await waitFor(()=>{
|
|
388
|
-
expect(screen.
|
|
440
|
+
expect(screen.getByRole('textbox', {
|
|
441
|
+
name: /target account id/i
|
|
442
|
+
})).toBeInTheDocument();
|
|
389
443
|
});
|
|
390
444
|
});
|
|
391
445
|
it('shows Replica KMS Key ID field when encryptReplicatedObjects is true', async ()=>{
|
|
@@ -393,7 +447,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
393
447
|
const encryptToggle = findToggleByLabel('Encrypt replicated objects');
|
|
394
448
|
await user_event.click(encryptToggle);
|
|
395
449
|
await waitFor(()=>{
|
|
396
|
-
expect(screen.
|
|
450
|
+
expect(screen.getByRole('textbox', {
|
|
451
|
+
name: /replica kms key id/i
|
|
452
|
+
})).toBeInTheDocument();
|
|
397
453
|
});
|
|
398
454
|
});
|
|
399
455
|
it('shows prefix field when filterType is prefix', async ()=>{
|
|
@@ -409,7 +465,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
409
465
|
name: 'Prefix filter'
|
|
410
466
|
}));
|
|
411
467
|
await waitFor(()=>{
|
|
412
|
-
expect(screen.
|
|
468
|
+
expect(screen.getByRole('textbox', {
|
|
469
|
+
name: /prefix/i
|
|
470
|
+
})).toBeInTheDocument();
|
|
413
471
|
});
|
|
414
472
|
});
|
|
415
473
|
});
|
|
@@ -505,7 +563,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
505
563
|
const sameAccountToggle = findToggleByLabel('Same account destination');
|
|
506
564
|
await user_event.click(sameAccountToggle);
|
|
507
565
|
await waitFor(()=>{
|
|
508
|
-
expect(screen.
|
|
566
|
+
expect(screen.getByRole('textbox', {
|
|
567
|
+
name: /target account id/i
|
|
568
|
+
})).toBeInTheDocument();
|
|
509
569
|
});
|
|
510
570
|
});
|
|
511
571
|
it('renders target bucket as Input for cross-account replication', async ()=>{
|
|
@@ -523,7 +583,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
523
583
|
const encryptToggle = findToggleByLabel('Encrypt replicated objects');
|
|
524
584
|
await user_event.click(encryptToggle);
|
|
525
585
|
await waitFor(()=>{
|
|
526
|
-
expect(screen.
|
|
586
|
+
expect(screen.getByRole('textbox', {
|
|
587
|
+
name: /replica kms key id/i
|
|
588
|
+
})).toBeInTheDocument();
|
|
527
589
|
});
|
|
528
590
|
});
|
|
529
591
|
});
|
|
@@ -556,9 +618,15 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
556
618
|
});
|
|
557
619
|
it('submits complete replication rule with all optional fields', async ()=>{
|
|
558
620
|
renderBucketReplicationFormPage();
|
|
559
|
-
await user_event.type(screen.
|
|
560
|
-
|
|
561
|
-
|
|
621
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
622
|
+
name: /role arn/i
|
|
623
|
+
}), 'arn:aws:iam::123456789012:role/replication-role');
|
|
624
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
625
|
+
name: /rule id/i
|
|
626
|
+
}), 'complete-rule');
|
|
627
|
+
await user_event.type(screen.getByRole('spinbutton', {
|
|
628
|
+
name: /rule priority/i
|
|
629
|
+
}), '5');
|
|
562
630
|
const filterSelect = document.querySelector('[id="filterType"]');
|
|
563
631
|
await user_event.click(filterSelect);
|
|
564
632
|
await waitFor(()=>{
|
|
@@ -570,15 +638,23 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
570
638
|
name: 'Prefix filter'
|
|
571
639
|
}));
|
|
572
640
|
await waitFor(()=>{
|
|
573
|
-
expect(screen.
|
|
641
|
+
expect(screen.getByRole('textbox', {
|
|
642
|
+
name: /prefix/i
|
|
643
|
+
})).toBeInTheDocument();
|
|
574
644
|
});
|
|
575
|
-
await user_event.type(screen.
|
|
645
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
646
|
+
name: /prefix/i
|
|
647
|
+
}), 'logs/');
|
|
576
648
|
const sameAccountToggle = findToggleByLabel('Same account destination');
|
|
577
649
|
await user_event.click(sameAccountToggle);
|
|
578
650
|
await waitFor(()=>{
|
|
579
|
-
expect(screen.
|
|
651
|
+
expect(screen.getByRole('textbox', {
|
|
652
|
+
name: /target account id/i
|
|
653
|
+
})).toBeInTheDocument();
|
|
580
654
|
});
|
|
581
|
-
await user_event.type(screen.
|
|
655
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
656
|
+
name: /target account id/i
|
|
657
|
+
}), '987654321098');
|
|
582
658
|
await user_event.type(screen.getByLabelText(/target bucket/i), 'cross-account-bucket');
|
|
583
659
|
const storageClassSelect = document.querySelector('[id="storageClass"]');
|
|
584
660
|
await user_event.click(storageClassSelect);
|
|
@@ -595,9 +671,13 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
595
671
|
const includeEncryptedToggle = findToggleByLabel('Replicate encrypted objects');
|
|
596
672
|
await user_event.click(includeEncryptedToggle);
|
|
597
673
|
await waitFor(()=>{
|
|
598
|
-
expect(screen.
|
|
674
|
+
expect(screen.getByRole('textbox', {
|
|
675
|
+
name: /replica kms key id/i
|
|
676
|
+
})).toBeInTheDocument();
|
|
599
677
|
});
|
|
600
|
-
await user_event.type(screen.
|
|
678
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
679
|
+
name: /replica kms key id/i
|
|
680
|
+
}), 'arn:aws:kms:us-east-1:987654321098:key/12345678-1234-1234-1234-123456789012');
|
|
601
681
|
const enforceRTCToggle = findToggleByLabel('Replication Time Control (RTC)');
|
|
602
682
|
await user_event.click(enforceRTCToggle);
|
|
603
683
|
const replicaModToggle = findToggleByLabel('Replica modification sync');
|
|
@@ -674,7 +754,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
674
754
|
status: 'success'
|
|
675
755
|
});
|
|
676
756
|
renderBucketReplicationFormPage();
|
|
677
|
-
await user_event.type(screen.
|
|
757
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
758
|
+
name: /rule id/i
|
|
759
|
+
}), 'new-rule');
|
|
678
760
|
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
679
761
|
await user_event.click(targetBucketSelect);
|
|
680
762
|
await user_event.click(screen.getByRole('option', {
|
|
@@ -753,7 +835,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
753
835
|
});
|
|
754
836
|
it('disables submit button when form is invalid', async ()=>{
|
|
755
837
|
renderBucketReplicationFormPage();
|
|
756
|
-
await user_event.type(screen.
|
|
838
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
839
|
+
name: /rule id/i
|
|
840
|
+
}), 'test');
|
|
757
841
|
await waitFor(()=>{
|
|
758
842
|
const createButton = screen.getByRole('button', {
|
|
759
843
|
name: /create/i
|
|
@@ -1033,7 +1117,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1033
1117
|
});
|
|
1034
1118
|
renderBucketReplicationFormPage('test-bucket', 'prefix-rule');
|
|
1035
1119
|
await waitFor(()=>{
|
|
1036
|
-
const prefixInput = screen.
|
|
1120
|
+
const prefixInput = screen.getByRole('textbox', {
|
|
1121
|
+
name: /prefix/i
|
|
1122
|
+
});
|
|
1037
1123
|
expect(prefixInput).toHaveValue('documents/');
|
|
1038
1124
|
});
|
|
1039
1125
|
});
|
|
@@ -1106,7 +1192,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1106
1192
|
});
|
|
1107
1193
|
renderBucketReplicationFormPage('test-bucket', 'and-rule');
|
|
1108
1194
|
await waitFor(()=>{
|
|
1109
|
-
const prefixInput = screen.
|
|
1195
|
+
const prefixInput = screen.getByRole('textbox', {
|
|
1196
|
+
name: /prefix/i
|
|
1197
|
+
});
|
|
1110
1198
|
expect(prefixInput).toHaveValue('logs/');
|
|
1111
1199
|
expect(screen.getByDisplayValue('type')).toBeInTheDocument();
|
|
1112
1200
|
expect(screen.getByDisplayValue('audit')).toBeInTheDocument();
|
|
@@ -1172,7 +1260,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1172
1260
|
await waitFor(()=>{
|
|
1173
1261
|
const encryptReplicatedToggle = findToggleByLabel('Encrypt replicated objects');
|
|
1174
1262
|
expect(encryptReplicatedToggle).toBeChecked();
|
|
1175
|
-
const kmsKeyInput = screen.
|
|
1263
|
+
const kmsKeyInput = screen.getByRole('textbox', {
|
|
1264
|
+
name: /replica kms key id/i
|
|
1265
|
+
});
|
|
1176
1266
|
expect(kmsKeyInput).toHaveValue('arn:aws:kms:us-east-1:123456789012:key/12345');
|
|
1177
1267
|
});
|
|
1178
1268
|
});
|
|
@@ -1300,7 +1390,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1300
1390
|
await waitFor(()=>{
|
|
1301
1391
|
const sameAccountToggle = screen.getByText(/not same account destination/i);
|
|
1302
1392
|
expect(sameAccountToggle).toBeInTheDocument();
|
|
1303
|
-
const accountIdInput = screen.
|
|
1393
|
+
const accountIdInput = screen.getByRole('textbox', {
|
|
1394
|
+
name: /target account id/i
|
|
1395
|
+
});
|
|
1304
1396
|
expect(accountIdInput).toHaveValue('987654321098');
|
|
1305
1397
|
const targetBucketInput = screen.getByLabelText(/target bucket/i);
|
|
1306
1398
|
expect(targetBucketInput).toHaveValue('cross-account-bucket');
|
|
@@ -1359,7 +1451,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1359
1451
|
});
|
|
1360
1452
|
renderBucketReplicationFormPage('test-bucket', 'storage-class-rule');
|
|
1361
1453
|
await waitFor(()=>{
|
|
1362
|
-
const storageClassSelect = screen.getByLabelText(/storage class/i
|
|
1454
|
+
const storageClassSelect = screen.getByLabelText(/storage class/i, {
|
|
1455
|
+
selector: 'input'
|
|
1456
|
+
});
|
|
1363
1457
|
expect(storageClassSelect).toBeInTheDocument();
|
|
1364
1458
|
});
|
|
1365
1459
|
});
|
|
@@ -1385,7 +1479,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1385
1479
|
});
|
|
1386
1480
|
renderBucketReplicationFormPage('test-bucket', 'priority-rule');
|
|
1387
1481
|
await waitFor(()=>{
|
|
1388
|
-
const priorityInput = screen.
|
|
1482
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1483
|
+
name: /rule priority/i
|
|
1484
|
+
});
|
|
1389
1485
|
expect(priorityInput).toHaveValue(99);
|
|
1390
1486
|
});
|
|
1391
1487
|
});
|
|
@@ -1393,7 +1489,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1393
1489
|
describe('Priority Auto-assignment', ()=>{
|
|
1394
1490
|
it('auto-assigns priority 0 when no existing rules', ()=>{
|
|
1395
1491
|
renderBucketReplicationFormPage();
|
|
1396
|
-
const priorityInput = screen.
|
|
1492
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1493
|
+
name: /rule priority/i
|
|
1494
|
+
});
|
|
1397
1495
|
expect(priorityInput).toHaveAttribute('placeholder', 'Example: Auto-assigned: 0');
|
|
1398
1496
|
});
|
|
1399
1497
|
it('auto-assigns next available priority when rules exist', ()=>{
|
|
@@ -1424,19 +1522,27 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1424
1522
|
status: 'success'
|
|
1425
1523
|
});
|
|
1426
1524
|
renderBucketReplicationFormPage();
|
|
1427
|
-
const priorityInput = screen.
|
|
1525
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1526
|
+
name: /rule priority/i
|
|
1527
|
+
});
|
|
1428
1528
|
expect(priorityInput).toHaveAttribute('placeholder', 'Example: Auto-assigned: 11');
|
|
1429
1529
|
});
|
|
1430
1530
|
it('allows manual priority override', async ()=>{
|
|
1431
1531
|
renderBucketReplicationFormPage();
|
|
1432
|
-
const priorityInput = screen.
|
|
1532
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1533
|
+
name: /rule priority/i
|
|
1534
|
+
});
|
|
1433
1535
|
await user_event.type(priorityInput, '25');
|
|
1434
1536
|
expect(priorityInput).toHaveValue(25);
|
|
1435
1537
|
});
|
|
1436
1538
|
it('accepts empty priority and defaults to 0 on submit', async ()=>{
|
|
1437
1539
|
renderBucketReplicationFormPage();
|
|
1438
|
-
await user_event.type(screen.
|
|
1439
|
-
|
|
1540
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
1541
|
+
name: /role arn/i
|
|
1542
|
+
}), 'arn:aws:iam::123456789012:role/role');
|
|
1543
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
1544
|
+
name: /rule id/i
|
|
1545
|
+
}), 'no-priority-rule');
|
|
1440
1546
|
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
1441
1547
|
await user_event.click(targetBucketSelect);
|
|
1442
1548
|
await user_event.click(screen.getByRole('option', {
|
|
@@ -1520,8 +1626,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1520
1626
|
isPending: true
|
|
1521
1627
|
});
|
|
1522
1628
|
renderBucketReplicationFormPage();
|
|
1523
|
-
await user_event.type(screen.
|
|
1524
|
-
|
|
1629
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
1630
|
+
name: /role arn/i
|
|
1631
|
+
}), 'arn:aws:iam::123456789012:role/role');
|
|
1632
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
1633
|
+
name: /rule id/i
|
|
1634
|
+
}), 'test-rule');
|
|
1525
1635
|
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
1526
1636
|
await user_event.click(targetBucketSelect);
|
|
1527
1637
|
await user_event.click(screen.getByRole('option', {
|
|
@@ -1619,7 +1729,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1619
1729
|
});
|
|
1620
1730
|
renderBucketReplicationFormPage('test-bucket', 'no-priority');
|
|
1621
1731
|
await waitFor(()=>{
|
|
1622
|
-
const priorityInput = screen.
|
|
1732
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1733
|
+
name: /rule priority/i
|
|
1734
|
+
});
|
|
1623
1735
|
expect(priorityInput).toHaveValue(null);
|
|
1624
1736
|
});
|
|
1625
1737
|
});
|
|
@@ -1645,7 +1757,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1645
1757
|
});
|
|
1646
1758
|
renderBucketReplicationFormPage('test-bucket', 'no-storage-class');
|
|
1647
1759
|
await waitFor(()=>{
|
|
1648
|
-
const storageClassSelect = screen.getByLabelText(/storage class/i
|
|
1760
|
+
const storageClassSelect = screen.getByLabelText(/storage class/i, {
|
|
1761
|
+
selector: 'input'
|
|
1762
|
+
});
|
|
1649
1763
|
expect(storageClassSelect).toBeInTheDocument();
|
|
1650
1764
|
});
|
|
1651
1765
|
});
|
|
@@ -1654,7 +1768,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1654
1768
|
it('accepts Rule ID with reasonable length', async ()=>{
|
|
1655
1769
|
renderBucketReplicationFormPage();
|
|
1656
1770
|
const longRuleId = 'rule-name-with-many-segments-' + 'segment-'.repeat(10);
|
|
1657
|
-
const ruleIdInput = screen.
|
|
1771
|
+
const ruleIdInput = screen.getByRole('textbox', {
|
|
1772
|
+
name: /rule id/i
|
|
1773
|
+
});
|
|
1658
1774
|
await user_event.type(ruleIdInput, longRuleId);
|
|
1659
1775
|
await waitFor(()=>{
|
|
1660
1776
|
expect(ruleIdInput).toHaveValue(longRuleId);
|
|
@@ -1663,7 +1779,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1663
1779
|
it('handles special characters in Rule ID', async ()=>{
|
|
1664
1780
|
renderBucketReplicationFormPage();
|
|
1665
1781
|
const validSpecialChars = 'rule-name_with.special-chars_123';
|
|
1666
|
-
const ruleIdInput = screen.
|
|
1782
|
+
const ruleIdInput = screen.getByRole('textbox', {
|
|
1783
|
+
name: /rule id/i
|
|
1784
|
+
});
|
|
1667
1785
|
await user_event.type(ruleIdInput, validSpecialChars);
|
|
1668
1786
|
await user_event.tab();
|
|
1669
1787
|
await waitFor(()=>{
|
|
@@ -1672,8 +1790,12 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1672
1790
|
});
|
|
1673
1791
|
it('validates Priority with boundary values', async ()=>{
|
|
1674
1792
|
renderBucketReplicationFormPage();
|
|
1675
|
-
await user_event.type(screen.
|
|
1676
|
-
|
|
1793
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
1794
|
+
name: /rule id/i
|
|
1795
|
+
}), 'boundary-test');
|
|
1796
|
+
const priorityInput = screen.getByRole('spinbutton', {
|
|
1797
|
+
name: /rule priority/i
|
|
1798
|
+
});
|
|
1677
1799
|
await user_event.clear(priorityInput);
|
|
1678
1800
|
await user_event.type(priorityInput, '0');
|
|
1679
1801
|
await user_event.tab();
|
|
@@ -1700,10 +1822,14 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1700
1822
|
name: 'Prefix filter'
|
|
1701
1823
|
}));
|
|
1702
1824
|
await waitFor(()=>{
|
|
1703
|
-
expect(screen.
|
|
1825
|
+
expect(screen.getByRole('textbox', {
|
|
1826
|
+
name: /prefix/i
|
|
1827
|
+
})).toBeInTheDocument();
|
|
1704
1828
|
});
|
|
1705
1829
|
const longPrefix = 'logs/' + 'a'.repeat(100);
|
|
1706
|
-
const prefixInput = screen.
|
|
1830
|
+
const prefixInput = screen.getByRole('textbox', {
|
|
1831
|
+
name: /prefix/i
|
|
1832
|
+
});
|
|
1707
1833
|
await user_event.type(prefixInput, longPrefix);
|
|
1708
1834
|
await waitFor(()=>{
|
|
1709
1835
|
expect(prefixInput).toHaveValue(longPrefix);
|
|
@@ -1711,7 +1837,9 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1711
1837
|
});
|
|
1712
1838
|
it('accepts valid Role ARN format', async ()=>{
|
|
1713
1839
|
renderBucketReplicationFormPage();
|
|
1714
|
-
const roleArnInput = screen.
|
|
1840
|
+
const roleArnInput = screen.getByRole('textbox', {
|
|
1841
|
+
name: /role arn/i
|
|
1842
|
+
});
|
|
1715
1843
|
await user_event.type(roleArnInput, 'arn:aws:iam::123456789012:role/replication-role');
|
|
1716
1844
|
await user_event.tab();
|
|
1717
1845
|
await waitFor(()=>{
|
|
@@ -1723,9 +1851,13 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1723
1851
|
const sameAccountToggle = findToggleByLabel('Same account destination');
|
|
1724
1852
|
await user_event.click(sameAccountToggle);
|
|
1725
1853
|
await waitFor(()=>{
|
|
1726
|
-
expect(screen.
|
|
1854
|
+
expect(screen.getByRole('textbox', {
|
|
1855
|
+
name: /target account id/i
|
|
1856
|
+
})).toBeInTheDocument();
|
|
1857
|
+
});
|
|
1858
|
+
const accountIdInput = screen.getByRole('textbox', {
|
|
1859
|
+
name: /target account id/i
|
|
1727
1860
|
});
|
|
1728
|
-
const accountIdInput = screen.getByLabelText(/target account id/i);
|
|
1729
1861
|
await user_event.type(accountIdInput, '123456789012');
|
|
1730
1862
|
await user_event.tab();
|
|
1731
1863
|
await waitFor(()=>{
|
|
@@ -1744,9 +1876,13 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1744
1876
|
const encryptToggle = findToggleByLabel('Encrypt replicated objects');
|
|
1745
1877
|
await user_event.click(encryptToggle);
|
|
1746
1878
|
await waitFor(()=>{
|
|
1747
|
-
expect(screen.
|
|
1879
|
+
expect(screen.getByRole('textbox', {
|
|
1880
|
+
name: /replica kms key id/i
|
|
1881
|
+
})).toBeInTheDocument();
|
|
1882
|
+
});
|
|
1883
|
+
const kmsKeyInput = screen.getByRole('textbox', {
|
|
1884
|
+
name: /replica kms key id/i
|
|
1748
1885
|
});
|
|
1749
|
-
const kmsKeyInput = screen.getByLabelText(/replica kms key id/i);
|
|
1750
1886
|
const validKmsArn = 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012';
|
|
1751
1887
|
await user_event.type(kmsKeyInput, validKmsArn);
|
|
1752
1888
|
await waitFor(()=>{
|
|
@@ -1754,4 +1890,66 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1754
1890
|
});
|
|
1755
1891
|
});
|
|
1756
1892
|
});
|
|
1893
|
+
describe('ISV Bucket Warning', ()=>{
|
|
1894
|
+
const setupISVMock = (isvApplication = 'Veeam')=>{
|
|
1895
|
+
mockUseISVBucketStatus.mockReturnValue({
|
|
1896
|
+
isVeeamBucket: 'Veeam' === isvApplication,
|
|
1897
|
+
isCommvaultBucket: 'Commvault' === isvApplication,
|
|
1898
|
+
isKastenBucket: 'Kasten' === isvApplication,
|
|
1899
|
+
isISVManaged: true,
|
|
1900
|
+
isvApplication,
|
|
1901
|
+
isLoading: false,
|
|
1902
|
+
bucketTagsStatus: 'success'
|
|
1903
|
+
});
|
|
1904
|
+
};
|
|
1905
|
+
it('renders ISV warning banner and checkbox when bucket is ISV-managed', ()=>{
|
|
1906
|
+
setupISVMock('Veeam');
|
|
1907
|
+
renderBucketReplicationFormPage();
|
|
1908
|
+
expect(screen.getByText(/bucket used for external integration with Veeam/i)).toBeInTheDocument();
|
|
1909
|
+
expect(screen.getByText(/rendering the replicated data unusable for recovery/i)).toBeInTheDocument();
|
|
1910
|
+
expect(screen.getByLabelText(/i understand what i'm doing/i)).toBeInTheDocument();
|
|
1911
|
+
});
|
|
1912
|
+
it('does not render ISV warning for non-ISV buckets', ()=>{
|
|
1913
|
+
renderBucketReplicationFormPage();
|
|
1914
|
+
expect(screen.queryByText(/bucket used for external integration with/i)).not.toBeInTheDocument();
|
|
1915
|
+
expect(screen.queryByLabelText(/i understand what i'm doing/i)).not.toBeInTheDocument();
|
|
1916
|
+
});
|
|
1917
|
+
it('blocks form submission when ISV checkbox is unchecked', async ()=>{
|
|
1918
|
+
setupISVMock('Veeam');
|
|
1919
|
+
renderBucketReplicationFormPage();
|
|
1920
|
+
await fillRequiredFields({
|
|
1921
|
+
ruleId: 'isv-rule'
|
|
1922
|
+
});
|
|
1923
|
+
await waitFor(()=>{
|
|
1924
|
+
const createButton = screen.getByRole('button', {
|
|
1925
|
+
name: /create/i
|
|
1926
|
+
});
|
|
1927
|
+
expect(createButton).toBeDisabled();
|
|
1928
|
+
});
|
|
1929
|
+
});
|
|
1930
|
+
it('allows form submission when ISV checkbox is checked', async ()=>{
|
|
1931
|
+
setupISVMock('Veeam');
|
|
1932
|
+
renderBucketReplicationFormPage();
|
|
1933
|
+
await fillRequiredFields({
|
|
1934
|
+
ruleId: 'isv-rule'
|
|
1935
|
+
});
|
|
1936
|
+
const checkbox = screen.getByLabelText(/i understand what i'm doing/i);
|
|
1937
|
+
await user_event.click(checkbox);
|
|
1938
|
+
mockSuccessSubmit(mockMutate);
|
|
1939
|
+
await submitForm('create');
|
|
1940
|
+
await waitFor(()=>{
|
|
1941
|
+
expect(mockMutate).toHaveBeenCalled();
|
|
1942
|
+
});
|
|
1943
|
+
});
|
|
1944
|
+
it('displays correct application name for Commvault ISV bucket', ()=>{
|
|
1945
|
+
setupISVMock('Commvault');
|
|
1946
|
+
renderBucketReplicationFormPage();
|
|
1947
|
+
expect(screen.getByText(/bucket used for external integration with Commvault/i)).toBeInTheDocument();
|
|
1948
|
+
});
|
|
1949
|
+
it('displays correct application name for Kasten ISV bucket', ()=>{
|
|
1950
|
+
setupISVMock('Kasten');
|
|
1951
|
+
renderBucketReplicationFormPage();
|
|
1952
|
+
expect(screen.getByText(/bucket used for external integration with Kasten/i)).toBeInTheDocument();
|
|
1953
|
+
});
|
|
1954
|
+
});
|
|
1757
1955
|
});
|