/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ import React from 'react'; import { Provider } from 'react-redux'; import { HashRouter as Router, RouteComponentProps, Route, Switch, } from 'react-router-dom'; import { render, fireEvent, waitFor } from '@testing-library/react'; import { DetectorConfig } from '../DetectorConfig'; import { Detector, UiMetaData, FILTER_TYPES, UIFilter, FEATURE_TYPE, UiFeature, FeatureAttributes, } from '../../../../models/interfaces'; import { getRandomDetector } from '../../../../redux/reducers/__tests__/utils'; import { coreServicesMock } from '../../../../../test/mocks'; import { toStringConfigCell } from '../../../ReviewAndCreate/utils/helpers'; import { DATA_TYPES } from '../../../../utils/constants'; import { OPERATORS_MAP } from '../../../../models/interfaces'; import { displayText } from '../../../DefineDetector/components/DataFilterList/utils/helpers'; import { mockedStore, initialState } from '../../../../redux/utils/testUtils'; import { CoreServicesContext } from '../../../../components/CoreServices/CoreServices'; const renderWithRouter = (detector: Detector) => ({ ...render( ( )} /> ), }); const fieldInFilter = 'age'; const filters = [ { filterType: FILTER_TYPES.SIMPLE, fieldInfo: [{ label: fieldInFilter, type: DATA_TYPES.NUMBER }], operator: OPERATORS_MAP.IN_RANGE, fieldRangeStart: 20, fieldRangeEnd: 40, }, { filterType: FILTER_TYPES.CUSTOM, query: { some: 'query' }, }, ] as UIFilter[]; const featureQuery1 = { featureName: 'value', featureEnabled: true, aggregationQuery: { size: 0, query: { bool: { must: { terms: { detector_id: ['detector_1', 'detector_2'], }, }, }, }, aggs: { unique_detectors: { terms: { field: 'detector_id', size: 20, order: { total_anomalies_in_24hr: 'asc', }, }, aggs: { total_anomalies_in_24hr: { filter: { range: { data_start_time: { gte: 'now-24h', lte: 'now' }, }, }, }, latest_anomaly_time: { max: { field: 'data_start_time' } }, }, }, }, }, } as { [key: string]: any }; const featureQuery2 = { featureName: 'value2', featureEnabled: true, aggregationQuery: { aggregation_name: { max: { field: 'value2', }, }, }, } as { [key: string]: any }; describe(' spec', () => { test('renders the component', () => { const randomDetector = { ...getRandomDetector(false), }; const { container } = renderWithRouter(randomDetector); expect(container.firstChild).toMatchSnapshot(); }); test('renders empty features and filters', async () => { const randomDetector = { ...getRandomDetector(true), uiMetadata: {} as UiMetaData, featureAttributes: [], shingleSize: 8, }; const { getByText, queryByText } = renderWithRouter(randomDetector); waitFor(() => { getByText('Model parameters are required to run a detector'); queryByText('Set the index fields'); getByText('Model configuration'); getByText(randomDetector.name); getByText(randomDetector.indices[0]); getByText(toStringConfigCell(randomDetector.detectionInterval)); getByText(toStringConfigCell(randomDetector.lastUpdateTime)); getByText(randomDetector.id); getByText(toStringConfigCell(randomDetector.windowDelay)); getByText(randomDetector.description); // filter should be - getByText('-'); queryByText('Set the index fields'); }); }); describe('test 1 simple feature enabled/disabled', () => { test.each([ [true, 'Enabled'], [false, 'Disabled'], ])( 'renders 1 simple feature enabled/disabled', async (enabledInDef, enabledInRender) => { const randomDetector = { ...getRandomDetector(true), featureAttributes: [ { featureName: 'value', featureEnabled: enabledInDef, }, ] as FeatureAttributes[], uiMetadata: { filterType: FILTER_TYPES.SIMPLE, filters: [], features: { value: { featureType: FEATURE_TYPE.SIMPLE, aggregationOf: 'value', aggregationBy: 'avg', } as UiFeature, }, } as UiMetaData, }; const { getByText, getAllByText } = renderWithRouter(randomDetector); waitFor(() => { getByText('Field: value'); getByText('Aggregation method: avg'); getAllByText(enabledInRender); }); } ); }); test('renders one custom feature', async () => { const randomDetector = { ...getRandomDetector(true), featureAttributes: [ { featureName: 'value', featureEnabled: true, aggregationQuery: featureQuery1, }, ] as FeatureAttributes[], uiMetadata: { filters: [filters[0]] as UIFilter[], features: { value: { featureType: FEATURE_TYPE.CUSTOM, } as UiFeature, }, } as UiMetaData, }; const { getByTestId, getByText, queryByText } = renderWithRouter(randomDetector); await waitFor(() => { getByText('Custom expression:'); expect(queryByText('detector_1')).toBeNull(); expect(queryByText('detector_2')).toBeNull(); }); fireEvent.click(getByTestId('viewFeature-0')); await waitFor(() => { queryByText('detector_1'); queryByText('detector_2'); }); }); describe('renders two custom features', () => { test.each([ [ 'viewFeature-0', ['detector_1', 'detector_2'], ['max', 'aggregation_name'], ], [ 'viewFeature-1', ['max', 'aggregation_name'], ['detector_1', 'detector_2'], ], ])( 'renders two custom features', async (toClick, notExpected, expected) => { const randomDetector = { ...getRandomDetector(true), featureAttributes: [ { featureName: 'value', featureEnabled: true, aggregationQuery: featureQuery1, }, { featureName: 'value2', featureEnabled: true, aggregationQuery: featureQuery2, }, ] as FeatureAttributes[], uiMetadata: { filterType: FILTER_TYPES.SIMPLE, filters: [], features: { value: { featureType: FEATURE_TYPE.CUSTOM, } as UiFeature, value2: { featureType: FEATURE_TYPE.CUSTOM, } as UiFeature, }, } as UiMetaData, }; const { getByTestId, getAllByText, queryByText } = renderWithRouter(randomDetector); await waitFor(() => { getAllByText('Custom expression:'); expect(queryByText('detector_1')).toBeNull(); expect(queryByText('detector_2')).toBeNull(); expect(queryByText('max')).toBeNull(); expect(queryByText('aggregation_name')).toBeNull(); }); fireEvent.click(getByTestId(toClick)); await waitFor(() => { notExpected.forEach((obj, index) => { expect(queryByText(notExpected[index])).toBeNull(); }); expected.forEach((obj, index) => { queryByText(expected[index]); }); }); } ); }); test('renders the component with 2 custom and 1 simple features', () => { const randomDetector = { ...getRandomDetector(true), featureAttributes: [ { featureName: 'value', featureEnabled: true, aggregationQuery: featureQuery1, }, { featureName: 'value2', featureEnabled: true, aggregationQuery: featureQuery2, }, { featureName: 'value', featureEnabled: false, }, ] as FeatureAttributes[], uiMetadata: { filterType: FILTER_TYPES.SIMPLE, filters: [], features: { value: { featureType: FEATURE_TYPE.CUSTOM, } as UiFeature, value2: { featureType: FEATURE_TYPE.CUSTOM, } as UiFeature, value3: { featureType: FEATURE_TYPE.SIMPLE, aggregationOf: 'value3', aggregationBy: 'avg', } as UiFeature, }, } as UiMetaData, }; const { container } = renderWithRouter(randomDetector); expect(container.firstChild).toMatchSnapshot(); }); });