diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 29eddb95..fbe1239e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,6 +11,7 @@ A clear and concise description of the bug. **How can one reproduce the bug?** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -20,9 +21,10 @@ Steps to reproduce the behavior: A clear and concise description of what you expected to happen. **What is your host/environment?** - - OS: [e.g. iOS] - - Version [e.g. 22] - - Plugins + +- OS: [e.g. iOS] +- Version [e.g. 22] +- Plugins **Do you have any screenshots?** If applicable, add screenshots to help explain your problem. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 6198f338..1bbccb57 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -5,6 +5,7 @@ title: '[FEATURE]' labels: 'enhancement, untriaged' assignees: '' --- + **Is your feature request related to a problem?** A clear and concise description of what the problem is, e.g. _I'm always frustrated when [...]_ @@ -15,4 +16,4 @@ A clear and concise description of what you want to happen. A clear and concise description of any alternative solutions or features you've considered. **Do you have any additional context?** -Add any other context or screenshots about the feature request here. \ No newline at end of file +Add any other context or screenshots about the feature request here. diff --git a/global-setup.js b/global-setup.js new file mode 100644 index 00000000..3c578000 --- /dev/null +++ b/global-setup.js @@ -0,0 +1,3 @@ +export default () => { + process.env.TZ = 'UTC'; + } \ No newline at end of file diff --git a/public/components/CodeModal/__tests__/CodeModal.test.tsx b/public/components/CodeModal/__tests__/CodeModal.test.tsx index b8dfbcbc..6a7de3f3 100644 --- a/public/components/CodeModal/__tests__/CodeModal.test.tsx +++ b/public/components/CodeModal/__tests__/CodeModal.test.tsx @@ -13,7 +13,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { CodeModal } from '../CodeModal'; -describe('CodeMOdal spec', () => { +describe('CodeModal spec', () => { const onVisibilityChange = jest.fn(() => true); const onCloseModal = jest.fn(); diff --git a/public/components/CodeModal/__tests__/__snapshots__/CodeModal.test.tsx.snap b/public/components/CodeModal/__tests__/__snapshots__/CodeModal.test.tsx.snap index fcddd060..d9be998c 100644 --- a/public/components/CodeModal/__tests__/__snapshots__/CodeModal.test.tsx.snap +++ b/public/components/CodeModal/__tests__/__snapshots__/CodeModal.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`CodeMOdal spec renders the component 1`] = ` +exports[`CodeModal spec renders the component 1`] = ` ,
World
]} + > +
Testing ContentPanel
+ + ); + getByText('testing-1'); + getByText('testing-2'); + }); + test('renders array subtitle', () => { + const { getByText } = render( + Hello,
World
]} + > +
Testing ContentPanel
+
+ ); + getByText('testing-1'); + getByText('testing-2'); + }); }); diff --git a/public/components/ContentPanel/ContentPanel.tsx b/public/components/ContentPanel/ContentPanel.tsx index 690ee45f..d3d89c04 100644 --- a/public/components/ContentPanel/ContentPanel.tsx +++ b/public/components/ContentPanel/ContentPanel.tsx @@ -49,7 +49,7 @@ const ContentPanel = (props: ContentPanelProps) => { ); return ( { margin="s" className={props.horizontalRuleClassName} /> -
- {props.children} -
+
{props.children}
) : null}
diff --git a/public/models/interfaces.ts b/public/models/interfaces.ts index 47420b44..2ca131fa 100644 --- a/public/models/interfaces.ts +++ b/public/models/interfaces.ts @@ -189,10 +189,10 @@ export type MonitorAlert = { triggerName: string; severity: number; state: string; - error: string; + error: string | null; startTime: number; - endTime: number; - acknowledgedTime: number; + endTime: number | null; + acknowledgedTime: number | null; }; export type AnomalySummary = { diff --git a/public/pages/AnomalyCharts/containers/__tests__/__snapshots__/AnomalyHeatmapChart.test.tsx.snap b/public/pages/AnomalyCharts/containers/__tests__/__snapshots__/AnomalyHeatmapChart.test.tsx.snap index bad12782..b547e348 100644 --- a/public/pages/AnomalyCharts/containers/__tests__/__snapshots__/AnomalyHeatmapChart.test.tsx.snap +++ b/public/pages/AnomalyCharts/containers/__tests__/__snapshots__/AnomalyHeatmapChart.test.tsx.snap @@ -434,14 +434,14 @@ exports[` spec AnomalyHeatmapChart with anomaly summaries xmlns="http://www.w3.org/2000/svg" > - No anomalies found in the specified date range. + Choose a filled rectangle in the heat map for a more detailed view of anomalies within that entity. @@ -931,14 +931,14 @@ exports[` spec AnomalyHeatmapChart with multiple category xmlns="http://www.w3.org/2000/svg" > - No anomalies found in the specified date range. + Choose a filled rectangle in the heat map for a more detailed view of anomalies within that entity. @@ -1516,14 +1516,14 @@ exports[` spec AnomalyHeatmapChart with one category fiel xmlns="http://www.w3.org/2000/svg" > - No anomalies found in the specified date range. + Choose a filled rectangle in the heat map for a more detailed view of anomalies within that entity. diff --git a/public/pages/AnomalyCharts/utils/__tests__/anomalyChartUtils.test.ts b/public/pages/AnomalyCharts/utils/__tests__/anomalyChartUtils.test.ts index 6f49c3e7..db37f67f 100644 --- a/public/pages/AnomalyCharts/utils/__tests__/anomalyChartUtils.test.ts +++ b/public/pages/AnomalyCharts/utils/__tests__/anomalyChartUtils.test.ts @@ -11,7 +11,13 @@ //@ts-ignore import moment from 'moment'; -import { getAnomalySummary } from '../anomalyChartUtils'; +import { + getAnomalySummary, + convertAlerts, + generateAlertAnnotations, +} from '../anomalyChartUtils'; +import { httpClientMock, coreServicesMock } from '../../../../../test/mocks'; +import { MonitorAlert } from '../../../../models/interfaces'; describe('anomalyChartUtils', () => { describe('getAnomalySummary', () => { @@ -75,3 +81,80 @@ describe('anomalyChartUtils', () => { }); }); }); + +describe('anomalyChartUtils function tests', () => { + const alertResponse = { + response: { + alerts: [ + { + id: 'eQURa3gBKo1jAh6qUo49', + version: 300, + monitor_id: 'awUMa3gBKo1jAh6qu47E', + schema_version: 2, + monitor_version: 2, + monitor_name: 'Example_monitor_name', + monitor_user: { + name: 'admin', + backend_roles: ['admin'], + roles: ['all_access', 'own_index'], + custom_attribute_names: [], + user_requested_tenant: null, + }, + trigger_id: 'bQUQa3gBKo1jAh6qnY6G', + trigger_name: 'Example_trigger_name', + state: 'ACTIVE', + error_message: null, + alert_history: [ + { + timestamp: 1617314504873, + message: 'Example error emssage', + }, + { + timestamp: 1617312543925, + message: 'Example error message', + }, + ], + severity: 1, + action_execution_results: [ + { + action_id: 'bgUQa3gBKo1jAh6qnY6G', + last_execution_time: 1617317979908, + throttled_count: 0, + }, + ], + start_time: 1616704000492, + last_notification_time: 1617317979908, + end_time: null, + acknowledged_time: null, + }, + ], + totalAlerts: 1, + }, + }; + const alertConverted = [ + { + monitorName: 'Example_monitor_name', + triggerName: 'Example_trigger_name', + severity: 1, + state: 'ACTIVE', + error: null, + startTime: 1616704000492, + endTime: null, + acknowledgedTime: null, + }, + ] as MonitorAlert[]; + test('convertAlerts', () => { + expect(convertAlerts(alertResponse)).toStrictEqual(alertConverted); + }); + test('generateAlertAnnotations', () => { + const alertsConverted = generateAlertAnnotations(alertConverted); + expect(alertsConverted).toStrictEqual([ + { + dataValue: 1616704000492, + details: + 'There is a severity 1 alert with state ACTIVE from 03/25/21 08:26:40 PM.', + header: '03/25/21 08:26:40 PM', + }, + ]); + }); +}); diff --git a/public/pages/AnomalyCharts/utils/anomalyChartUtils.tsx b/public/pages/AnomalyCharts/utils/anomalyChartUtils.tsx index b6d889a5..b2603ada 100644 --- a/public/pages/AnomalyCharts/utils/anomalyChartUtils.tsx +++ b/public/pages/AnomalyCharts/utils/anomalyChartUtils.tsx @@ -406,7 +406,6 @@ export const getEntityAnomaliesHeatmapData = ( singleAnomalySummary.startTime >= timeWindow.startDate && singleAnomalySummary.startTime < timeWindow.endDate ); - if (isEmpty(anomalySummaryInTimeRange)) { maxAnomalyGradesForEntity.push(0); numAnomalyGradesForEntity.push(0); diff --git a/public/pages/ConfigureModel/containers/__tests__/ConfigureModel.test.tsx b/public/pages/ConfigureModel/containers/__tests__/ConfigureModel.test.tsx index 9dbb0c03..77a9e370 100644 --- a/public/pages/ConfigureModel/containers/__tests__/ConfigureModel.test.tsx +++ b/public/pages/ConfigureModel/containers/__tests__/ConfigureModel.test.tsx @@ -64,7 +64,7 @@ describe(' spec', () => { test('validate all required fields', async () => { const { getByText } = renderWithRouter(); fireEvent.click(getByText('Next')); - await waitFor(()=>{}); + await waitFor(() => {}); getByText('You must enter a feature name'); getByText('You must select a field'); }); diff --git a/public/pages/Dashboard/Components/AnomaliesLiveChart.tsx b/public/pages/Dashboard/Components/AnomaliesLiveChart.tsx index b395256b..a0176b22 100644 --- a/public/pages/Dashboard/Components/AnomaliesLiveChart.tsx +++ b/public/pages/Dashboard/Components/AnomaliesLiveChart.tsx @@ -128,7 +128,6 @@ export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => { ALL_CUSTOM_AD_RESULT_INDICES, false ); - setLiveAnomalyData(latestLiveAnomalyResult); setLatestLiveAnomalousDetectorsCount( @@ -144,6 +143,7 @@ export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => { } else { setLastAnomalyResult(undefined); } + setLiveTimeRange({ startDateTime: moment().subtract(31, 'minutes'), endDateTime: moment(), diff --git a/public/pages/Dashboard/Components/__tests__/AnomaliesLiveCharts.test.tsx b/public/pages/Dashboard/Components/__tests__/AnomaliesLiveCharts.test.tsx new file mode 100644 index 00000000..5c497688 --- /dev/null +++ b/public/pages/Dashboard/Components/__tests__/AnomaliesLiveCharts.test.tsx @@ -0,0 +1,65 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { render, waitFor } from '@testing-library/react'; +import React from 'react'; +import { AnomaliesLiveChart } from '../AnomaliesLiveChart'; +import { selectedDetectors } from '../../../../pages/utils/__tests__/constants'; +import { Provider } from 'react-redux'; +import { coreServicesMock } from '../../../../../test/mocks'; +import { CoreServicesContext } from '../../../../components/CoreServices/CoreServices'; +import { mockedStore } from '../../../../redux/utils/testUtils'; +const anomalyResponse = [ + { + ok: true, + response: { + anomaly_grade: 0.10949221682655441, + data_start_time: 1651817250642, + data_end_time: 1651817310642, + detector_id: 'gtU2l4ABuV34PY9ITTdm', + name: 'test2', + }, + }, +]; +const anomalyResultQuery = [ + { + anomaly_grade: 0.10949221682655441, + data_start_time: 1651817250642, + data_end_time: 1651817310642, + detector_id: 'gtU2l4ABuV34PY9ITTdm', + }, +]; + +jest.mock('../../utils/utils', () => ({ + getLatestAnomalyResultsForDetectorsByTimeRange: jest.fn( + () => anomalyResponse + ), + getFloorPlotTime: jest.fn(() => 1651817250642), + getLatestAnomalyResultsByTimeRange: jest.fn(() => anomalyResultQuery), + visualizeAnomalyResultForXYChart: jest.fn(), +})); +describe(' spec', () => { + test('AnomaliesLiveChart with Sample anomaly data', async () => { + const { container, getByTestId, getAllByText, getByText } = render( + + + + + + ); + //mock current last update to a specific date so doesn't produce new snapshot each minute + Date.now = jest.fn().mockReturnValue(new Date('2021-06-06T12:33:37.000Z')); + await waitFor(() => { + expect( + getByTestId('dashboardFullScreenButton').innerHTML.includes( + 'euiIcon-isssLoaded' + ) + ); + }); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + getAllByText('Detector with the most recent anomaly'); + }); +}); diff --git a/public/pages/Dashboard/Components/__tests__/__snapshots__/AnomaliesLiveCharts.test.tsx.snap b/public/pages/Dashboard/Components/__tests__/__snapshots__/AnomaliesLiveCharts.test.tsx.snap new file mode 100644 index 00000000..93b78331 --- /dev/null +++ b/public/pages/Dashboard/Components/__tests__/__snapshots__/AnomaliesLiveCharts.test.tsx.snap @@ -0,0 +1,234 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` spec AnomaliesLiveChart with Sample anomaly data 1`] = ` +
+
+
+
+
+
+

+ Live anomalies + + + + + Live + + + +

+
+
+
+
+ Live anomaly results across detectors for the last 30 minutes. + 'The results refresh every 1 minute. + 'For each detector, if an anomaly occurrence is detected at the end of the detector interval, + 'you will see a bar representing its anomaly grade. +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +

+ Last updated time 06/06/2021 12:33 PM +

+
+
+
+
+
+ +
+

+ Detector with the most recent anomaly +

+
+
+
+
+
+ +
+ +

+ Most recent anomaly grade 0.00e+0 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/public/pages/Dashboard/utils/__tests__/utils.test.tsx b/public/pages/Dashboard/utils/__tests__/utils.test.tsx new file mode 100644 index 00000000..7694dea8 --- /dev/null +++ b/public/pages/Dashboard/utils/__tests__/utils.test.tsx @@ -0,0 +1,136 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + visualizeAnomalyResultForXYChart, + getLatestAnomalyResultsByTimeRange, + getLatestAnomalyResultsForDetectorsByTimeRange, +} from '../utils'; +import { httpClientMock, coreServicesMock } from '../../../../../test/mocks'; +import { + Detector, + FeatureAttributes, + DetectorListItem, +} from '../../../../models/interfaces'; +import { + selectedDetectors, + anomalyResultQuery, + anomalyResultQueryPerDetector, +} from '../../../../pages/utils/__tests__/constants'; +const anomalyResult = { + detector_id: 'gtU2l4ABuV34PY9ITTdm', + anomaly_grade: 0.10949221682655441, + data_start_time: 1651804360194, + data_end_time: 1651804420194, + name: 'test2', +}; +const visualizedAnomalyResult = { + anomaly_grade: '0.11', + data_end_time: 1651804420194, + data_start_time: 1651804360194, + detector_id: 'gtU2l4ABuV34PY9ITTdm', + name: 'test2', + // plot time calculated using Math.floor(plotTime / MIN_IN_MILLI_SECS) * MIN_IN_MILLI_SECS + plot_time: 1651804380000, +}; + +const buildQueryInput = { + timeRange: '30m', + from: 0, + threshold: 10, + checkLastIndexOnly: false, +}; + +const searchResponseGetLatestAnomalyResults = { + ok: true, + response: { + took: 1, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: { + value: 255, + relation: 'eq', + }, + max_score: null, + hits: [ + { + _index: '.opendistro-anomaly-results-history-2022.05.06-1', + _id: 'hNX8l4ABuV34PY9I1EAZ', + _version: 1, + _seq_no: 2980, + _primary_term: 1, + _score: null, + _source: { + detector_id: 'gtU2l4ABuV34PY9ITTdm', + schema_version: 5, + data_start_time: 1651817250642, + data_end_time: 1651817310642, + feature_data: [ + { + feature_id: 'W9U0l4ABuV34PY9IUzdM', + feature_name: 'f-1', + data: 1, + }, + ], + execution_start_time: 1651817370642, + execution_end_time: 1651817370649, + anomaly_score: 0.44207098120965693, + anomaly_grade: 0.10949221682655441, + confidence: 0.9821335094192676, + threshold: 4.239534075827808, + }, + sort: [1651817250642], + }, + ], + }, + }, +}; + +describe('visualizeAnomalyResultForXYChart', () => { + test('should return chart object', () => { + expect(visualizeAnomalyResultForXYChart(anomalyResult)).toStrictEqual( + visualizedAnomalyResult + ); + }); +}); + +describe('get latest anomaly result by time range', () => { + test('get latest by time range only ', async () => { + const response = await getLatestAnomalyResultsByTimeRange( + jest.fn(), + '30m', + jest.fn().mockResolvedValue(searchResponseGetLatestAnomalyResults), + -1, + 1, + true, + 'opensearch-ad-plugin-result-*', + false + ); + expect(response[0]).toStrictEqual(anomalyResultQuery); + }, 10000); +}); +describe('get latest anomaly result for detectors', () => { + test('get latest by detectors and time range ', async () => { + const response = await getLatestAnomalyResultsForDetectorsByTimeRange( + jest.fn(), + selectedDetectors, + '30m', + jest.fn().mockResolvedValue(searchResponseGetLatestAnomalyResults), + -1, + 10000, + 1, + true, + 'opensearch-ad-plugin-result-*', + false + ); + expect(response[0]).toStrictEqual(anomalyResultQueryPerDetector); + }, 10000); +}); diff --git a/public/pages/Dashboard/utils/utils.tsx b/public/pages/Dashboard/utils/utils.tsx index e9d1c95c..603bb37a 100644 --- a/public/pages/Dashboard/utils/utils.tsx +++ b/public/pages/Dashboard/utils/utils.tsx @@ -23,11 +23,7 @@ import { FeatureAttributes, DetectorListItem, } from '../../../models/interfaces'; -import { - PLUGIN_NAME, - ANOMALY_RESULT_INDEX, - MAX_ANOMALIES, -} from '../../../utils/constants'; +import { PLUGIN_NAME, MAX_ANOMALIES } from '../../../utils/constants'; import { get, orderBy, isEmpty } from 'lodash'; import { APIAction } from 'public/redux/middleware/types'; import { Dispatch } from 'redux'; @@ -43,19 +39,6 @@ import { MAX_DETECTORS } from '../../../pages/utils/constants'; * @param {[string]} timeRange [last time period which query is for] * @returns query which is used to get anomaly result for the last timeRange period */ -export const buildGetRecentAnomalyResultQuery = (timeRange: string) => { - return { - range: { - [AD_DOC_FIELDS.DATA_START_TIME]: { - gte: 'now-' + timeRange, - }, - }, - size: 30, - sortField: AD_DOC_FIELDS.DATA_START_TIME, - from: 0, - sortDirection: SORT_DIRECTION.DESC, - }; -}; export type RgbColor = [number, number, number, number?]; export const rgbColors: RgbColor[] = [ @@ -500,7 +483,6 @@ export const getLatestAnomalyResultsByTimeRange = async ( from += anomalySize; numSingleBatchResults = anomalies.length; } while (numSingleBatchResults === MAX_ANOMALIES); - return anomalyResults; }; @@ -539,7 +521,6 @@ export const getLatestAnomalyResultsForDetectorsByTimeRange = async ( ) ); const searchAnomalyResponse = searchResponse.response; - const numHits = get(searchAnomalyResponse, 'hits.total.value', 0); if (numHits === 0) { break; diff --git a/public/pages/DefineDetector/components/DataFilterList/components/DataFilter.tsx b/public/pages/DefineDetector/components/DataFilterList/components/DataFilter.tsx index 37187a79..170874a2 100644 --- a/public/pages/DefineDetector/components/DataFilterList/components/DataFilter.tsx +++ b/public/pages/DefineDetector/components/DataFilterList/components/DataFilter.tsx @@ -215,6 +215,7 @@ export const DataFilter = (props: DataFilterProps) => { { props.onOpen(); openPopover(); @@ -252,6 +253,7 @@ export const DataFilter = (props: DataFilterProps) => { { filterType === FILTER_TYPES.SIMPLE ? setFilterType(FILTER_TYPES.CUSTOM) @@ -285,6 +287,7 @@ export const DataFilter = (props: DataFilterProps) => { Create custom label?} checked={isCustomLabel} onChange={() => { diff --git a/public/pages/DefineDetector/components/DataFilterList/components/__tests__/DataFilter.test.tsx b/public/pages/DefineDetector/components/DataFilterList/components/__tests__/DataFilter.test.tsx new file mode 100644 index 00000000..4eb5f4cd --- /dev/null +++ b/public/pages/DefineDetector/components/DataFilterList/components/__tests__/DataFilter.test.tsx @@ -0,0 +1,168 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { DATA_TYPES } from '../../../../../../utils/constants'; +import { CoreServicesContext } from '../../../../../../components/CoreServices/CoreServices'; +import { + coreServicesMock, + httpClientMock, +} from '../../../../../../../test/mocks'; +import { DataFilter } from '../DataFilter'; +import { + OPERATORS_MAP, + FILTER_TYPES, + UIFilter, +} from '../../../../../../models/interfaces'; +import { DetectorDefinitionFormikValues } from '../../../../models/interfaces'; +import { FormikProps, Formik } from 'formik'; +import { Provider } from 'react-redux'; +import { mockedStore } from '../../../../../../redux/utils/testUtils'; + +const initialState = { + opensearch: { + indices: [ + { + label: 'test-index', + health: 'green', + }, + ], + aliases: [], + dataTypes: { + integer: ['cpu', 'memory'], + }, + requesting: false, + searchResult: {}, + errorMessage: '', + }, +}; + +const filters = [ + { + filterType: FILTER_TYPES.SIMPLE, + fieldInfo: [ + { + label: 'cpu', + type: DATA_TYPES.NUMBER, + }, + ], + operator: OPERATORS_MAP.IS_GREATER, + fieldValue: 0, + }, +] as UIFilter; + +const values = { + name: 'test-ad', + description: 'desc', + index: [ + { + label: 'test-index', + health: 'green', + }, + ], + filters: [ + { + filterType: FILTER_TYPES.SIMPLE, + fieldInfo: [ + { + label: 'cpu', + type: DATA_TYPES.NUMBER, + }, + ], + operator: OPERATORS_MAP.IS_GREATER, + fieldValue: 0, + }, + ], + filterQuery: JSON.stringify({ bool: { filter: [] } }, null, 4), + timeField: 'timestamp', + interval: 10, + windowDelay: 1, +} as DetectorDefinitionFormikValues; + +const formikProps = { + values: { values }, + errors: {}, + touched: { + index: true, + name: true, + timeField: true, + }, + isSubmitting: false, + isValidating: false, + submitCount: 0, + initialErrors: {}, + initialTouched: {}, + isValid: true, + dirty: true, + validateOnBlur: true, + validateOnChange: true, + validateOnMount: true, +} as FormikProps; + +const renderWithProvider = () => ({ + ...render( + + + + {}} + onSave={jest.fn()} + onCancel={jest.fn()} + onDelete={jest.fn()} + openPopoverIndex={0} + setOpenPopoverIndex={jest.fn(() => 0)} + isNewFilter={true} + oldFilterType={undefined} + oldFilterQuery={undefined} + /> + + + + ), +}); + +describe('dataFilter', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('renders data filter', async () => { + const { container, getByText, getByTestId, getAllByText } = + renderWithProvider(); + expect(container).toMatchSnapshot(); + getByText('Create custom label?'); + getByText('Operator'); + expect(getByTestId('switchForCustomLabel')).not.toBeChecked(); + userEvent.click(getByTestId('switchForCustomLabel')); + await waitFor(() => {}); + expect(getByTestId('switchForCustomLabel')).toBeChecked(); + userEvent.click(getByTestId('switchForCustomLabel')); + userEvent.click(getByTestId('comboBoxToggleListButton')); + await waitFor(() => { + getAllByText('cpu'); + }); + userEvent.click(getByTestId('cancelFilter0Button')); + }, 10000); + test('renders data filter, click on custom', async () => { + const { container, getByText, getByTestId } = renderWithProvider(); + getByText('Create custom label?'); + getByText('Operator'); + userEvent.click(getByTestId('filterTypeButton')); + await waitFor(() => { + getByText('Use visual editor'); + }); + userEvent.click(getByTestId('filterTypeButton')); + await waitFor(() => { + getByText('Use query DSL'); + }); + userEvent.click(getByTestId('cancelFilter0Button')); + }, 10000); +}); diff --git a/public/pages/DefineDetector/components/DataFilterList/components/__tests__/__snapshots__/DataFilter.test.tsx.snap b/public/pages/DefineDetector/components/DataFilterList/components/__tests__/__snapshots__/DataFilter.test.tsx.snap new file mode 100644 index 00000000..f9799139 --- /dev/null +++ b/public/pages/DefineDetector/components/DataFilterList/components/__tests__/__snapshots__/DataFilter.test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`dataFilter renders data filter 1`] = ` +
+
+
+
+ +
+
+
+
+`; diff --git a/public/pages/DefineDetector/containers/__tests__/DefineDetector.test.tsx b/public/pages/DefineDetector/containers/__tests__/DefineDetector.test.tsx index cb6e5e59..84f9a212 100644 --- a/public/pages/DefineDetector/containers/__tests__/DefineDetector.test.tsx +++ b/public/pages/DefineDetector/containers/__tests__/DefineDetector.test.tsx @@ -22,9 +22,12 @@ import { DefineDetector } from '../DefineDetector'; import configureStore from '../../../../redux/configureStore'; import { httpClientMock, coreServicesMock } from '../../../../../test/mocks'; import { CoreServicesContext } from '../../../../components/CoreServices/CoreServices'; -import { INITIAL_DETECTOR_DEFINITION_VALUES } from '../../utils/constants'; +import { + INITIAL_DETECTOR_DEFINITION_VALUES, + testDetectorDefinitionValues, +} from '../../utils/constants'; -const renderWithRouter = (isEdit: boolean = false) => ({ +const renderWithRouterEmpty = (isEdit: boolean = false) => ({ ...render( @@ -46,7 +49,61 @@ const renderWithRouter = (isEdit: boolean = false) => ({ ), }); -describe(' spec', () => { +const renderWithRouterFull = (isEdit: boolean = false) => ({ + ...render( + + + + ( + + + + )} + /> + + + + ), +}); + +describe(' Full', () => { + beforeEach(() => { + jest.clearAllMocks(); + console.error = jest.fn(); + console.warn = jest.fn(); + }); + describe('creating detector definition', () => { + test('renders the component', () => { + const { container, getByText } = renderWithRouterFull(false); + getByText('Define detector'); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('duplicate name', async () => { + httpClientMock.get = jest.fn().mockResolvedValue({ + ok: true, + response: { + count: 0, + match: true, + }, + }); + + const { getByText } = renderWithRouterFull(); + fireEvent.click(getByText('Next')); + + await waitFor(() => {}); + getByText('Duplicate detector name'); + getByText('Must specify an index'); + }); + }); +}); + +describe(' empty', () => { beforeEach(() => { jest.clearAllMocks(); console.error = jest.fn(); @@ -54,7 +111,7 @@ describe(' spec', () => { }); describe('creating detector definition', () => { test('renders the component', () => { - const { container, getByText } = renderWithRouter(false); + const { container, getByText } = renderWithRouterEmpty(false); expect(container.firstChild).toMatchSnapshot(); getByText('Define detector'); }); @@ -69,9 +126,9 @@ describe(' spec', () => { ], }, }); - const { getByText } = renderWithRouter(); + const { getByText } = renderWithRouterEmpty(); fireEvent.click(getByText('Next')); - await waitFor(()=>{}); + await waitFor(() => {}); getByText('Detector name cannot be empty'); getByText('Must specify an index'); getByText('Required'); @@ -79,7 +136,7 @@ describe(' spec', () => { }); describe('editing detector definition', () => { test('renders the component', () => { - const { container, getByText } = renderWithRouter(true); + const { container, getByText } = renderWithRouterEmpty(true); expect(container.firstChild).toMatchSnapshot(); getByText('Edit detector settings'); getByText('Save changes'); diff --git a/public/pages/DefineDetector/containers/__tests__/__snapshots__/DefineDetector.test.tsx.snap b/public/pages/DefineDetector/containers/__tests__/__snapshots__/DefineDetector.test.tsx.snap index 8e3dfe27..839c07ad 100644 --- a/public/pages/DefineDetector/containers/__tests__/__snapshots__/DefineDetector.test.tsx.snap +++ b/public/pages/DefineDetector/containers/__tests__/__snapshots__/DefineDetector.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` spec creating detector definition renders the component 1`] = ` +exports[` Full creating detector definition renders the component 1`] = `
spec creating detector definition renders the compon name="name" placeholder="Enter detector name" type="text" - value="" + value="test" />
@@ -172,7 +172,9 @@ exports[` spec creating detector definition renders the compon name="description" placeholder="Describe the detector" rows="3" - /> + > + desc +
@@ -518,11 +520,11 @@ exports[` spec creating detector definition renders the compon data-test-subj="comboBoxInput" tabindex="-1" > -

- Find timestamp -

+ timestamp +
spec creating detector definition renders the compon
`; -exports[` spec editing detector definition renders the component 1`] = ` +exports[` empty creating detector definition renders the component 1`] = ` +
+
+
+
+

+ Define detector + +

+
+
+
+
+
+

+ Detector details +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+ Detector name must contain 1-64 characters. Valid characters are + a-z, A-Z, 0-9, -(hyphen), _(underscore) and .(period). +
+
+
+
+
+ +
+
+