@spinnaker/google 2026.3.2 → 2026.4.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/autoscalingPolicy/GceAutoScalingFieldLayout.d.ts +2 -2
- package/dist/domain/loadBalancer.d.ts +6 -3
- package/dist/image/ImageSelect.d.ts +1 -1
- package/dist/index.js +159 -1
- package/dist/index.js.map +1 -1
- package/dist/loadBalancer/configure/common/gceLoadBalancerModels.d.ts +13 -2
- package/dist/loadBalancer/configure/http/GceHttpLoadBalancerEditor.d.ts +3 -0
- package/dist/loadBalancer/configure/http/GceHttpLoadBalancerModal.d.ts +1 -1
- package/dist/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerEditor.d.ts +30 -0
- package/dist/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerModal.d.ts +53 -0
- package/dist/loadBalancer/httpLoadBalancerUtils.service.d.ts +3 -1
- package/dist/serverGroup/configure/wizard/GceCloneServerGroupModal.d.ts +3 -0
- package/dist/serverGroup/configure/wizard/GceServerGroupWizard.types.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/customInstance/CustomInstanceConfigurer.d.ts +1 -1
- package/dist/serverGroup/configure/wizard/customInstance/GceCustomInstanceBuilder.d.ts +2 -2
- package/dist/serverGroup/configure/wizard/pages/AdvancedSettings.d.ts +3 -0
- package/dist/serverGroup/configure/wizard/pages/GceServerGroupLoadBalancers.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/pages/Policies.d.ts +21 -3
- package/dist/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupCapacity.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupImageSettings.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupInstanceType.d.ts +1 -0
- package/dist/serverGroup/configure/wizard/zones/GceInstanceFlexibilityConfigurer.d.ts +2 -2
- package/dist/serverGroup/details/GceInstanceFlexibilityPolicyDetails.d.ts +2 -2
- package/dist/serverGroup/details/stateful/MarkDiskStatefulButton.d.ts +2 -2
- package/dist/serverGroup/details/stateful/UpdateBootImageButton.d.ts +2 -2
- package/package.json +5 -5
- package/src/autoHealingPolicy/GceAutoHealingPolicyEditor.spec.tsx +68 -52
- package/src/autoscalingPolicy/GceAutoscalingPolicyEditor.spec.tsx +43 -50
- package/src/autoscalingPolicy/GceAutoscalingPolicyEditor.tsx +1 -1
- package/src/autoscalingPolicy/GceAutoscalingPolicyWriter.spec.ts +1 -1
- package/src/domain/loadBalancer.ts +6 -3
- package/src/gce.module.spec.ts +132 -153
- package/src/instance/details/GceInstanceDetails.spec.tsx +86 -83
- package/src/loadBalancer/configure/choice/GceLoadBalancerChoiceModal.spec.tsx +162 -121
- package/src/loadBalancer/configure/choice/GceLoadBalancerChoiceModal.tsx +13 -1
- package/src/loadBalancer/configure/common/GceProxyLoadBalancerEditor.spec.tsx +47 -30
- package/src/loadBalancer/configure/common/GceProxyLoadBalancerEditor.tsx +2 -1
- package/src/loadBalancer/configure/common/GceProxyLoadBalancerModal.spec.tsx +85 -57
- package/src/loadBalancer/configure/common/gceLoadBalancerData.spec.ts +17 -16
- package/src/loadBalancer/configure/common/gceLoadBalancerModels.spec.ts +230 -5
- package/src/loadBalancer/configure/common/gceLoadBalancerModels.ts +186 -22
- package/src/loadBalancer/configure/common/gceLoadBalancerSubmission.spec.ts +298 -2
- package/src/loadBalancer/configure/common/gceLoadBalancerSubmission.ts +35 -5
- package/src/loadBalancer/configure/common/useGceLoadBalancerData.spec.tsx +37 -46
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerEditor.spec.tsx +399 -58
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerEditor.tsx +148 -41
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerListenerEditor.spec.tsx +169 -36
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerListenerEditor.tsx +80 -12
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerModal.spec.tsx +224 -124
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerModal.tsx +8 -2
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerResourceEditors.spec.tsx +57 -22
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerResourceEditors.tsx +21 -0
- package/src/loadBalancer/configure/http/GceHttpLoadBalancerRoutingEditor.spec.tsx +24 -20
- package/src/loadBalancer/configure/network/GceNetworkLoadBalancerEditor.spec.tsx +41 -32
- package/src/loadBalancer/configure/network/GceNetworkLoadBalancerModal.spec.tsx +35 -30
- package/src/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerEditor.spec.tsx +443 -0
- package/src/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerEditor.tsx +401 -0
- package/src/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerModal.spec.tsx +330 -0
- package/src/loadBalancer/configure/network/GceRegionalExternalNetworkLoadBalancerModal.tsx +348 -0
- package/src/loadBalancer/details/gceLoadBalancerDetails.spec.tsx +439 -35
- package/src/loadBalancer/details/gceLoadBalancerDetails.tsx +104 -21
- package/src/loadBalancer/httpLoadBalancerUtils.service.spec.ts +126 -0
- package/src/loadBalancer/httpLoadBalancerUtils.service.ts +27 -11
- package/src/loadBalancer/loadBalancer.setTransformer.spec.ts +165 -0
- package/src/loadBalancer/loadBalancer.setTransformer.ts +15 -2
- package/src/pipeline/stages/googleStageConfig.spec.js +22 -16
- package/src/securityGroup/configure/GceSecurityGroupModal.spec.tsx +177 -193
- package/src/securityGroup/configure/GceSecurityGroupModal.tsx +14 -2
- package/src/securityGroup/details/GceSecurityGroupDetails.spec.tsx +69 -78
- package/src/serverGroup/configure/serverGroupCommandBuilder.service.spec.js +35 -15
- package/src/serverGroup/configure/serverGroupConfiguration.service.js +7 -1
- package/src/serverGroup/configure/serverGroupConfiguration.service.spec.js +74 -4
- package/src/serverGroup/configure/wizard/GceCloneServerGroupModal.spec.tsx +593 -855
- package/src/serverGroup/configure/wizard/GceCloneServerGroupModal.tsx +120 -38
- package/src/serverGroup/configure/wizard/GceServerGroupWizard.types.ts +1 -0
- package/src/serverGroup/configure/wizard/GceServerGroupWizardPage.spec.tsx +53 -50
- package/src/serverGroup/configure/wizard/customInstance/GceCustomInstanceBuilder.spec.tsx +65 -49
- package/src/serverGroup/configure/wizard/hiddenMetadataKeys.value.js +1 -0
- package/src/serverGroup/configure/wizard/pages/AdvancedSettings.spec.tsx +101 -108
- package/src/serverGroup/configure/wizard/pages/AdvancedSettings.tsx +32 -28
- package/src/serverGroup/configure/wizard/pages/GceServerGroupFirewalls.spec.tsx +60 -59
- package/src/serverGroup/configure/wizard/pages/GceServerGroupLoadBalancers.spec.tsx +240 -114
- package/src/serverGroup/configure/wizard/pages/GceServerGroupLoadBalancers.tsx +152 -63
- package/src/serverGroup/configure/wizard/pages/Policies.spec.tsx +93 -48
- package/src/serverGroup/configure/wizard/pages/Policies.tsx +80 -55
- package/src/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.spec.tsx +123 -94
- package/src/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.tsx +24 -18
- package/src/serverGroup/configure/wizard/pages/ServerGroupCapacity.spec.tsx +152 -133
- package/src/serverGroup/configure/wizard/pages/ServerGroupCapacity.tsx +40 -37
- package/src/serverGroup/configure/wizard/pages/ServerGroupImageSettings.spec.tsx +66 -60
- package/src/serverGroup/configure/wizard/pages/ServerGroupImageSettings.tsx +8 -2
- package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.spec.tsx +131 -101
- package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.tsx +29 -28
- package/src/serverGroup/configure/wizard/zones/GceInstanceFlexibilityConfigurer.spec.tsx +104 -81
- package/src/serverGroup/details/GceInstanceFlexibilityPolicyDetails.spec.tsx +10 -11
- package/src/serverGroup/details/autoHealingPolicy/GceAutoHealingPolicyDetails.spec.tsx +51 -59
- package/src/serverGroup/details/autoHealingPolicy/modal/GceUpsertAutoHealingPolicyModal.spec.tsx +3 -3
- package/src/serverGroup/details/autoscalingPolicy/GceAutoscalingPolicyDetails.spec.tsx +49 -58
- package/src/serverGroup/details/autoscalingPolicy/modal/GceUpsertAutoscalingPolicyModal.spec.tsx +3 -3
- package/src/serverGroup/details/gceServerGroupDetails.spec.tsx +162 -141
- package/src/serverGroup/details/resize/GceResizeServerGroupModal.spec.tsx +102 -86
- package/src/serverGroup/details/resize/GceResizeServerGroupModal.tsx +4 -0
- package/src/serverGroup/details/rollback/GceRollbackServerGroupModal.spec.tsx +40 -31
- package/src/serverGroup/serverGroup.transformer.js +1 -0
- package/src/serverGroup/serverGroup.transformer.spec.js +48 -0
- package/src/validation/ApplicationNameValidator.spec.ts +1 -1
- /package/dist/{gce.logo2ae85d8704b1d6b8.png → gce.logoChI3w_A5.png} +0 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { HelpTextExpandedContext } from '@spinnaker/core';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
GceInstanceFlexibilityConfigurer,
|
|
8
8
|
hasValidFlexibilityPolicy,
|
|
9
9
|
nextSelectionName,
|
|
10
10
|
} from './GceInstanceFlexibilityConfigurer';
|
|
11
|
+
import { setupUser } from '../../../../../../core/src/utils/testUtils/userEvent';
|
|
12
|
+
import '../../../../help/gce.help';
|
|
11
13
|
|
|
12
14
|
describe('GceInstanceFlexibilityConfigurer', () => {
|
|
13
15
|
const policy = {
|
|
@@ -17,15 +19,19 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
it('links the flexibility editor to its help content', () => {
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
render(
|
|
23
|
+
<HelpTextExpandedContext.Provider value={true}>
|
|
24
|
+
<GceInstanceFlexibilityConfigurer
|
|
25
|
+
regional={true}
|
|
26
|
+
targetShape="BALANCED"
|
|
27
|
+
setInstanceFlexibilityPolicy={vi.fn()}
|
|
28
|
+
/>
|
|
29
|
+
</HelpTextExpandedContext.Provider>,
|
|
26
30
|
);
|
|
27
31
|
|
|
28
|
-
expect(
|
|
32
|
+
expect(
|
|
33
|
+
screen.getByText(/Defines named sets of acceptable machine types for a regional managed instance group/),
|
|
34
|
+
).toBeInTheDocument();
|
|
29
35
|
});
|
|
30
36
|
|
|
31
37
|
it('allows EVEN when flexibility is absent', () => {
|
|
@@ -124,16 +130,15 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
124
130
|
}),
|
|
125
131
|
).toBe(false);
|
|
126
132
|
|
|
127
|
-
|
|
133
|
+
render(
|
|
128
134
|
<GceInstanceFlexibilityConfigurer
|
|
129
135
|
instanceFlexibilityPolicy={duplicatePolicy}
|
|
130
136
|
regional={true}
|
|
131
137
|
targetShape="BALANCED"
|
|
132
|
-
setInstanceFlexibilityPolicy={
|
|
138
|
+
setInstanceFlexibilityPolicy={vi.fn()}
|
|
133
139
|
/>,
|
|
134
140
|
);
|
|
135
|
-
expect(
|
|
136
|
-
expect(wrapper.find('[role="alert"]').text()).toBe('Machine types must be unique across instance selections.');
|
|
141
|
+
expect(screen.getByRole('alert')).toHaveTextContent(/^Machine types must be unique across instance selections\.$/);
|
|
137
142
|
});
|
|
138
143
|
|
|
139
144
|
it('accepts distinct machine types across selections', () => {
|
|
@@ -168,7 +173,7 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
168
173
|
});
|
|
169
174
|
|
|
170
175
|
it('announces submission errors and associates malformed persisted controls', () => {
|
|
171
|
-
|
|
176
|
+
render(
|
|
172
177
|
<GceInstanceFlexibilityConfigurer
|
|
173
178
|
instanceFlexibilityPolicy={{
|
|
174
179
|
instanceSelections: {
|
|
@@ -178,22 +183,21 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
178
183
|
regional={true}
|
|
179
184
|
targetShape="BALANCED"
|
|
180
185
|
validationError="Instance flexibility policy is invalid."
|
|
181
|
-
setInstanceFlexibilityPolicy={
|
|
186
|
+
setInstanceFlexibilityPolicy={vi.fn()}
|
|
182
187
|
/>,
|
|
183
188
|
);
|
|
184
|
-
const
|
|
185
|
-
const rankInput =
|
|
186
|
-
const blankMachineType =
|
|
187
|
-
const validMachineType =
|
|
188
|
-
|
|
189
|
-
expect(
|
|
190
|
-
expect(
|
|
191
|
-
expect(rankInput.
|
|
192
|
-
expect(
|
|
193
|
-
expect(blankMachineType.
|
|
194
|
-
expect(
|
|
195
|
-
expect(validMachineType.
|
|
196
|
-
expect(validMachineType.prop('aria-describedby')).toBeUndefined();
|
|
189
|
+
const alert = screen.getByRole('alert');
|
|
190
|
+
const rankInput = screen.getByLabelText('Rank (optional)');
|
|
191
|
+
const blankMachineType = screen.getByRole('textbox', { name: 'Machine type 1 for selection preferred' });
|
|
192
|
+
const validMachineType = screen.getByRole('textbox', { name: 'Machine type 2 for selection preferred' });
|
|
193
|
+
|
|
194
|
+
expect(alert).toHaveTextContent(/^Instance flexibility policy is invalid\.$/);
|
|
195
|
+
expect(rankInput).toBeInvalid();
|
|
196
|
+
expect(rankInput).toHaveAccessibleDescription('Instance flexibility policy is invalid.');
|
|
197
|
+
expect(blankMachineType).toBeInvalid();
|
|
198
|
+
expect(blankMachineType).toHaveAccessibleDescription('Instance flexibility policy is invalid.');
|
|
199
|
+
expect(validMachineType).toBeValid();
|
|
200
|
+
expect(validMachineType).not.toHaveAttribute('aria-describedby');
|
|
197
201
|
});
|
|
198
202
|
|
|
199
203
|
it('accepts regional BALANCED/ANY/ANY_SINGLE_ZONE with rankless selections', () => {
|
|
@@ -221,9 +225,10 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
221
225
|
expect(nextSelectionName(['selection-2'])).toBe('selection-1');
|
|
222
226
|
});
|
|
223
227
|
|
|
224
|
-
it('adds a named selection through the configurer', () => {
|
|
225
|
-
const
|
|
226
|
-
const
|
|
228
|
+
it('adds a named selection through the configurer', async () => {
|
|
229
|
+
const user = setupUser();
|
|
230
|
+
const setPolicy = vi.fn();
|
|
231
|
+
render(
|
|
227
232
|
<GceInstanceFlexibilityConfigurer
|
|
228
233
|
instanceFlexibilityPolicy={undefined}
|
|
229
234
|
regional={true}
|
|
@@ -232,7 +237,7 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
232
237
|
/>,
|
|
233
238
|
);
|
|
234
239
|
|
|
235
|
-
|
|
240
|
+
await user.click(screen.getByRole('button', { name: 'Add flexibility policy' }));
|
|
236
241
|
|
|
237
242
|
expect(setPolicy).toHaveBeenCalledWith({
|
|
238
243
|
instanceSelections: {
|
|
@@ -241,9 +246,10 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
241
246
|
});
|
|
242
247
|
});
|
|
243
248
|
|
|
244
|
-
it('does not overwrite an existing renamed selection when adding another', () => {
|
|
245
|
-
const
|
|
246
|
-
const
|
|
249
|
+
it('does not overwrite an existing renamed selection when adding another', async () => {
|
|
250
|
+
const user = setupUser();
|
|
251
|
+
const setPolicy = vi.fn();
|
|
252
|
+
render(
|
|
247
253
|
<GceInstanceFlexibilityConfigurer
|
|
248
254
|
instanceFlexibilityPolicy={{
|
|
249
255
|
instanceSelections: {
|
|
@@ -256,7 +262,7 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
256
262
|
/>,
|
|
257
263
|
);
|
|
258
264
|
|
|
259
|
-
|
|
265
|
+
await user.click(screen.getByRole('button', { name: 'Add selection' }));
|
|
260
266
|
|
|
261
267
|
expect(setPolicy).toHaveBeenCalledWith({
|
|
262
268
|
instanceSelections: {
|
|
@@ -266,9 +272,10 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
266
272
|
});
|
|
267
273
|
});
|
|
268
274
|
|
|
269
|
-
it('sends an explicit empty policy when the final selection is removed', () => {
|
|
270
|
-
const
|
|
271
|
-
const
|
|
275
|
+
it('sends an explicit empty policy when the final selection is removed', async () => {
|
|
276
|
+
const user = setupUser();
|
|
277
|
+
const setPolicy = vi.fn();
|
|
278
|
+
render(
|
|
272
279
|
<GceInstanceFlexibilityConfigurer
|
|
273
280
|
instanceFlexibilityPolicy={policy}
|
|
274
281
|
regional={true}
|
|
@@ -277,17 +284,14 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
277
284
|
/>,
|
|
278
285
|
);
|
|
279
286
|
|
|
280
|
-
|
|
281
|
-
.find('button')
|
|
282
|
-
.filterWhere((button) => button.text() === 'Remove')
|
|
283
|
-
.simulate('click');
|
|
287
|
+
await user.click(screen.getByRole('button', { name: 'Remove selection preferred' }));
|
|
284
288
|
|
|
285
289
|
expect(setPolicy).toHaveBeenCalledWith({ instanceSelections: {} });
|
|
286
290
|
});
|
|
287
291
|
|
|
288
292
|
it('only persists finite non-negative integer ranks and supports rank zero and clearing', () => {
|
|
289
|
-
const setPolicy =
|
|
290
|
-
|
|
293
|
+
const setPolicy = vi.fn();
|
|
294
|
+
render(
|
|
291
295
|
<GceInstanceFlexibilityConfigurer
|
|
292
296
|
instanceFlexibilityPolicy={policy}
|
|
293
297
|
regional={true}
|
|
@@ -295,24 +299,25 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
295
299
|
setInstanceFlexibilityPolicy={setPolicy}
|
|
296
300
|
/>,
|
|
297
301
|
);
|
|
298
|
-
const rankInput =
|
|
302
|
+
const rankInput = screen.getByRole('spinbutton', { name: 'Rank (optional)' });
|
|
299
303
|
|
|
300
|
-
expect(rankInput.
|
|
304
|
+
expect(rankInput).toHaveAttribute('step', '1');
|
|
301
305
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
306
|
+
// Non-numeric text cannot be entered into a number input (the DOM sanitizes it to ''), so only
|
|
307
|
+
// fractional and negative values are exercised as rejected ranks.
|
|
308
|
+
fireEvent.change(rankInput, { target: { value: '1.5' } });
|
|
309
|
+
fireEvent.change(rankInput, { target: { value: '-1' } });
|
|
305
310
|
expect(setPolicy).not.toHaveBeenCalled();
|
|
306
311
|
|
|
307
|
-
|
|
312
|
+
fireEvent.change(rankInput, { target: { value: '0' } });
|
|
308
313
|
expect(setPolicy).toHaveBeenCalledWith({
|
|
309
314
|
instanceSelections: {
|
|
310
315
|
preferred: { rank: 0, machineTypes: ['n2-standard-8'] },
|
|
311
316
|
},
|
|
312
317
|
});
|
|
313
318
|
|
|
314
|
-
setPolicy.
|
|
315
|
-
|
|
319
|
+
setPolicy.mockClear();
|
|
320
|
+
fireEvent.change(rankInput, { target: { value: '' } });
|
|
316
321
|
expect(setPolicy).toHaveBeenCalledWith({
|
|
317
322
|
instanceSelections: {
|
|
318
323
|
preferred: { machineTypes: ['n2-standard-8'] },
|
|
@@ -320,9 +325,10 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
320
325
|
});
|
|
321
326
|
});
|
|
322
327
|
|
|
323
|
-
it('resets blank and duplicate rename drafts to the current valid selection name', () => {
|
|
324
|
-
const
|
|
325
|
-
const
|
|
328
|
+
it('resets blank and duplicate rename drafts to the current valid selection name', async () => {
|
|
329
|
+
const user = setupUser();
|
|
330
|
+
const setPolicy = vi.fn();
|
|
331
|
+
render(
|
|
326
332
|
<GceInstanceFlexibilityConfigurer
|
|
327
333
|
instanceFlexibilityPolicy={{
|
|
328
334
|
instanceSelections: {
|
|
@@ -335,56 +341,73 @@ describe('GceInstanceFlexibilityConfigurer', () => {
|
|
|
335
341
|
setInstanceFlexibilityPolicy={setPolicy}
|
|
336
342
|
/>,
|
|
337
343
|
);
|
|
338
|
-
const preferredNameInput =
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
expect(
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
const preferredNameInput = screen.getByDisplayValue('preferred');
|
|
345
|
+
|
|
346
|
+
await user.clear(preferredNameInput);
|
|
347
|
+
await user.type(preferredNameInput, ' ');
|
|
348
|
+
await user.tab();
|
|
349
|
+
expect(preferredNameInput).toHaveValue('preferred');
|
|
350
|
+
|
|
351
|
+
await user.clear(preferredNameInput);
|
|
352
|
+
await user.type(preferredNameInput, 'fallback');
|
|
353
|
+
await user.tab();
|
|
354
|
+
expect(preferredNameInput).toHaveValue('preferred');
|
|
346
355
|
expect(setPolicy).not.toHaveBeenCalled();
|
|
347
356
|
});
|
|
348
357
|
|
|
349
358
|
it('associates labels and contextual accessible names with selection controls', () => {
|
|
350
|
-
|
|
359
|
+
render(
|
|
351
360
|
<GceInstanceFlexibilityConfigurer
|
|
352
361
|
instanceFlexibilityPolicy={policy}
|
|
353
362
|
regional={true}
|
|
354
363
|
targetShape="BALANCED"
|
|
355
|
-
setInstanceFlexibilityPolicy={
|
|
364
|
+
setInstanceFlexibilityPolicy={vi.fn()}
|
|
356
365
|
/>,
|
|
357
366
|
);
|
|
358
367
|
const selectionId = 'instance-flexibility-selection-preferred';
|
|
359
368
|
|
|
360
|
-
expect(
|
|
361
|
-
expect(
|
|
362
|
-
expect(
|
|
363
|
-
|
|
364
|
-
expect(wrapper.find(`input[aria-label="Machine type 1 for selection preferred"]`).prop('id')).toBe(
|
|
369
|
+
expect(screen.getByRole('textbox', { name: 'Selection name' })).toHaveAttribute('id', `${selectionId}-name`);
|
|
370
|
+
expect(screen.getByRole('spinbutton', { name: 'Rank (optional)' })).toHaveAttribute('id', `${selectionId}-rank`);
|
|
371
|
+
expect(screen.getByRole('textbox', { name: 'Machine type 1 for selection preferred' })).toHaveAttribute(
|
|
372
|
+
'id',
|
|
365
373
|
`${selectionId}-machine-type-0`,
|
|
366
374
|
);
|
|
367
|
-
expect(
|
|
368
|
-
expect(
|
|
375
|
+
expect(screen.getByRole('button', { name: 'Remove selection preferred' })).toBeInTheDocument();
|
|
376
|
+
expect(screen.getByRole('button', { name: 'Remove machine type 1 from selection preferred' })).toBeInTheDocument();
|
|
369
377
|
});
|
|
370
378
|
|
|
371
379
|
it('rerenders when policy and sibling primitive props change identity', () => {
|
|
372
|
-
const
|
|
380
|
+
const setPolicy = vi.fn();
|
|
381
|
+
const { rerender } = render(
|
|
373
382
|
<GceInstanceFlexibilityConfigurer
|
|
374
383
|
instanceFlexibilityPolicy={undefined}
|
|
375
384
|
regional={true}
|
|
376
385
|
targetShape="BALANCED"
|
|
377
|
-
setInstanceFlexibilityPolicy={
|
|
386
|
+
setInstanceFlexibilityPolicy={setPolicy}
|
|
378
387
|
/>,
|
|
379
388
|
);
|
|
380
389
|
|
|
381
|
-
expect(
|
|
390
|
+
expect(screen.getByRole('button', { name: 'Add flexibility policy' })).toBeInTheDocument();
|
|
382
391
|
|
|
383
|
-
|
|
384
|
-
|
|
392
|
+
rerender(
|
|
393
|
+
<GceInstanceFlexibilityConfigurer
|
|
394
|
+
instanceFlexibilityPolicy={policy}
|
|
395
|
+
regional={true}
|
|
396
|
+
targetShape="BALANCED"
|
|
397
|
+
setInstanceFlexibilityPolicy={setPolicy}
|
|
398
|
+
/>,
|
|
399
|
+
);
|
|
400
|
+
expect(screen.getByRole('button', { name: 'Remove selection preferred' })).toBeInTheDocument();
|
|
385
401
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
402
|
+
rerender(
|
|
403
|
+
<GceInstanceFlexibilityConfigurer
|
|
404
|
+
instanceFlexibilityPolicy={policy}
|
|
405
|
+
regional={false}
|
|
406
|
+
targetShape="EVEN"
|
|
407
|
+
setInstanceFlexibilityPolicy={setPolicy}
|
|
408
|
+
/>,
|
|
409
|
+
);
|
|
410
|
+
expect(screen.getByText('Flexibility requires a regional server group.')).toBeInTheDocument();
|
|
411
|
+
expect(screen.getByText(/not EVEN/)).toBeInTheDocument();
|
|
389
412
|
});
|
|
390
413
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
4
|
import { GceInstanceFlexibilityPolicyDetails } from './GceInstanceFlexibilityPolicyDetails';
|
|
5
5
|
|
|
6
6
|
describe('GceInstanceFlexibilityPolicyDetails', () => {
|
|
7
7
|
it('renders selection names, optional ranks, and machine types without duplicating target shape', () => {
|
|
8
|
-
const
|
|
8
|
+
const { container } = render(
|
|
9
9
|
<GceInstanceFlexibilityPolicyDetails
|
|
10
10
|
instanceFlexibilityPolicy={{
|
|
11
11
|
instanceSelections: {
|
|
@@ -16,17 +16,16 @@ describe('GceInstanceFlexibilityPolicyDetails', () => {
|
|
|
16
16
|
/>,
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
expect(
|
|
21
|
-
expect(
|
|
22
|
-
expect(
|
|
23
|
-
expect(
|
|
24
|
-
expect(
|
|
25
|
-
expect(text).not.toContain('Target Shape');
|
|
19
|
+
expect(container).toHaveTextContent('preferred');
|
|
20
|
+
expect(container).toHaveTextContent('n2-standard-8');
|
|
21
|
+
expect(container).toHaveTextContent('fallback');
|
|
22
|
+
expect(container).toHaveTextContent('1');
|
|
23
|
+
expect(container).toHaveTextContent('e2-standard-8, c3-standard-8');
|
|
24
|
+
expect(container).not.toHaveTextContent('Target Shape');
|
|
26
25
|
});
|
|
27
26
|
|
|
28
27
|
it('renders nothing when the policy is absent', () => {
|
|
29
|
-
const
|
|
30
|
-
expect(
|
|
28
|
+
const { container } = render(<GceInstanceFlexibilityPolicyDetails />);
|
|
29
|
+
expect(container).toBeEmptyDOMElement();
|
|
31
30
|
});
|
|
32
31
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import { shallow } from 'enzyme';
|
|
3
3
|
|
|
4
4
|
import { ConfirmationModalService } from '@spinnaker/core';
|
|
5
5
|
|
|
6
|
-
import { GceAutoscalingPolicyWriter } from '../../../autoscalingPolicy';
|
|
7
6
|
import { GceAutoHealingPolicyDetails } from './GceAutoHealingPolicyDetails';
|
|
7
|
+
import { GceAutoscalingPolicyWriter } from '../../../autoscalingPolicy';
|
|
8
8
|
import { GceUpsertAutoHealingPolicyModal } from './modal/GceUpsertAutoHealingPolicyModal';
|
|
9
9
|
|
|
10
10
|
describe('GceAutoHealingPolicyDetails', () => {
|
|
@@ -22,7 +22,7 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
22
22
|
const policy = { healthCheck: 'web', initialDelaySec: 0, maxUnavailable: { fixed: 0 } } as any;
|
|
23
23
|
|
|
24
24
|
it('summarizes zero-valued delay without rendering legacy max unavailable data', () => {
|
|
25
|
-
const
|
|
25
|
+
const { container } = render(
|
|
26
26
|
<GceAutoHealingPolicyDetails
|
|
27
27
|
application={application}
|
|
28
28
|
mutationsEnabled={true}
|
|
@@ -31,16 +31,16 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
31
31
|
/>,
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
-
expect(
|
|
35
|
-
expect(
|
|
36
|
-
expect(
|
|
37
|
-
expect(
|
|
34
|
+
expect(screen.getByText('web')).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText('0 seconds')).toBeInTheDocument();
|
|
36
|
+
expect(container).not.toHaveTextContent('Max Unavailable');
|
|
37
|
+
expect(container).not.toHaveTextContent('0 fixed');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('opens edit after managed-resource confirmation proceeds', async () => {
|
|
41
|
-
const show = spyOn(GceUpsertAutoHealingPolicyModal, 'show');
|
|
42
|
-
const confirm = spyOn(ConfirmationModalService, 'confirm').
|
|
43
|
-
|
|
41
|
+
const show = vi.spyOn(GceUpsertAutoHealingPolicyModal, 'show').mockReturnValue(undefined);
|
|
42
|
+
const confirm = vi.spyOn(ConfirmationModalService, 'confirm').mockReturnValue(Promise.resolve() as any);
|
|
43
|
+
render(
|
|
44
44
|
<GceAutoHealingPolicyDetails
|
|
45
45
|
application={application}
|
|
46
46
|
mutationsEnabled={true}
|
|
@@ -49,19 +49,17 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
49
49
|
/>,
|
|
50
50
|
);
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
fireEvent.click(screen.getByTestId('edit-auto-healing-policy'));
|
|
53
53
|
expect(show).not.toHaveBeenCalled();
|
|
54
|
-
await Promise.resolve();
|
|
55
|
-
await Promise.resolve();
|
|
56
54
|
|
|
57
|
-
expect(confirm).toHaveBeenCalledWith(
|
|
58
|
-
expect(show).toHaveBeenCalledWith({ application, serverGroup: managedServerGroup, policy });
|
|
55
|
+
expect(confirm).toHaveBeenCalledWith(expect.objectContaining({ header: 'Pause Management?' }));
|
|
56
|
+
await waitFor(() => expect(show).toHaveBeenCalledWith({ application, serverGroup: managedServerGroup, policy }));
|
|
59
57
|
});
|
|
60
58
|
|
|
61
59
|
it('does not open edit when managed-resource confirmation is cancelled', async () => {
|
|
62
|
-
const show = spyOn(GceUpsertAutoHealingPolicyModal, 'show');
|
|
63
|
-
spyOn(ConfirmationModalService, 'confirm').
|
|
64
|
-
|
|
60
|
+
const show = vi.spyOn(GceUpsertAutoHealingPolicyModal, 'show').mockReturnValue(undefined);
|
|
61
|
+
vi.spyOn(ConfirmationModalService, 'confirm').mockReturnValue(Promise.reject() as any);
|
|
62
|
+
render(
|
|
65
63
|
<GceAutoHealingPolicyDetails
|
|
66
64
|
application={application}
|
|
67
65
|
mutationsEnabled={true}
|
|
@@ -70,17 +68,16 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
70
68
|
/>,
|
|
71
69
|
);
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
await
|
|
75
|
-
await Promise.resolve();
|
|
71
|
+
fireEvent.click(screen.getByTestId('edit-auto-healing-policy'));
|
|
72
|
+
await waitFor(() => expect(ConfirmationModalService.confirm).toHaveBeenCalled());
|
|
76
73
|
|
|
77
74
|
expect(show).not.toHaveBeenCalled();
|
|
78
75
|
});
|
|
79
76
|
|
|
80
77
|
it('opens add after managed-resource confirmation proceeds', async () => {
|
|
81
|
-
const show = spyOn(GceUpsertAutoHealingPolicyModal, 'show');
|
|
82
|
-
const confirm = spyOn(ConfirmationModalService, 'confirm').
|
|
83
|
-
|
|
78
|
+
const show = vi.spyOn(GceUpsertAutoHealingPolicyModal, 'show').mockReturnValue(undefined);
|
|
79
|
+
const confirm = vi.spyOn(ConfirmationModalService, 'confirm').mockReturnValue(Promise.resolve() as any);
|
|
80
|
+
render(
|
|
84
81
|
<GceAutoHealingPolicyDetails
|
|
85
82
|
application={application}
|
|
86
83
|
mutationsEnabled={true}
|
|
@@ -89,19 +86,17 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
89
86
|
/>,
|
|
90
87
|
);
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
fireEvent.click(screen.getByTestId('add-auto-healing-policy'));
|
|
93
90
|
expect(show).not.toHaveBeenCalled();
|
|
94
|
-
await Promise.resolve();
|
|
95
|
-
await Promise.resolve();
|
|
96
91
|
|
|
97
|
-
expect(confirm).toHaveBeenCalledWith(
|
|
98
|
-
expect(show).toHaveBeenCalledWith({ application, serverGroup: managedServerGroup });
|
|
92
|
+
expect(confirm).toHaveBeenCalledWith(expect.objectContaining({ header: 'Pause Management?' }));
|
|
93
|
+
await waitFor(() => expect(show).toHaveBeenCalledWith({ application, serverGroup: managedServerGroup }));
|
|
99
94
|
});
|
|
100
95
|
|
|
101
96
|
it('does not open add when managed-resource confirmation is cancelled', async () => {
|
|
102
|
-
const show = spyOn(GceUpsertAutoHealingPolicyModal, 'show');
|
|
103
|
-
spyOn(ConfirmationModalService, 'confirm').
|
|
104
|
-
|
|
97
|
+
const show = vi.spyOn(GceUpsertAutoHealingPolicyModal, 'show').mockReturnValue(undefined);
|
|
98
|
+
vi.spyOn(ConfirmationModalService, 'confirm').mockReturnValue(Promise.reject() as any);
|
|
99
|
+
render(
|
|
105
100
|
<GceAutoHealingPolicyDetails
|
|
106
101
|
application={application}
|
|
107
102
|
mutationsEnabled={true}
|
|
@@ -110,20 +105,19 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
110
105
|
/>,
|
|
111
106
|
);
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
await
|
|
115
|
-
await Promise.resolve();
|
|
108
|
+
fireEvent.click(screen.getByTestId('add-auto-healing-policy'));
|
|
109
|
+
await waitFor(() => expect(ConfirmationModalService.confirm).toHaveBeenCalled());
|
|
116
110
|
|
|
117
111
|
expect(show).not.toHaveBeenCalled();
|
|
118
112
|
});
|
|
119
113
|
|
|
120
114
|
it('offers delete confirmation after managed-resource confirmation proceeds', async () => {
|
|
121
|
-
const confirm =
|
|
122
|
-
|
|
123
|
-
Promise.resolve() as any
|
|
124
|
-
|
|
125
|
-
const deletePolicy = spyOn(GceAutoscalingPolicyWriter, 'deleteAutoHealingPolicy');
|
|
126
|
-
|
|
115
|
+
const confirm = vi
|
|
116
|
+
.spyOn(ConfirmationModalService, 'confirm')
|
|
117
|
+
.mockReturnValueOnce(Promise.resolve() as any)
|
|
118
|
+
.mockReturnValueOnce(Promise.resolve() as any);
|
|
119
|
+
const deletePolicy = vi.spyOn(GceAutoscalingPolicyWriter, 'deleteAutoHealingPolicy').mockReturnValue(undefined);
|
|
120
|
+
render(
|
|
127
121
|
<GceAutoHealingPolicyDetails
|
|
128
122
|
application={application}
|
|
129
123
|
mutationsEnabled={true}
|
|
@@ -132,12 +126,10 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
132
126
|
/>,
|
|
133
127
|
);
|
|
134
128
|
|
|
135
|
-
|
|
136
|
-
await
|
|
137
|
-
await Promise.resolve();
|
|
129
|
+
fireEvent.click(screen.getByTestId('delete-auto-healing-policy'));
|
|
130
|
+
await waitFor(() => expect(confirm.mock.calls.length).toBe(2));
|
|
138
131
|
|
|
139
|
-
|
|
140
|
-
const deleteConfirmation = confirm.calls.mostRecent().args[0];
|
|
132
|
+
const deleteConfirmation = confirm.mock.lastCall[0];
|
|
141
133
|
deleteConfirmation.submitMethod();
|
|
142
134
|
|
|
143
135
|
expect(deletePolicy).toHaveBeenCalledWith(application, managedServerGroup);
|
|
@@ -147,9 +139,9 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
147
139
|
const cancelledConfirmation = {
|
|
148
140
|
then: (_onProceed: () => void, onCancel: () => void) => Promise.resolve(onCancel()),
|
|
149
141
|
} as any;
|
|
150
|
-
const confirm = spyOn(ConfirmationModalService, 'confirm').
|
|
151
|
-
const deletePolicy = spyOn(GceAutoscalingPolicyWriter, 'deleteAutoHealingPolicy');
|
|
152
|
-
|
|
142
|
+
const confirm = vi.spyOn(ConfirmationModalService, 'confirm').mockReturnValue(cancelledConfirmation);
|
|
143
|
+
const deletePolicy = vi.spyOn(GceAutoscalingPolicyWriter, 'deleteAutoHealingPolicy').mockReturnValue(undefined);
|
|
144
|
+
render(
|
|
153
145
|
<GceAutoHealingPolicyDetails
|
|
154
146
|
application={application}
|
|
155
147
|
mutationsEnabled={true}
|
|
@@ -158,17 +150,16 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
158
150
|
/>,
|
|
159
151
|
);
|
|
160
152
|
|
|
161
|
-
|
|
162
|
-
await
|
|
163
|
-
await Promise.resolve();
|
|
153
|
+
fireEvent.click(screen.getByTestId('delete-auto-healing-policy'));
|
|
154
|
+
await waitFor(() => expect(confirm).toHaveBeenCalled());
|
|
164
155
|
|
|
165
|
-
expect(confirm.calls.
|
|
166
|
-
expect(confirm).toHaveBeenCalledWith(
|
|
156
|
+
expect(confirm.mock.calls.length).toBe(1);
|
|
157
|
+
expect(confirm).toHaveBeenCalledWith(expect.objectContaining({ header: 'Pause Management?' }));
|
|
167
158
|
expect(deletePolicy).not.toHaveBeenCalled();
|
|
168
159
|
});
|
|
169
160
|
|
|
170
161
|
it('hides all mutation actions when mutations are disabled', () => {
|
|
171
|
-
const details =
|
|
162
|
+
const details = render(
|
|
172
163
|
<GceAutoHealingPolicyDetails
|
|
173
164
|
application={application}
|
|
174
165
|
mutationsEnabled={false}
|
|
@@ -176,7 +167,10 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
176
167
|
policy={policy}
|
|
177
168
|
/>,
|
|
178
169
|
);
|
|
179
|
-
|
|
170
|
+
expect(details.queryByTestId('edit-auto-healing-policy')).not.toBeInTheDocument();
|
|
171
|
+
expect(details.queryByTestId('delete-auto-healing-policy')).not.toBeInTheDocument();
|
|
172
|
+
details.unmount();
|
|
173
|
+
const emptyDetails = render(
|
|
180
174
|
<GceAutoHealingPolicyDetails
|
|
181
175
|
application={application}
|
|
182
176
|
mutationsEnabled={false}
|
|
@@ -185,8 +179,6 @@ describe('GceAutoHealingPolicyDetails', () => {
|
|
|
185
179
|
/>,
|
|
186
180
|
);
|
|
187
181
|
|
|
188
|
-
expect(
|
|
189
|
-
expect(details.find('[data-testid="delete-auto-healing-policy"]').exists()).toBe(false);
|
|
190
|
-
expect(emptyDetails.isEmptyRender()).toBe(true);
|
|
182
|
+
expect(emptyDetails.container).toBeEmptyDOMElement();
|
|
191
183
|
});
|
|
192
184
|
});
|
package/src/serverGroup/details/autoHealingPolicy/modal/GceUpsertAutoHealingPolicyModal.spec.tsx
CHANGED
|
@@ -23,15 +23,15 @@ describe('GceUpsertAutoHealingPolicyModal', () => {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
it('retains edited policy state when task creation is rejected', async () => {
|
|
26
|
-
spyOn(GceAutoscalingPolicyWriter, 'upsertAutoHealingPolicy').
|
|
26
|
+
vi.spyOn(GceAutoscalingPolicyWriter, 'upsertAutoHealingPolicy').mockReturnValue(
|
|
27
27
|
Promise.reject({ failureMessage: 'No permission' }),
|
|
28
28
|
);
|
|
29
29
|
const modal = new GceUpsertAutoHealingPolicyModal({
|
|
30
30
|
application: { name: 'my-app' },
|
|
31
31
|
serverGroup: { account: 'my-account', name: 'my-app-main-v001', region: 'us-central1' },
|
|
32
32
|
policy: { healthCheck: 'web', initialDelaySec: 300 },
|
|
33
|
-
closeModal:
|
|
34
|
-
dismissModal:
|
|
33
|
+
closeModal: vi.fn(),
|
|
34
|
+
dismissModal: vi.fn(),
|
|
35
35
|
} as any);
|
|
36
36
|
const editedPolicy = { healthCheck: 'web', initialDelaySec: 0 };
|
|
37
37
|
modal.state.policy = editedPolicy;
|