mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[ML] Add functional tests for Change Point Detection UI (#158164)
## Summary Part of https://github.com/elastic/kibana/issues/157980 Adds functional tests for the Change Point Detection UI. ### Checklist - [x] [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
This commit is contained in:
parent
84d070d2f7
commit
3db3709eb4
9 changed files with 311 additions and 8 deletions
|
@ -121,6 +121,7 @@ export const ChangePointDetectionPage: FC = () => {
|
|||
onClick={() => setFlyoutVisible(!isFlyoutVisible)}
|
||||
size={'s'}
|
||||
disabled={!hasSelectedChangePoints}
|
||||
data-test-subj={'aiopsChangePointDetectionViewSelected'}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.aiops.changePointDetection.viewSelectedButtonLabel"
|
||||
|
@ -149,6 +150,7 @@ export const ChangePointDetectionPage: FC = () => {
|
|||
onClose={setFlyoutVisible.bind(null, false)}
|
||||
aria-labelledby={'change_point_charts'}
|
||||
size={'l'}
|
||||
data-test-subj={'aiopsChangePointDetectionSelectedCharts'}
|
||||
>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
|
|
|
@ -94,7 +94,9 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
|
||||
const columns: Array<EuiBasicTableColumn<ChangePointAnnotation>> = [
|
||||
{
|
||||
id: 'timestamp',
|
||||
field: 'timestamp',
|
||||
'data-test-subj': 'aiopsChangePointTimestamp',
|
||||
name: i18n.translate('xpack.aiops.changePointDetection.timeColumn', {
|
||||
defaultMessage: 'Time',
|
||||
}),
|
||||
|
@ -104,6 +106,8 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
render: (timestamp: ChangePointAnnotation['timestamp']) => dateFormatter.convert(timestamp),
|
||||
},
|
||||
{
|
||||
id: 'preview',
|
||||
'data-test-subj': 'aiopsChangePointPreview',
|
||||
name: i18n.translate('xpack.aiops.changePointDetection.previewColumn', {
|
||||
defaultMessage: 'Preview',
|
||||
}),
|
||||
|
@ -118,6 +122,8 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
'data-test-subj': 'aiopsChangePointType',
|
||||
field: 'type',
|
||||
name: i18n.translate('xpack.aiops.changePointDetection.typeColumn', {
|
||||
defaultMessage: 'Type',
|
||||
|
@ -127,6 +133,8 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
render: (type: ChangePointAnnotation['type']) => <EuiBadge color="hollow">{type}</EuiBadge>,
|
||||
},
|
||||
{
|
||||
id: 'pValue',
|
||||
'data-test-subj': 'aiopsChangePointPValue',
|
||||
field: 'p_value',
|
||||
name: (
|
||||
<EuiToolTip
|
||||
|
@ -153,6 +161,8 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
...(fieldConfig.splitField
|
||||
? [
|
||||
{
|
||||
id: 'groupName',
|
||||
'data-test-subj': 'aiopsChangePointGroupName',
|
||||
field: 'group.name',
|
||||
name: i18n.translate('xpack.aiops.changePointDetection.fieldNameColumn', {
|
||||
defaultMessage: 'Field name',
|
||||
|
@ -160,6 +170,8 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
truncateText: false,
|
||||
},
|
||||
{
|
||||
id: 'groupValue',
|
||||
'data-test-subj': 'aiopsChangePointGroupValue',
|
||||
field: 'group.value',
|
||||
name: i18n.translate('xpack.aiops.changePointDetection.fieldValueColumn', {
|
||||
defaultMessage: 'Field value',
|
||||
|
@ -218,7 +230,7 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
);
|
||||
},
|
||||
isPrimary: true,
|
||||
'data-test-subj': 'aiopsChangePointFilterForValue',
|
||||
'data-test-subj': 'aiopsChangePointFilterOutValue',
|
||||
},
|
||||
] as Array<DefaultItemAction<ChangePointAnnotation>>,
|
||||
},
|
||||
|
@ -247,11 +259,15 @@ export const ChangePointsTable: FC<ChangePointsTableProps> = ({
|
|||
itemId={'id'}
|
||||
selection={selectionValue}
|
||||
loading={isLoading}
|
||||
data-test-subj={`aiopsChangePointResultsTable ${isLoading ? 'loading' : 'loaded'}`}
|
||||
items={annotations}
|
||||
columns={columns}
|
||||
pagination={{ pageSizeOptions: [5, 10, 15] }}
|
||||
sorting={defaultSorting}
|
||||
hasActions={hasActions}
|
||||
rowProps={(item) => ({
|
||||
'data-test-subj': `aiopsChangePointResultsTableRow row-${item.id}`,
|
||||
})}
|
||||
message={
|
||||
isLoading ? (
|
||||
<EuiEmptyPrompt
|
||||
|
@ -303,7 +319,7 @@ export const MiniChartPreview: FC<ChartComponentProps> = ({ fieldConfig, annotat
|
|||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div data-test-subj={'aiopChangePointPreviewChart'}>
|
||||
<EmbeddableComponent
|
||||
id={`mini_changePointChart_${annotation.group ? annotation.group.value : annotation.label}`}
|
||||
style={{ height: 80 }}
|
||||
|
|
|
@ -93,6 +93,7 @@ export const FieldsConfig: FC = () => {
|
|||
return (
|
||||
<React.Fragment key={key}>
|
||||
<FieldPanel
|
||||
data-test-subj={`aiopsChangePointPanel_${index}`}
|
||||
fieldConfig={fieldConfig}
|
||||
onChange={(value) => onChange(value, index)}
|
||||
onRemove={onRemove.bind(null, index)}
|
||||
|
@ -105,7 +106,11 @@ export const FieldsConfig: FC = () => {
|
|||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
<EuiButton onClick={onAdd} disabled={fieldConfigs.length >= MAX_CHANGE_POINT_CONFIGS}>
|
||||
<EuiButton
|
||||
onClick={onAdd}
|
||||
disabled={fieldConfigs.length >= MAX_CHANGE_POINT_CONFIGS}
|
||||
data-test-subj={'aiopsChangePointAddConfig'}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.aiops.changePointDetection.addButtonLabel"
|
||||
defaultMessage="Add"
|
||||
|
@ -121,6 +126,7 @@ export interface FieldPanelProps {
|
|||
onChange: (update: FieldConfig) => void;
|
||||
onRemove: () => void;
|
||||
onSelectionChange: (update: SelectedChangePoint[]) => void;
|
||||
'data-test-subj': string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,6 +143,7 @@ const FieldPanel: FC<FieldPanelProps> = ({
|
|||
onRemove,
|
||||
removeDisabled,
|
||||
onSelectionChange,
|
||||
'data-test-subj': dataTestSubj,
|
||||
}) => {
|
||||
const { combinedQuery, requestParams } = useChangePointDetectionContext();
|
||||
|
||||
|
@ -151,7 +158,7 @@ const FieldPanel: FC<FieldPanelProps> = ({
|
|||
} = useChangePointResults(fieldConfig, requestParams, combinedQuery, splitFieldCardinality);
|
||||
|
||||
return (
|
||||
<EuiPanel paddingSize="s" hasBorder hasShadow={false}>
|
||||
<EuiPanel paddingSize="s" hasBorder hasShadow={false} data-test-subj={dataTestSubj}>
|
||||
<EuiFlexGroup alignItems={'center'} justifyContent={'spaceBetween'} gutterSize={'s'}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems={'center'} gutterSize={'s'}>
|
||||
|
|
95
x-pack/test/functional/apps/aiops/change_point_detection.ts
Normal file
95
x-pack/test/functional/apps/aiops/change_point_detection.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||
const elasticChart = getService('elasticChart');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const aiops = getService('aiops');
|
||||
|
||||
// aiops lives in the ML UI so we need some related services.
|
||||
const ml = getService('ml');
|
||||
|
||||
describe('change point detection', async function () {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce');
|
||||
await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date');
|
||||
await ml.testResources.setKibanaTimeZoneToUTC();
|
||||
await ml.securityUI.loginAsMlPowerUser();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce');
|
||||
});
|
||||
|
||||
it(`loads the change point detection page`, async () => {
|
||||
// Start navigation from the base of the ML app.
|
||||
await ml.navigation.navigateToMl();
|
||||
await elasticChart.setNewChartUiDebugFlag(true);
|
||||
await aiops.changePointDetectionPage.navigateToIndexPatternSelection();
|
||||
await ml.jobSourceSelection.selectSourceForChangePointDetection('ft_ecommerce');
|
||||
await aiops.changePointDetectionPage.assertChangePointDetectionPageExists();
|
||||
});
|
||||
|
||||
it('detects a change point when no split field is selected', async () => {
|
||||
await aiops.changePointDetectionPage.clickUseFullDataButton();
|
||||
await aiops.changePointDetectionPage.selectMetricField(0, 'products.discount_amount');
|
||||
const result = await aiops.changePointDetectionPage.getTable(0).parseTable();
|
||||
expect(result.length).to.eql(1);
|
||||
expect(parseInt(result[0].pValue, 10)).to.eql(0);
|
||||
expect(result[0].type).to.eql('distribution_change');
|
||||
|
||||
await elasticChart.waitForRenderComplete('aiopChangePointPreviewChart > xyVisChart');
|
||||
const chartState = await elasticChart.getChartDebugData(
|
||||
'aiopChangePointPreviewChart > xyVisChart',
|
||||
0,
|
||||
5000
|
||||
);
|
||||
if (!chartState) {
|
||||
throw new Error('Preview chart debug state is not available');
|
||||
}
|
||||
expect(chartState.annotations![0].data.details).to.eql('distribution_change');
|
||||
expect(chartState.annotations![0].domainType).to.eql('xDomain');
|
||||
expect(chartState.lines![0].points.length).to.be.above(30);
|
||||
});
|
||||
|
||||
it('shows multiple results when split field is selected', async () => {
|
||||
await aiops.changePointDetectionPage.clickUseFullDataButton();
|
||||
await aiops.changePointDetectionPage.selectMetricField(0, 'products.discount_amount');
|
||||
await aiops.changePointDetectionPage.selectSplitField(0, 'geoip.city_name');
|
||||
const result = await aiops.changePointDetectionPage.getTable(0).parseTable();
|
||||
expect(result.length).to.eql(5);
|
||||
// assert asc sorting by p_value is applied
|
||||
expect(parseFloat(result[0].pValue)).to.be.lessThan(parseFloat(result[4].pValue));
|
||||
});
|
||||
|
||||
it('allows change point selection for detailed view', async () => {
|
||||
await aiops.changePointDetectionPage.getTable(0).selectAllRows();
|
||||
await aiops.changePointDetectionPage.viewSelected();
|
||||
await aiops.changePointDetectionPage.assertDetailedView(5);
|
||||
await aiops.changePointDetectionPage.closeFlyout();
|
||||
// deselect
|
||||
await aiops.changePointDetectionPage.getTable(0).selectAllRows();
|
||||
});
|
||||
|
||||
it('supports a quick filter actions', async () => {
|
||||
await aiops.changePointDetectionPage
|
||||
.getTable(0)
|
||||
.invokeAction(0, 'aiopsChangePointFilterForValue');
|
||||
const resultFor = await aiops.changePointDetectionPage.getTable(0).parseTable();
|
||||
expect(resultFor.length).to.eql(1);
|
||||
});
|
||||
|
||||
it('supports multiple configurations for change point detection', async () => {
|
||||
await aiops.changePointDetectionPage.assertPanelExist(0);
|
||||
await aiops.changePointDetectionPage.addChangePointConfig();
|
||||
await aiops.changePointDetectionPage.assertPanelExist(1);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -30,5 +30,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
loadTestFile(require.resolve('./explain_log_rate_spikes'));
|
||||
loadTestFile(require.resolve('./change_point_detection'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { MlTableService } from '../ml/common_table_service';
|
||||
|
||||
export function ChangePointDetectionPageProvider(
|
||||
{ getService, getPageObject }: FtrProviderContext,
|
||||
tableService: MlTableService
|
||||
) {
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const comboBox = getService('comboBox');
|
||||
const browser = getService('browser');
|
||||
const elasticChart = getService('elasticChart');
|
||||
|
||||
return {
|
||||
async navigateToIndexPatternSelection() {
|
||||
await testSubjects.click('mlMainTab changePointDetection');
|
||||
await testSubjects.existOrFail('mlPageSourceSelection');
|
||||
},
|
||||
|
||||
async assertChangePointDetectionPageExists() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await testSubjects.existOrFail('aiopsChangePointDetectionPage');
|
||||
});
|
||||
},
|
||||
|
||||
async assertQueryInput(expectedQueryString: string) {
|
||||
const aiopsQueryInput = await testSubjects.find('aiopsQueryInput');
|
||||
const actualQueryString = await aiopsQueryInput.getVisibleText();
|
||||
expect(actualQueryString).to.eql(
|
||||
expectedQueryString,
|
||||
`Expected query bar text to be '${expectedQueryString}' (got '${actualQueryString}')`
|
||||
);
|
||||
},
|
||||
|
||||
async assertPanelLoaded() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await testSubjects.waitForHidden('aiopsChangePointResultsTable loading');
|
||||
});
|
||||
},
|
||||
|
||||
async assertMetricFieldSelection(panelIndex: number = 0, expectedIdentifier: string[]) {
|
||||
const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions(
|
||||
`aiopsChangePointPanel_${panelIndex} > aiopsChangePointMetricField > comboBoxInput`
|
||||
);
|
||||
expect(comboBoxSelectedOptions).to.eql(
|
||||
expectedIdentifier,
|
||||
`Expected a metric field to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')`
|
||||
);
|
||||
},
|
||||
|
||||
async selectMetricField(panelIndex: number = 0, value: string) {
|
||||
await comboBox.set(
|
||||
`aiopsChangePointPanel_${panelIndex} > aiopsChangePointMetricField > comboBoxInput`,
|
||||
value
|
||||
);
|
||||
await this.assertMetricFieldSelection(panelIndex, [value]);
|
||||
},
|
||||
|
||||
async assertSplitFieldSelection(panelIndex: number = 0, expectedIdentifier: string[]) {
|
||||
const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions(
|
||||
`aiopsChangePointPanel_${panelIndex} > aiopsChangePointSplitField > comboBoxInput`
|
||||
);
|
||||
expect(comboBoxSelectedOptions).to.eql(
|
||||
expectedIdentifier,
|
||||
`Expected a split field to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')`
|
||||
);
|
||||
},
|
||||
|
||||
async selectSplitField(panelIndex: number = 0, value: string) {
|
||||
await comboBox.set(
|
||||
`aiopsChangePointPanel_${panelIndex} > aiopsChangePointSplitField > comboBoxInput`,
|
||||
value
|
||||
);
|
||||
await this.assertSplitFieldSelection(panelIndex, [value]);
|
||||
},
|
||||
|
||||
async clickUseFullDataButton() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await testSubjects.clickWhenNotDisabledWithoutRetry('mlDatePickerButtonUseFullData');
|
||||
await testSubjects.clickWhenNotDisabledWithoutRetry('superDatePickerApplyTimeButton');
|
||||
await testSubjects.existOrFail('aiopsChangePointResultsTable loaded');
|
||||
});
|
||||
},
|
||||
|
||||
async viewSelected() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await testSubjects.clickWhenNotDisabledWithoutRetry(
|
||||
'aiopsChangePointDetectionViewSelected'
|
||||
);
|
||||
await testSubjects.existOrFail('aiopsChangePointDetectionSelectedCharts');
|
||||
});
|
||||
},
|
||||
|
||||
async assertDetailedView(expectedChartCount: number) {
|
||||
const testSubj = 'aiopsChangePointDetectionSelectedCharts > xyVisChart';
|
||||
await elasticChart.waitForRenderComplete(testSubj);
|
||||
const changePointCharts = await testSubjects.findAll(testSubj);
|
||||
expect(changePointCharts.length).to.eql(
|
||||
expectedChartCount,
|
||||
`Expected ${expectedChartCount} charts in the flyout (got '${changePointCharts.length}')`
|
||||
);
|
||||
},
|
||||
|
||||
async closeFlyout() {
|
||||
await browser.pressKeys(browser.keys.ESCAPE);
|
||||
await testSubjects.missingOrFail('aiopsChangePointDetectionSelectedCharts');
|
||||
},
|
||||
|
||||
async addChangePointConfig() {
|
||||
await testSubjects.click('aiopsChangePointAddConfig');
|
||||
},
|
||||
|
||||
async assertPanelExist(index: number) {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await testSubjects.existOrFail(`aiopsChangePointPanel_${index}`);
|
||||
});
|
||||
},
|
||||
|
||||
getTable(index: number) {
|
||||
return tableService.getServiceInstance(
|
||||
'ChangePointResultsTable',
|
||||
`aiopsChangePointResultsTable`,
|
||||
'aiopsChangePointResultsTableRow',
|
||||
[
|
||||
{ id: 'timestamp', testSubj: 'aiopsChangePointTimestamp' },
|
||||
{ id: 'preview', testSubj: 'aiopsChangePointPreview' },
|
||||
{ id: 'type', testSubj: 'aiopsChangePointType' },
|
||||
{ id: 'pValue', testSubj: 'aiopsChangePointPValue' },
|
||||
{ id: 'groupName', testSubj: 'aiopsChangePointGroupName' },
|
||||
{ id: 'groupValue', testSubj: 'aiopsChangePointGroupValue' },
|
||||
],
|
||||
'',
|
||||
`aiopsChangePointPanel_${index}`
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
|
@ -12,6 +12,8 @@ import { ExplainLogRateSpikesAnalysisTableProvider } from './explain_log_rate_sp
|
|||
import { ExplainLogRateSpikesAnalysisGroupsTableProvider } from './explain_log_rate_spikes_analysis_groups_table';
|
||||
import { ExplainLogRateSpikesDataGeneratorProvider } from './explain_log_rate_spikes_data_generator';
|
||||
import { LogPatternAnalysisPageProvider } from './log_pattern_analysis_page';
|
||||
import { ChangePointDetectionPageProvider } from './change_point_detection_page';
|
||||
import { MlTableServiceProvider } from '../ml/common_table_service';
|
||||
|
||||
export function AiopsProvider(context: FtrProviderContext) {
|
||||
const explainLogRateSpikesPage = ExplainLogRateSpikesPageProvider(context);
|
||||
|
@ -21,7 +23,12 @@ export function AiopsProvider(context: FtrProviderContext) {
|
|||
const explainLogRateSpikesDataGenerator = ExplainLogRateSpikesDataGeneratorProvider(context);
|
||||
const logPatternAnalysisPageProvider = LogPatternAnalysisPageProvider(context);
|
||||
|
||||
const tableService = MlTableServiceProvider(context);
|
||||
|
||||
const changePointDetectionPage = ChangePointDetectionPageProvider(context, tableService);
|
||||
|
||||
return {
|
||||
changePointDetectionPage,
|
||||
explainLogRateSpikesPage,
|
||||
explainLogRateSpikesAnalysisTable,
|
||||
explainLogRateSpikesAnalysisGroupsTable,
|
||||
|
|
|
@ -21,7 +21,8 @@ export function MlTableServiceProvider({ getPageObject, getService }: FtrProvide
|
|||
public readonly tableTestSubj: string,
|
||||
public readonly tableRowSubj: string,
|
||||
public readonly columns: Array<{ id: string; testSubj: string }>,
|
||||
public readonly searchInputSubj: string
|
||||
public readonly searchInputSubj: string,
|
||||
public readonly parentSubj?: string
|
||||
) {}
|
||||
|
||||
public async assertTableLoaded() {
|
||||
|
@ -33,7 +34,9 @@ export function MlTableServiceProvider({ getPageObject, getService }: FtrProvide
|
|||
}
|
||||
|
||||
public async parseTable() {
|
||||
const table = await testSubjects.find(`~${this.tableTestSubj}`);
|
||||
const table = await testSubjects.find(
|
||||
`${this.parentSubj ? `${this.parentSubj} > ` : ''}~${this.tableTestSubj}`
|
||||
);
|
||||
const $ = await table.parseDomContent();
|
||||
const rows = [];
|
||||
|
||||
|
@ -138,6 +141,28 @@ export function MlTableServiceProvider({ getPageObject, getService }: FtrProvide
|
|||
await this.assertTableSorting(columnName, columnIndex, direction);
|
||||
});
|
||||
}
|
||||
|
||||
public async invokeAction(rowIndex: number, actionSubject: string) {
|
||||
const rows = await testSubjects.findAll(
|
||||
`${this.parentSubj ? `${this.parentSubj} > ` : ''}~${this.tableTestSubj} > ~${
|
||||
this.tableRowSubj
|
||||
}`
|
||||
);
|
||||
|
||||
const requestedRow = rows[rowIndex];
|
||||
const actionButton = await requestedRow.findByTestSubject(actionSubject);
|
||||
|
||||
await retry.tryForTime(5000, async () => {
|
||||
await actionButton.click();
|
||||
await this.waitForTableToLoad();
|
||||
});
|
||||
}
|
||||
|
||||
public async selectAllRows() {
|
||||
await testSubjects.click(
|
||||
`${this.parentSubj ? `${this.parentSubj} > ` : ''} > checkboxSelectAll`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -146,10 +171,11 @@ export function MlTableServiceProvider({ getPageObject, getService }: FtrProvide
|
|||
tableTestSubj: string,
|
||||
tableRowSubj: string,
|
||||
columns: Array<{ id: string; testSubj: string }>,
|
||||
searchInputSubj: string
|
||||
searchInputSubj: string,
|
||||
parentSubj?: string
|
||||
) {
|
||||
Object.defineProperty(TableService, 'name', { value: name });
|
||||
return new TableService(tableTestSubj, tableRowSubj, columns, searchInputSubj);
|
||||
return new TableService(tableTestSubj, tableRowSubj, columns, searchInputSubj, parentSubj);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -46,5 +46,9 @@ export function MachineLearningJobSourceSelectionProvider({ getService }: FtrPro
|
|||
async selectSourceForExplainLogRateSpikes(sourceName: string) {
|
||||
await this.selectSource(sourceName, 'aiopsExplainLogRateSpikesPage');
|
||||
},
|
||||
|
||||
async selectSourceForChangePointDetection(sourceName: string) {
|
||||
await this.selectSource(sourceName, 'aiopsChangePointDetectionPage');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue