/*
* 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();
});
});