Skip to content

Commit 153b7e1

Browse files
authored
[Fleet] Fix fleet server hosts client validation (#125085)
1 parent 8e8c4b8 commit 153b7e1

File tree

3 files changed

+102
-14
lines changed

3 files changed

+102
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { act } from 'react-test-renderer';
9+
10+
import { createFleetTestRendererMock } from '../../../../../../mock';
11+
12+
import { useFleetServerHostsForm } from './use_fleet_server_host_form';
13+
14+
jest.mock('../../services/agent_and_policies_count', () => ({
15+
...jest.requireActual('../../services/agent_and_policies_count'),
16+
getAgentAndPolicyCount: () => ({ agentCount: 0, agentPolicyCount: 0 }),
17+
}));
18+
jest.mock('../../hooks/use_confirm_modal', () => ({
19+
...jest.requireActual('../../hooks/use_confirm_modal'),
20+
useConfirmModal: () => ({ confirm: () => true }),
21+
}));
22+
23+
describe('useFleetServerHostsForm', () => {
24+
it('should not allow to submit an invalid form', async () => {
25+
const testRenderer = createFleetTestRendererMock();
26+
const onSucess = jest.fn();
27+
const { result } = testRenderer.renderHook(() => useFleetServerHostsForm([], onSucess));
28+
29+
act(() =>
30+
result.current.fleetServerHostsInput.props.onChange(['http://test.fr', 'http://test.fr'])
31+
);
32+
33+
await act(() => result.current.submit());
34+
35+
expect(result.current.fleetServerHostsInput.props.errors).toMatchInlineSnapshot(`
36+
Array [
37+
Object {
38+
"index": 0,
39+
"message": "Duplicate URL",
40+
},
41+
Object {
42+
"index": 1,
43+
"message": "Duplicate URL",
44+
},
45+
]
46+
`);
47+
expect(onSucess).not.toBeCalled();
48+
expect(result.current.isDisabled).toBeTruthy();
49+
});
50+
51+
it('should submit a valid form', async () => {
52+
const testRenderer = createFleetTestRendererMock();
53+
const onSucess = jest.fn();
54+
testRenderer.startServices.http.post.mockResolvedValue({});
55+
const { result } = testRenderer.renderHook(() => useFleetServerHostsForm([], onSucess));
56+
57+
act(() => result.current.fleetServerHostsInput.props.onChange(['http://test.fr']));
58+
59+
await act(() => result.current.submit());
60+
expect(onSucess).toBeCalled();
61+
});
62+
63+
it('should allow the user to correct and submit a invalid form', async () => {
64+
const testRenderer = createFleetTestRendererMock();
65+
const onSucess = jest.fn();
66+
testRenderer.startServices.http.post.mockResolvedValue({});
67+
const { result } = testRenderer.renderHook(() => useFleetServerHostsForm([], onSucess));
68+
69+
act(() =>
70+
result.current.fleetServerHostsInput.props.onChange(['http://test.fr', 'http://test.fr'])
71+
);
72+
73+
await act(() => result.current.submit());
74+
expect(onSucess).not.toBeCalled();
75+
expect(result.current.isDisabled).toBeTruthy();
76+
77+
act(() => result.current.fleetServerHostsInput.props.onChange(['http://test.fr']));
78+
expect(result.current.isDisabled).toBeFalsy();
79+
80+
await act(() => result.current.submit());
81+
expect(onSucess).toBeCalled();
82+
});
83+
});

x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/fleet_server_hosts_flyout/use_fleet_server_host_form.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export function useFleetServerHostsForm(
142142

143143
const submit = useCallback(async () => {
144144
try {
145-
if (!validate) {
145+
if (!validate()) {
146146
return;
147147
}
148148
const { agentCount, agentPolicyCount } = await getAgentAndPolicyCount();
@@ -178,9 +178,12 @@ export function useFleetServerHostsForm(
178178
}
179179
}, [fleetServerHostsInput.value, validate, notifications, confirm, onSuccess]);
180180

181+
const isDisabled =
182+
isLoading || !fleetServerHostsInput.hasChanged || fleetServerHostsInput.props.isInvalid;
183+
181184
return {
182185
isLoading,
183-
isDisabled: isLoading || !fleetServerHostsInput.hasChanged,
186+
isDisabled,
184187
submit,
185188
fleetServerHostsInput,
186189
};

x-pack/plugins/fleet/public/hooks/use_input.ts

+14-12
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,22 @@ export function useComboInput(
125125

126126
const isInvalid = errors !== undefined;
127127

128+
const validateCallback = useCallback(() => {
129+
if (validate) {
130+
const newErrors = validate(value);
131+
setErrors(newErrors);
132+
133+
return newErrors === undefined;
134+
}
135+
136+
return true;
137+
}, [validate, value]);
138+
128139
const onChange = useCallback(
129140
(newValues: string[]) => {
130141
setValue(newValues);
131-
if (errors && validate && validate(newValues) === undefined) {
132-
setErrors(undefined);
142+
if (errors && validate) {
143+
setErrors(validate(newValues));
133144
}
134145
},
135146
[validate, errors]
@@ -149,16 +160,7 @@ export function useComboInput(
149160
setValue([]);
150161
},
151162
setValue,
152-
validate: () => {
153-
if (validate) {
154-
const newErrors = validate(value);
155-
setErrors(newErrors);
156-
157-
return newErrors === undefined;
158-
}
159-
160-
return true;
161-
},
163+
validate: validateCallback,
162164
hasChanged,
163165
};
164166
}

0 commit comments

Comments
 (0)