@spinnaker/google 2026.3.1 → 2026.4.0
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,5 +1,5 @@
|
|
|
1
|
+
import { fireEvent, render, within } from '@testing-library/react';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import { shallow } from 'enzyme';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
GceHttpLoadBalancerBackendServiceEditor,
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
|
|
9
9
|
describe('GceHttpLoadBalancerResourceEditors', () => {
|
|
10
10
|
it('edits complete health-check objects without dropping unknown fields', () => {
|
|
11
|
-
const onChange =
|
|
12
|
-
const
|
|
11
|
+
const onChange = vi.fn();
|
|
12
|
+
const { getByTestId, getAllByRole } = render(
|
|
13
13
|
<GceHttpLoadBalancerHealthCheckEditor
|
|
14
14
|
healthCheck={{
|
|
15
15
|
checkIntervalSec: 10,
|
|
@@ -22,40 +22,69 @@ describe('GceHttpLoadBalancerResourceEditors', () => {
|
|
|
22
22
|
}}
|
|
23
23
|
healthChecks={[{ name: 'check-a' }]}
|
|
24
24
|
onChange={onChange}
|
|
25
|
-
onRemove={
|
|
25
|
+
onRemove={vi.fn()}
|
|
26
26
|
/>,
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
fireEvent.change(getByTestId('health-check-port'), { target: { value: '8080' } });
|
|
30
30
|
|
|
31
31
|
expect(onChange).toHaveBeenCalledWith(
|
|
32
|
-
|
|
32
|
+
expect.objectContaining({ name: 'check-a', port: 8080, requestPath: '/health', unknownField: 'keep' }),
|
|
33
33
|
);
|
|
34
|
-
expect(
|
|
34
|
+
expect(getAllByRole('button').every((button) => button.getAttribute('type') === 'button')).toBe(true);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('supports HTTP2 request paths and GRPC service names', () => {
|
|
38
|
-
const onChange =
|
|
39
|
-
const
|
|
38
|
+
const onChange = vi.fn();
|
|
39
|
+
const { getByTestId, queryByTestId, rerender } = render(
|
|
40
40
|
<GceHttpLoadBalancerHealthCheckEditor
|
|
41
41
|
healthCheck={{ healthCheckType: 'GRPC', name: 'grpc-check', port: 443 }}
|
|
42
42
|
healthChecks={[]}
|
|
43
43
|
onChange={onChange}
|
|
44
|
-
onRemove={
|
|
44
|
+
onRemove={vi.fn()}
|
|
45
45
|
/>,
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
-
expect(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
expect(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
expect(
|
|
48
|
+
expect(optionValues(getByTestId('health-check-protocol'))).toContain('HTTP2');
|
|
49
|
+
expect(optionValues(getByTestId('health-check-protocol'))).toContain('GRPC');
|
|
50
|
+
expect(getByTestId('health-check-grpc-service-name')).toBeInTheDocument();
|
|
51
|
+
expect(queryByTestId('health-check-path')).not.toBeInTheDocument();
|
|
52
|
+
|
|
53
|
+
fireEvent.change(getByTestId('health-check-grpc-service-name'), { target: { value: 'new.Service' } });
|
|
54
|
+
expect(onChange).toHaveBeenLastCalledWith(
|
|
55
|
+
expect.objectContaining({ grpcServiceName: 'new.Service', healthCheckType: 'GRPC' }),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
rerender(
|
|
59
|
+
<GceHttpLoadBalancerHealthCheckEditor
|
|
60
|
+
healthCheck={{ healthCheckType: 'HTTP2', name: 'http2-check', port: 443, requestPath: '/ready' }}
|
|
61
|
+
healthChecks={[]}
|
|
62
|
+
onChange={onChange}
|
|
63
|
+
onRemove={vi.fn()}
|
|
64
|
+
/>,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(getByTestId('health-check-path')).toHaveValue('/ready');
|
|
68
|
+
expect(queryByTestId('health-check-grpc-service-name')).not.toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('offers only HTTP and HTTPS backend protocols for EXTERNAL_MANAGED', () => {
|
|
72
|
+
const { getByTestId } = render(
|
|
73
|
+
<GceHttpLoadBalancerBackendServiceEditor
|
|
74
|
+
backendService={{ name: 'backend-a', protocol: 'HTTP' }}
|
|
75
|
+
backendServices={[]}
|
|
76
|
+
healthChecks={[]}
|
|
77
|
+
loadBalancerType="EXTERNAL_MANAGED"
|
|
78
|
+
onChange={vi.fn()}
|
|
79
|
+
onRemove={vi.fn()}
|
|
80
|
+
/>,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(optionValues(getByTestId('backend-service-protocol'))).toEqual(['HTTP', 'HTTPS']);
|
|
55
84
|
});
|
|
56
85
|
|
|
57
86
|
it('selects complete backend-service and health-check references', () => {
|
|
58
|
-
const onChange =
|
|
87
|
+
const onChange = vi.fn();
|
|
59
88
|
const backendServices = [
|
|
60
89
|
{
|
|
61
90
|
healthCheck: { name: 'check-a', selfLink: 'https://compute/healthChecks/check-a' },
|
|
@@ -65,22 +94,28 @@ describe('GceHttpLoadBalancerResourceEditors', () => {
|
|
|
65
94
|
unknownField: 'keep',
|
|
66
95
|
},
|
|
67
96
|
];
|
|
68
|
-
const
|
|
97
|
+
const { getByTestId, getAllByRole } = render(
|
|
69
98
|
<GceHttpLoadBalancerBackendServiceEditor
|
|
70
99
|
backendService={{ name: '' }}
|
|
71
100
|
backendServices={backendServices}
|
|
72
101
|
healthChecks={[{ name: 'check-a', selfLink: 'https://compute/healthChecks/check-a' }]}
|
|
73
102
|
loadBalancerType="HTTP"
|
|
74
103
|
onChange={onChange}
|
|
75
|
-
onRemove={
|
|
104
|
+
onRemove={vi.fn()}
|
|
76
105
|
/>,
|
|
77
106
|
);
|
|
78
107
|
|
|
79
|
-
|
|
108
|
+
fireEvent.change(getByTestId('backend-service-reference'), {
|
|
80
109
|
target: { value: 'backend-a' },
|
|
81
110
|
});
|
|
82
111
|
|
|
83
112
|
expect(onChange).toHaveBeenCalledWith(backendServices[0]);
|
|
84
|
-
expect(
|
|
113
|
+
expect(getAllByRole('button').every((button) => button.getAttribute('type') === 'button')).toBe(true);
|
|
85
114
|
});
|
|
86
115
|
});
|
|
116
|
+
|
|
117
|
+
function optionValues(select: HTMLElement): string[] {
|
|
118
|
+
return within(select)
|
|
119
|
+
.getAllByRole('option')
|
|
120
|
+
.map((option) => (option as HTMLOptionElement).value);
|
|
121
|
+
}
|
|
@@ -239,6 +239,27 @@ export function GceHttpLoadBalancerBackendServiceEditor({
|
|
|
239
239
|
onChange={(event) => onChange({ ...backendService, portName: event.target.value })}
|
|
240
240
|
/>
|
|
241
241
|
</label>
|
|
242
|
+
{loadBalancerType === 'EXTERNAL_MANAGED' && (
|
|
243
|
+
<label>
|
|
244
|
+
Protocol
|
|
245
|
+
<select
|
|
246
|
+
data-testid="backend-service-protocol"
|
|
247
|
+
value={backendService.protocol || 'HTTP'}
|
|
248
|
+
onChange={(event) =>
|
|
249
|
+
onChange({
|
|
250
|
+
...backendService,
|
|
251
|
+
protocol: event.target.value as IGceLoadBalancerBackendService['protocol'],
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
>
|
|
255
|
+
{['HTTP', 'HTTPS'].map((protocol) => (
|
|
256
|
+
<option key={protocol} value={protocol}>
|
|
257
|
+
{protocol}
|
|
258
|
+
</option>
|
|
259
|
+
))}
|
|
260
|
+
</select>
|
|
261
|
+
</label>
|
|
262
|
+
)}
|
|
242
263
|
<label>
|
|
243
264
|
Connection draining timeout
|
|
244
265
|
<input
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { fireEvent, render, within } from '@testing-library/react';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
GceHttpLoadBalancerHostRuleEditor,
|
|
@@ -13,8 +13,8 @@ describe('GceHttpLoadBalancerRoutingEditor', () => {
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
it('adds and removes exact nested path-rule rows with non-submit buttons', () => {
|
|
16
|
-
const onChange =
|
|
17
|
-
const
|
|
16
|
+
const onChange = vi.fn();
|
|
17
|
+
const { getByTestId, getAllByRole } = render(
|
|
18
18
|
<GceHttpLoadBalancerHostRuleEditor
|
|
19
19
|
backendServices={backendServices}
|
|
20
20
|
hostRule={{
|
|
@@ -25,11 +25,11 @@ describe('GceHttpLoadBalancerRoutingEditor', () => {
|
|
|
25
25
|
},
|
|
26
26
|
}}
|
|
27
27
|
onChange={onChange}
|
|
28
|
-
onRemove={
|
|
28
|
+
onRemove={vi.fn()}
|
|
29
29
|
/>,
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
fireEvent.click(getByTestId('add-path-rule'));
|
|
33
33
|
|
|
34
34
|
expect(onChange).toHaveBeenCalledWith({
|
|
35
35
|
hostPatterns: ['api.example.com'],
|
|
@@ -38,45 +38,49 @@ describe('GceHttpLoadBalancerRoutingEditor', () => {
|
|
|
38
38
|
pathRules: [{ backendService: backendServices[1], paths: ['/v1'] }, { paths: [] }],
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
|
-
expect(
|
|
41
|
+
expect(getAllByRole('button').every((button) => button.getAttribute('type') === 'button')).toBe(true);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('edits path lists and preserves complete unresolved backend references', () => {
|
|
45
|
-
const onChange =
|
|
46
|
-
const
|
|
45
|
+
const onChange = vi.fn();
|
|
46
|
+
const { getByTestId, getAllByRole } = render(
|
|
47
47
|
<GceHttpLoadBalancerPathRuleEditor
|
|
48
48
|
backendServices={backendServices}
|
|
49
49
|
onChange={onChange}
|
|
50
|
-
onRemove={
|
|
50
|
+
onRemove={vi.fn()}
|
|
51
51
|
pathRule={{ backendService: backendServices[1], paths: ['/v1'] }}
|
|
52
52
|
/>,
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
fireEvent.change(getByTestId('path-rule-paths'), { target: { value: '/v1, /v2' } });
|
|
56
|
+
fireEvent.change(getByTestId('path-rule-backend'), {
|
|
57
57
|
target: { value: 'default-backend' },
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
expect(onChange.calls
|
|
61
|
-
expect(onChange.calls
|
|
62
|
-
expect(
|
|
60
|
+
expect(onChange.mock.calls[0][0]).toEqual({ backendService: backendServices[1], paths: ['/v1', '/v2'] });
|
|
61
|
+
expect(onChange.mock.calls[1][0]).toEqual({ backendService: backendServices[0], paths: ['/v1'] });
|
|
62
|
+
expect(getAllByRole('button').every((button) => button.getAttribute('type') === 'button')).toBe(true);
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
it('requires every path matcher to select an explicit default backend', () => {
|
|
66
|
-
const
|
|
66
|
+
const { getByTestId } = render(
|
|
67
67
|
<GceHttpLoadBalancerHostRuleEditor
|
|
68
68
|
backendServices={backendServices}
|
|
69
69
|
hostRule={{
|
|
70
70
|
hostPatterns: ['api.example.com'],
|
|
71
71
|
pathMatcher: { defaultService: backendServices[0], pathRules: [] },
|
|
72
72
|
}}
|
|
73
|
-
onChange={
|
|
74
|
-
onRemove={
|
|
73
|
+
onChange={vi.fn()}
|
|
74
|
+
onRemove={vi.fn()}
|
|
75
75
|
/>,
|
|
76
76
|
);
|
|
77
|
-
const select =
|
|
77
|
+
const select = getByTestId('host-rule-default-backend');
|
|
78
78
|
|
|
79
|
-
expect(select
|
|
80
|
-
expect(
|
|
79
|
+
expect(select).toBeRequired();
|
|
80
|
+
expect(
|
|
81
|
+
within(select)
|
|
82
|
+
.getAllByRole('option')
|
|
83
|
+
.map((option) => (option as HTMLOptionElement).value),
|
|
84
|
+
).toEqual(['default-backend', 'api-backend']);
|
|
81
85
|
});
|
|
82
86
|
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
import { fireEvent, render, within } from '@testing-library/react';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import { shallow } from 'enzyme';
|
|
3
|
-
|
|
4
|
-
import type { IGceLoadBalancerData } from '../common';
|
|
5
3
|
|
|
6
4
|
import {
|
|
7
5
|
buildGceNetworkLoadBalancerOptions,
|
|
@@ -9,6 +7,7 @@ import {
|
|
|
9
7
|
validateGceNetworkLoadBalancerCommand,
|
|
10
8
|
} from './GceNetworkLoadBalancerEditor';
|
|
11
9
|
import { normalizeGceNetworkLoadBalancerCommand } from './GceNetworkLoadBalancerModal';
|
|
10
|
+
import type { IGceLoadBalancerData } from '../common';
|
|
12
11
|
|
|
13
12
|
describe('GceNetworkLoadBalancerEditor', () => {
|
|
14
13
|
it('keeps unavailable persisted address and network references in scoped options', () => {
|
|
@@ -57,8 +56,8 @@ describe('GceNetworkLoadBalancerEditor', () => {
|
|
|
57
56
|
},
|
|
58
57
|
'edit',
|
|
59
58
|
);
|
|
60
|
-
const
|
|
61
|
-
<GceNetworkLoadBalancerEditor command={command} data={emptyData()} onChange={
|
|
59
|
+
const { container } = render(
|
|
60
|
+
<GceNetworkLoadBalancerEditor command={command} data={emptyData()} onChange={vi.fn()} />,
|
|
62
61
|
);
|
|
63
62
|
|
|
64
63
|
[
|
|
@@ -78,25 +77,15 @@ describe('GceNetworkLoadBalancerEditor', () => {
|
|
|
78
77
|
'checkIntervalSec',
|
|
79
78
|
'healthyThreshold',
|
|
80
79
|
'unhealthyThreshold',
|
|
81
|
-
].forEach((
|
|
82
|
-
['name', 'credentials', 'region', 'network', 'targetPool', 'sessionAffinity'].forEach((
|
|
83
|
-
|
|
84
|
-
expect((control.find('input').exists() ? control.find('input') : control.find('select')).prop('disabled')).toBe(
|
|
85
|
-
true,
|
|
86
|
-
);
|
|
80
|
+
].forEach((name) => expect(field(container, name)).toBeInTheDocument());
|
|
81
|
+
['name', 'credentials', 'region', 'network', 'targetPool', 'sessionAffinity'].forEach((name) => {
|
|
82
|
+
expect(fieldControl(container, name)).toBeDisabled();
|
|
87
83
|
});
|
|
88
|
-
['address', 'protocol', 'portRange', 'healthCheckPort'].forEach((
|
|
89
|
-
|
|
90
|
-
expect(
|
|
91
|
-
(control.find('input').exists() ? control.find('input') : control.find('select')).prop('disabled'),
|
|
92
|
-
).not.toBe(true);
|
|
84
|
+
['address', 'protocol', 'portRange', 'healthCheckPort'].forEach((name) => {
|
|
85
|
+
expect(fieldControl(container, name)).not.toBeDisabled();
|
|
93
86
|
});
|
|
94
|
-
expect(
|
|
95
|
-
|
|
96
|
-
'TCP',
|
|
97
|
-
'UDP',
|
|
98
|
-
]);
|
|
99
|
-
expect(wrapper.find('[data-field="sessionAffinity"] option').map((option) => option.prop('value'))).toEqual([
|
|
87
|
+
expect(optionValues(fieldControl(container, 'protocol'))).toEqual(['', 'TCP', 'UDP']);
|
|
88
|
+
expect(optionValues(fieldControl(container, 'sessionAffinity'))).toEqual([
|
|
100
89
|
'',
|
|
101
90
|
'NONE',
|
|
102
91
|
'CLIENT_IP',
|
|
@@ -109,22 +98,24 @@ describe('GceNetworkLoadBalancerEditor', () => {
|
|
|
109
98
|
{ account: 'account-a', loadBalancerName: 'app-main', region: 'europe-west1' },
|
|
110
99
|
'create',
|
|
111
100
|
);
|
|
112
|
-
const onChange =
|
|
113
|
-
const
|
|
101
|
+
const onChange = vi.fn();
|
|
102
|
+
const { container } = render(
|
|
103
|
+
<GceNetworkLoadBalancerEditor command={command} data={emptyData()} onChange={onChange} />,
|
|
104
|
+
);
|
|
114
105
|
|
|
115
|
-
|
|
116
|
-
expect(onChange.
|
|
106
|
+
fireEvent.change(fieldControl(container, 'protocol'), { target: { value: 'UDP' } });
|
|
107
|
+
expect(onChange.mock.lastCall[0].listeners[0].protocol).toBe('UDP');
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
fireEvent.change(fieldControl(container, 'sessionAffinity'), {
|
|
119
110
|
target: { value: 'CLIENT_IP_PROTO' },
|
|
120
111
|
});
|
|
121
|
-
expect(onChange.
|
|
112
|
+
expect(onChange.mock.lastCall[0].sessionAffinity).toBe('CLIENT_IP_PROTO');
|
|
122
113
|
|
|
123
|
-
|
|
124
|
-
expect(onChange.
|
|
114
|
+
fireEvent.change(fieldControl(container, 'requestPath'), { target: { value: 'status' } });
|
|
115
|
+
expect(onChange.mock.lastCall[0].healthChecks[0].requestPath).toBe('/status');
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
expect(onChange.
|
|
117
|
+
fireEvent.click(fieldControl(container, 'healthCheckEnabled'));
|
|
118
|
+
expect(onChange.mock.lastCall[0].healthChecks).toEqual([]);
|
|
128
119
|
});
|
|
129
120
|
|
|
130
121
|
it('validates the exact required listener and enabled health-check fields', () => {
|
|
@@ -173,3 +164,21 @@ function emptyData(): IGceLoadBalancerData {
|
|
|
173
164
|
subnets: [],
|
|
174
165
|
};
|
|
175
166
|
}
|
|
167
|
+
|
|
168
|
+
function field(container: HTMLElement, name: string): HTMLElement | null {
|
|
169
|
+
return container.querySelector(`[data-field="${name}"]`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function fieldControl(container: HTMLElement, name: string): HTMLInputElement | HTMLSelectElement {
|
|
173
|
+
const control = field(container, name)?.querySelector('input, select');
|
|
174
|
+
if (!(control instanceof HTMLInputElement || control instanceof HTMLSelectElement)) {
|
|
175
|
+
throw new Error(`No control found for ${name}`);
|
|
176
|
+
}
|
|
177
|
+
return control;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function optionValues(select: HTMLElement): string[] {
|
|
181
|
+
return within(select)
|
|
182
|
+
.getAllByRole('option')
|
|
183
|
+
.map((option) => (option as HTMLOptionElement).value);
|
|
184
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
|
|
4
|
-
import { GceNetworkLoadBalancerEditor } from './GceNetworkLoadBalancerEditor';
|
|
5
4
|
import {
|
|
6
5
|
GceNetworkLoadBalancerModal,
|
|
7
6
|
normalizeGceNetworkLoadBalancerCommand,
|
|
@@ -39,7 +38,7 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
39
38
|
);
|
|
40
39
|
|
|
41
40
|
expect(command).toEqual(
|
|
42
|
-
|
|
41
|
+
expect.objectContaining({
|
|
43
42
|
credentials: 'account-a',
|
|
44
43
|
loadBalancerType: 'NETWORK',
|
|
45
44
|
mode: 'edit',
|
|
@@ -65,7 +64,7 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
65
64
|
},
|
|
66
65
|
]);
|
|
67
66
|
expect(command.healthChecks).toEqual([
|
|
68
|
-
|
|
67
|
+
expect.objectContaining({
|
|
69
68
|
checkIntervalSec: 15,
|
|
70
69
|
healthyThreshold: 3,
|
|
71
70
|
name: 'app-main-hc',
|
|
@@ -102,7 +101,7 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
102
101
|
portRange: '53',
|
|
103
102
|
protocol: 'UDP',
|
|
104
103
|
});
|
|
105
|
-
expect(command.healthChecks[0]).toEqual(
|
|
104
|
+
expect(command.healthChecks[0]).toEqual(expect.objectContaining({ port: 53, requestPath: '/health' }));
|
|
106
105
|
expect(command.sessionAffinity).toBe('CLIENT_IP');
|
|
107
106
|
});
|
|
108
107
|
|
|
@@ -113,7 +112,7 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
113
112
|
});
|
|
114
113
|
|
|
115
114
|
expect(command).toEqual(
|
|
116
|
-
|
|
115
|
+
expect.objectContaining({
|
|
117
116
|
credentials: 'account-a',
|
|
118
117
|
loadBalancerType: 'NETWORK',
|
|
119
118
|
mode: 'create',
|
|
@@ -140,31 +139,28 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
140
139
|
|
|
141
140
|
([null, undefined] as const).forEach((loadBalancer) => {
|
|
142
141
|
it(`initializes infrastructure create when the persisted load balancer is ${String(loadBalancer)}`, () => {
|
|
143
|
-
const
|
|
142
|
+
const { container } = render(
|
|
144
143
|
<GceNetworkLoadBalancerModal
|
|
145
144
|
app={application}
|
|
146
|
-
closeModal={
|
|
145
|
+
closeModal={vi.fn()}
|
|
147
146
|
data={emptyData()}
|
|
148
|
-
dismissModal={
|
|
147
|
+
dismissModal={vi.fn()}
|
|
149
148
|
loadBalancer={loadBalancer as any}
|
|
150
149
|
mode="create"
|
|
151
150
|
/>,
|
|
152
151
|
);
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
expect(
|
|
156
|
-
expect(
|
|
157
|
-
expect(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
unhealthyThreshold: 2,
|
|
166
|
-
},
|
|
167
|
-
]);
|
|
153
|
+
expect(screen.getByRole('heading', { name: 'Create Network Load Balancer' })).toBeInTheDocument();
|
|
154
|
+
expect(fieldControl(container, 'name')).toHaveValue('app');
|
|
155
|
+
expect(fieldControl(container, 'protocol')).toHaveValue('TCP');
|
|
156
|
+
expect(fieldControl(container, 'portRange')).toHaveValue('8080');
|
|
157
|
+
expect(fieldControl(container, 'healthCheckEnabled')).toBeChecked();
|
|
158
|
+
expect(fieldControl(container, 'healthCheckPort')).toHaveValue(80);
|
|
159
|
+
expect(fieldControl(container, 'requestPath')).toHaveValue('/');
|
|
160
|
+
expect(fieldControl(container, 'timeoutSec')).toHaveValue(5);
|
|
161
|
+
expect(fieldControl(container, 'checkIntervalSec')).toHaveValue(10);
|
|
162
|
+
expect(fieldControl(container, 'healthyThreshold')).toHaveValue(10);
|
|
163
|
+
expect(fieldControl(container, 'unhealthyThreshold')).toHaveValue(2);
|
|
168
164
|
});
|
|
169
165
|
});
|
|
170
166
|
|
|
@@ -227,7 +223,7 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
227
223
|
});
|
|
228
224
|
|
|
229
225
|
it('returns only the normalized command in pipeline mode', () => {
|
|
230
|
-
const executeTask =
|
|
226
|
+
const executeTask = vi.fn();
|
|
231
227
|
const command = validCommand('pipeline');
|
|
232
228
|
|
|
233
229
|
const result = submitGceNetworkLoadBalancerCommand(command, { application, executeTask });
|
|
@@ -239,13 +235,13 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
239
235
|
(['create', 'edit'] as const).forEach((mode) => {
|
|
240
236
|
it(`executes the direct normalized job in infrastructure ${mode} mode`, () => {
|
|
241
237
|
const task = Promise.resolve({ id: 'task' });
|
|
242
|
-
const executeTask =
|
|
238
|
+
const executeTask = vi.fn().mockReturnValue(task);
|
|
243
239
|
const command = validCommand(mode);
|
|
244
240
|
|
|
245
241
|
const result = submitGceNetworkLoadBalancerCommand(command, { application, executeTask });
|
|
246
242
|
|
|
247
243
|
expect(result).toBe(task);
|
|
248
|
-
expect(executeTask).
|
|
244
|
+
expect(executeTask).toHaveBeenCalledExactlyOnceWith({
|
|
249
245
|
application,
|
|
250
246
|
description: `${mode === 'edit' ? 'Update' : 'Create'} Load Balancer: app-main`,
|
|
251
247
|
job: [serializeGceNetworkLoadBalancerCommand(command)],
|
|
@@ -256,18 +252,19 @@ describe('GceNetworkLoadBalancerModal', () => {
|
|
|
256
252
|
it('exposes pipeline support and passes edit mode to the editor', () => {
|
|
257
253
|
expect(GceNetworkLoadBalancerModal.supportsPipelineConfig).toBe(true);
|
|
258
254
|
expect(typeof GceNetworkLoadBalancerModal.show).toBe('function');
|
|
259
|
-
const
|
|
255
|
+
const { container } = render(
|
|
260
256
|
<GceNetworkLoadBalancerModal
|
|
261
257
|
app={application}
|
|
262
|
-
closeModal={
|
|
258
|
+
closeModal={vi.fn()}
|
|
263
259
|
data={emptyData()}
|
|
264
|
-
dismissModal={
|
|
260
|
+
dismissModal={vi.fn()}
|
|
265
261
|
isNew={false}
|
|
266
262
|
loadBalancer={{ account: 'account-a', name: 'app-main', region: 'europe-west1' } as any}
|
|
267
263
|
/>,
|
|
268
264
|
);
|
|
269
265
|
|
|
270
|
-
expect(
|
|
266
|
+
expect(screen.getByRole('heading', { name: 'Edit app-main' })).toBeInTheDocument();
|
|
267
|
+
expect(fieldControl(container, 'name')).toBeDisabled();
|
|
271
268
|
});
|
|
272
269
|
});
|
|
273
270
|
|
|
@@ -301,3 +298,11 @@ function emptyData(): any {
|
|
|
301
298
|
subnets: [],
|
|
302
299
|
};
|
|
303
300
|
}
|
|
301
|
+
|
|
302
|
+
function fieldControl(container: HTMLElement, name: string): HTMLInputElement | HTMLSelectElement {
|
|
303
|
+
const control = container.querySelector(`[data-field="${name}"] input, [data-field="${name}"] select`);
|
|
304
|
+
if (!(control instanceof HTMLInputElement || control instanceof HTMLSelectElement)) {
|
|
305
|
+
throw new Error(`No control found for ${name}`);
|
|
306
|
+
}
|
|
307
|
+
return control;
|
|
308
|
+
}
|