Skip to content

Commit 287eb3e

Browse files
authored
[Response Ops] Es query rule "size" field re-initializes to 100 if set to 0 when editing (#213636)
Resolves #209427 ## Summary This PR fixes a bug when editing an es query rule with size set to 0. I also refactored the tests to use react testing library. ### Checklist Check the PR satisfies following conditions. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### To verify 1. Create an es query rule 2. Set the size to be 0 3. Save your rule 4. Edit your rule and verify that the size is set to 0 when you open the editor
1 parent 67d6707 commit 287eb3e

File tree

6 files changed

+158
-201
lines changed

6 files changed

+158
-201
lines changed

x-pack/platform/plugins/shared/stack_alerts/public/rule_types/es_query/expression/es_query_expression.test.tsx

Lines changed: 84 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
* 2.0.
66
*/
77

8-
import React from 'react';
8+
import React, { PropsWithChildren } from 'react';
9+
import { fireEvent, render, waitFor, screen, act } from '@testing-library/react';
10+
import { I18nProvider } from '@kbn/i18n-react';
911
import { of, Subject } from 'rxjs';
10-
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
11-
import { act } from 'react-dom/test-utils';
1212
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
1313
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
1414
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
@@ -106,6 +106,10 @@ const createDataPluginMock = () => {
106106
return dataMock;
107107
};
108108

109+
const AppWrapper = React.memo<PropsWithChildren<unknown>>(({ children }) => (
110+
<I18nProvider>{children}</I18nProvider>
111+
));
112+
109113
const dataMock = createDataPluginMock();
110114
const dataViewMock = dataViewPluginMocks.createStartContract();
111115
const unifiedSearchMock = unifiedSearchPluginMock.createStartContract();
@@ -151,76 +155,71 @@ describe('EsQueryRuleTypeExpression', () => {
151155
timeWindowSize: [],
152156
};
153157

154-
const wrapper = mountWithIntl(
155-
<EsQueryExpression
156-
unifiedSearch={unifiedSearchMock}
157-
ruleInterval="1m"
158-
ruleThrottle="1m"
159-
alertNotifyWhen="onThrottleInterval"
160-
ruleParams={alertParams}
161-
setRuleParams={() => {}}
162-
setRuleProperty={() => {}}
163-
errors={errors}
164-
data={dataMock}
165-
dataViews={dataViewMock}
166-
defaultActionGroupId=""
167-
actionGroups={[]}
168-
charts={chartsStartMock}
169-
onChangeMetaData={() => {}}
170-
/>
158+
return await act(async () =>
159+
render(
160+
<EsQueryExpression
161+
unifiedSearch={unifiedSearchMock}
162+
ruleInterval="1m"
163+
ruleThrottle="1m"
164+
alertNotifyWhen="onThrottleInterval"
165+
ruleParams={alertParams}
166+
setRuleParams={() => {}}
167+
setRuleProperty={() => {}}
168+
errors={errors}
169+
data={dataMock}
170+
dataViews={dataViewMock}
171+
defaultActionGroupId=""
172+
actionGroups={[]}
173+
charts={chartsStartMock}
174+
onChangeMetaData={() => {}}
175+
/>,
176+
{
177+
wrapper: AppWrapper,
178+
}
179+
)
171180
);
172-
173-
const update = async () =>
174-
await act(async () => {
175-
await nextTick();
176-
wrapper.update();
177-
});
178-
179-
await update();
180-
return wrapper;
181181
}
182182

183183
test('should render EsQueryRuleTypeExpression with expected components', async () => {
184-
const wrapper = await setup(defaultEsQueryExpressionParams);
185-
expect(wrapper.find('[data-test-subj="indexSelectPopover"]').exists()).toBeTruthy();
186-
expect(wrapper.find('[data-test-subj="sizeValueExpression"]').exists()).toBeTruthy();
187-
expect(wrapper.find('[data-test-subj="queryJsonEditor"]').exists()).toBeTruthy();
188-
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeFalsy();
189-
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy();
190-
expect(wrapper.find('[data-test-subj="thresholdExpression"]').exists()).toBeTruthy();
191-
expect(wrapper.find('[data-test-subj="forLastExpression"]').exists()).toBeTruthy();
192-
193-
const excludeHitsButton = wrapper.find(
194-
'[data-test-subj="excludeHitsFromPreviousRunExpression"]'
195-
);
196-
expect(excludeHitsButton.exists()).toBeTruthy();
197-
expect(excludeHitsButton.first().prop('checked')).toBeTruthy();
184+
const result = await setup(defaultEsQueryExpressionParams);
185+
expect(result.getByTestId('indexSelectPopover')).toBeInTheDocument();
186+
expect(result.getByTestId('sizeValueExpression')).toBeInTheDocument();
187+
expect(result.getByTestId('queryJsonEditor')).toBeInTheDocument();
188+
expect(result.getByTestId('thresholdPopover')).toBeInTheDocument();
189+
expect(result.getByTestId('forLastExpression')).toBeInTheDocument();
190+
expect(result.queryByTestId('testQuerySuccess')).not.toBeInTheDocument();
191+
expect(result.queryByTestId('testQueryError')).not.toBeInTheDocument();
192+
193+
expect(result.getByTestId('excludeHitsFromPreviousRunExpression')).toBeChecked();
198194

199-
const testQueryButton = wrapper.find('EuiButton[data-test-subj="testQuery"]');
200-
expect(testQueryButton.exists()).toBeTruthy();
201-
expect(testQueryButton.prop('disabled')).toBe(false);
195+
expect(result.getByTestId('testQuery')).not.toBeDisabled();
202196
});
203197

204198
test('should render Test Query button disabled if alert params are invalid', async () => {
205-
const wrapper = await setup({
199+
const result = await setup({
206200
...defaultEsQueryExpressionParams,
207201
timeField: null,
208202
} as unknown as EsQueryRuleParams<SearchType.esQuery>);
209-
const testQueryButton = wrapper.find('EuiButton[data-test-subj="testQuery"]');
210-
expect(testQueryButton.exists()).toBeTruthy();
211-
expect(testQueryButton.prop('disabled')).toBe(true);
203+
204+
expect(result.getByTestId('testQuery')).toBeDisabled();
212205
});
213206

214207
test('should show excludeHitsFromPreviousRun unchecked by default', async () => {
215-
const wrapper = await setup({
208+
const result = await setup({
216209
...defaultEsQueryExpressionParams,
217210
excludeHitsFromPreviousRun: undefined,
218211
} as unknown as EsQueryRuleParams<SearchType.esQuery>);
219-
const excludeMatchesCheckBox = wrapper.find(
220-
'EuiCheckbox[data-test-subj="excludeHitsFromPreviousRunExpression"]'
221-
);
222-
expect(excludeMatchesCheckBox.exists()).toBeTruthy();
223-
expect(excludeMatchesCheckBox.prop('checked')).toBe(false);
212+
213+
expect(result.getByTestId('excludeHitsFromPreviousRunExpression')).not.toBeChecked();
214+
});
215+
216+
test('should render EsQueryRuleTypeExpression with chosen size field', async () => {
217+
const result = await setup({
218+
...defaultEsQueryExpressionParams,
219+
size: 0,
220+
} as unknown as EsQueryRuleParams<SearchType.esQuery>);
221+
222+
expect(result.getByTestId('sizeValueExpression')).toHaveTextContent('Size 0');
224223
});
225224

226225
test('should show success message if ungrouped Test Query is successful', async () => {
@@ -232,19 +231,14 @@ describe('EsQueryRuleTypeExpression', () => {
232231
},
233232
});
234233
dataMock.search.search.mockImplementation(() => searchResponseMock$);
235-
const wrapper = await setup(defaultEsQueryExpressionParams);
236-
const testQueryButton = wrapper.find('button[data-test-subj="testQuery"]');
237-
testQueryButton.simulate('click');
238-
expect(dataMock.search.search).toHaveBeenCalled();
239-
await act(async () => {
240-
await nextTick();
241-
wrapper.update();
242-
});
243-
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeTruthy();
244-
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy();
245-
expect(wrapper.find('EuiText[data-test-subj="testQuerySuccess"]').text()).toEqual(
246-
`Query matched 1234 documents in the last 15s.`
247-
);
234+
await setup(defaultEsQueryExpressionParams);
235+
236+
fireEvent.click(screen.getByTestId('testQuery'));
237+
await waitFor(() => expect(dataMock.search.search).toBeCalled());
238+
239+
expect(screen.getByTestId('testQuerySuccess')).toBeInTheDocument();
240+
expect(screen.getByText('Query matched 1234 documents in the last 15s.')).toBeInTheDocument();
241+
expect(screen.queryByTestId('testQueryError')).not.toBeInTheDocument();
248242
});
249243

250244
test('should show success message if grouped Test Query is successful', async () => {
@@ -284,23 +278,18 @@ describe('EsQueryRuleTypeExpression', () => {
284278
},
285279
});
286280
dataMock.search.search.mockImplementation(() => searchResponseMock$);
287-
const wrapper = await setup({
281+
await setup({
288282
...defaultEsQueryExpressionParams,
289283
termField: 'the-term',
290284
termSize: 10,
291285
});
292-
const testQueryButton = wrapper.find('button[data-test-subj="testQuery"]');
293-
testQueryButton.simulate('click');
294-
expect(dataMock.search.search).toHaveBeenCalled();
295-
await act(async () => {
296-
await nextTick();
297-
wrapper.update();
298-
});
299-
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeTruthy();
300-
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy();
301-
expect(wrapper.find('EuiText[data-test-subj="testQuerySuccess"]').text()).toEqual(
302-
`Grouped query matched 5 groups in the last 15s.`
303-
);
286+
287+
fireEvent.click(screen.getByTestId('testQuery'));
288+
await waitFor(() => expect(dataMock.search.search).toBeCalled());
289+
290+
expect(screen.getByTestId('testQuerySuccess')).toBeInTheDocument();
291+
expect(screen.getByText('Grouped query matched 5 groups in the last 15s.')).toBeInTheDocument();
292+
expect(screen.queryByTestId('testQueryError')).not.toBeInTheDocument();
304293
});
305294

306295
test('should show success message if Test Query is successful (with partial result)', async () => {
@@ -319,41 +308,31 @@ describe('EsQueryRuleTypeExpression', () => {
319308
};
320309
const searchResponseMock$ = new Subject();
321310
dataMock.search.search.mockImplementation(() => searchResponseMock$);
322-
const wrapper = await setup(defaultEsQueryExpressionParams);
323-
const testQueryButton = wrapper.find('button[data-test-subj="testQuery"]');
311+
await setup(defaultEsQueryExpressionParams);
324312

325-
testQueryButton.simulate('click');
326-
expect(dataMock.search.search).toHaveBeenCalled();
327-
await act(async () => {
313+
fireEvent.click(screen.getByTestId('testQuery'));
314+
await waitFor(() => expect(dataMock.search.search).toBeCalled());
315+
await waitFor(() => {
328316
searchResponseMock$.next(partial);
329317
searchResponseMock$.next(complete);
330318
searchResponseMock$.complete();
331-
await nextTick();
332-
wrapper.update();
333319
});
334320

335-
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeTruthy();
336-
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy();
337-
expect(wrapper.find('EuiText[data-test-subj="testQuerySuccess"]').text()).toEqual(
338-
`Query matched 1234 documents in the last 15s.`
339-
);
321+
expect(screen.getByTestId('testQuerySuccess')).toBeInTheDocument();
322+
expect(screen.getByText('Query matched 1234 documents in the last 15s.')).toBeInTheDocument();
323+
expect(screen.queryByTestId('testQueryError')).not.toBeInTheDocument();
340324
});
341325

342326
test('should show error message if Test Query is throws error', async () => {
343327
dataMock.search.search.mockImplementation(() => {
344328
throw new Error('What is this query');
345329
});
346-
const wrapper = await setup(defaultEsQueryExpressionParams);
347-
const testQueryButton = wrapper.find('button[data-test-subj="testQuery"]');
348-
349-
testQueryButton.simulate('click');
350-
expect(dataMock.search.search).toHaveBeenCalled();
351-
await act(async () => {
352-
await nextTick();
353-
wrapper.update();
354-
});
330+
await setup(defaultEsQueryExpressionParams);
331+
332+
fireEvent.click(screen.getByTestId('testQuery'));
333+
await waitFor(() => expect(dataMock.search.search).toBeCalled());
355334

356-
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeFalsy();
357-
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeTruthy();
335+
expect(screen.queryByTestId('testQuerySuccess')).not.toBeInTheDocument();
336+
expect(screen.getByTestId('testQueryError')).toBeInTheDocument();
358337
});
359338
});

x-pack/platform/plugins/shared/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const EsQueryExpression: React.FC<
6868
timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT,
6969
threshold: threshold ?? DEFAULT_VALUES.THRESHOLD,
7070
thresholdComparator: thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR,
71-
size: size ? size : isServerless ? SERVERLESS_DEFAULT_VALUES.SIZE : DEFAULT_VALUES.SIZE,
71+
size: size ?? (isServerless ? SERVERLESS_DEFAULT_VALUES.SIZE : DEFAULT_VALUES.SIZE),
7272
esQuery: esQuery ?? DEFAULT_VALUES.QUERY,
7373
aggType: aggType ?? DEFAULT_VALUES.AGGREGATION_TYPE,
7474
groupBy: groupBy ?? DEFAULT_VALUES.GROUP_BY,
@@ -198,6 +198,7 @@ export const EsQueryExpression: React.FC<
198198
<Fragment>
199199
<EuiFormRow
200200
fullWidth
201+
data-test-subj="indexSelectPopover"
201202
label={
202203
<FormattedMessage
203204
id="xpack.stackAlerts.esQuery.ui.selectIndexPrompt"
@@ -207,7 +208,6 @@ export const EsQueryExpression: React.FC<
207208
>
208209
<IndexSelectPopover
209210
index={index}
210-
data-test-subj="indexSelectPopover"
211211
esFields={esFields}
212212
timeField={timeField}
213213
errors={errors}

0 commit comments

Comments
 (0)