[ML] Functional tests for Analytics list row expansion content (#98678)
This commit is contained in:
parent
18213b673f
commit
762c57b995
11 changed files with 331 additions and 22 deletions
|
@ -93,6 +93,7 @@ export const JobMessages: FC<JobMessagesProps> = ({ messages, loading, error, re
|
||||||
compressed={true}
|
compressed={true}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
|
data-test-subj={'mlAnalyticsDetailsJobMessagesTable'}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -192,6 +192,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
}),
|
}),
|
||||||
items: stateItems as SectionItem[],
|
items: stateItems as SectionItem[],
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
dataTestSubj: 'mlAnalyticsTableRowDetailsSection state',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { currentPhase, totalPhases } = getDataFrameAnalyticsProgressPhase(item.stats);
|
const { currentPhase, totalPhases } = getDataFrameAnalyticsProgressPhase(item.stats);
|
||||||
|
@ -217,6 +218,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
position: 'right',
|
position: 'right',
|
||||||
|
dataTestSubj: 'mlAnalyticsTableRowDetailsSection progress',
|
||||||
};
|
};
|
||||||
|
|
||||||
const stats: SectionConfig = {
|
const stats: SectionConfig = {
|
||||||
|
@ -234,6 +236,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
{ title: 'version', description: item.config.version },
|
{ title: 'version', description: item.config.version },
|
||||||
],
|
],
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
dataTestSubj: 'mlAnalyticsTableRowDetailsSection stats',
|
||||||
};
|
};
|
||||||
|
|
||||||
const analysisStats: SectionConfig | undefined = analysisStatsValues
|
const analysisStats: SectionConfig | undefined = analysisStatsValues
|
||||||
|
@ -263,6 +266,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
position: 'right',
|
position: 'right',
|
||||||
|
dataTestSubj: 'mlAnalyticsTableRowDetailsSection analysisStats',
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
@ -364,7 +368,13 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
name: i18n.translate('xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettingsLabel', {
|
name: i18n.translate('xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettingsLabel', {
|
||||||
defaultMessage: 'Job details',
|
defaultMessage: 'Job details',
|
||||||
}),
|
}),
|
||||||
content: <ExpandedRowDetailsPane sections={detailsSections} />,
|
content: (
|
||||||
|
<ExpandedRowDetailsPane
|
||||||
|
sections={detailsSections}
|
||||||
|
dataTestSubj={`mlAnalyticsTableRowDetailsTabContent job-details ${item.config.id}`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
'data-test-subj': `mlAnalyticsTableRowDetailsTab job-details ${item.config.id}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ml-analytics-job-stats',
|
id: 'ml-analytics-job-stats',
|
||||||
|
@ -374,12 +384,24 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
defaultMessage: 'Job stats',
|
defaultMessage: 'Job stats',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
content: <ExpandedRowDetailsPane sections={statsSections} />,
|
content: (
|
||||||
|
<ExpandedRowDetailsPane
|
||||||
|
sections={statsSections}
|
||||||
|
dataTestSubj={`mlAnalyticsTableRowDetailsTabContent job-stats ${item.config.id}`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
'data-test-subj': `mlAnalyticsTableRowDetailsTab job-stats ${item.config.id}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ml-analytics-job-json',
|
id: 'ml-analytics-job-json',
|
||||||
name: 'JSON',
|
name: 'JSON',
|
||||||
content: <ExpandedRowJsonPane json={item.config} />,
|
content: (
|
||||||
|
<ExpandedRowJsonPane
|
||||||
|
json={item.config}
|
||||||
|
dataTestSubj={`mlAnalyticsTableRowDetailsTabContent json ${item.config.id}`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
'data-test-subj': `mlAnalyticsTableRowDetailsTab json ${item.config.id}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ml-analytics-job-messages',
|
id: 'ml-analytics-job-messages',
|
||||||
|
@ -389,7 +411,13 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
defaultMessage: 'Job messages',
|
defaultMessage: 'Job messages',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
content: <ExpandedRowMessagesPane analyticsId={item.id} />,
|
content: (
|
||||||
|
<ExpandedRowMessagesPane
|
||||||
|
analyticsId={item.id}
|
||||||
|
dataTestSubj={`mlAnalyticsTableRowDetailsTabContent job-messages ${item.config.id}`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
'data-test-subj': `mlAnalyticsTableRowDetailsTab job-messages ${item.config.id}`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -406,6 +434,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
||||||
onTabClick={() => {}}
|
onTabClick={() => {}}
|
||||||
expand={false}
|
expand={false}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
|
data-test-subj={`mlAnalyticsTableRowDetails-${item.config.id}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface SectionConfig {
|
||||||
title: string;
|
title: string;
|
||||||
position: 'left' | 'right';
|
position: 'left' | 'right';
|
||||||
items: SectionItem[];
|
items: SectionItem[];
|
||||||
|
dataTestSubj: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SectionProps {
|
interface SectionProps {
|
||||||
|
@ -44,7 +45,7 @@ export const Section: FC<SectionProps> = ({ section }) => {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div data-test-subj={section.dataTestSubj}>
|
||||||
<EuiTitle size="xs">
|
<EuiTitle size="xs">
|
||||||
<span>{section.title}</span>
|
<span>{section.title}</span>
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
|
@ -55,18 +56,23 @@ export const Section: FC<SectionProps> = ({ section }) => {
|
||||||
tableCaption={section.title}
|
tableCaption={section.title}
|
||||||
tableLayout="auto"
|
tableLayout="auto"
|
||||||
className="mlExpandedRowDetailsSection"
|
className="mlExpandedRowDetailsSection"
|
||||||
|
data-test-subj={`${section.dataTestSubj}-table`}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ExpandedRowDetailsPaneProps {
|
interface ExpandedRowDetailsPaneProps {
|
||||||
sections: SectionConfig[];
|
sections: SectionConfig[];
|
||||||
|
dataTestSubj: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExpandedRowDetailsPane: FC<ExpandedRowDetailsPaneProps> = ({ sections }) => {
|
export const ExpandedRowDetailsPane: FC<ExpandedRowDetailsPaneProps> = ({
|
||||||
|
sections,
|
||||||
|
dataTestSubj,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<EuiFlexGroup className="mlExpandedRowDetails">
|
<EuiFlexGroup className="mlExpandedRowDetails" data-test-subj={dataTestSubj}>
|
||||||
<EuiFlexItem style={{ width: '50%' }}>
|
<EuiFlexItem style={{ width: '50%' }}>
|
||||||
{sections
|
{sections
|
||||||
.filter((s) => s.position === 'left')
|
.filter((s) => s.position === 'left')
|
||||||
|
|
|
@ -11,11 +11,12 @@ import { EuiCodeEditor, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eu
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
json: object;
|
json: object;
|
||||||
|
dataTestSubj: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExpandedRowJsonPane: FC<Props> = ({ json }) => {
|
export const ExpandedRowJsonPane: FC<Props> = ({ json, dataTestSubj }) => {
|
||||||
return (
|
return (
|
||||||
<EuiFlexGroup>
|
<EuiFlexGroup data-test-subj={dataTestSubj}>
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiSpacer size="s" />
|
<EuiSpacer size="s" />
|
||||||
<EuiCodeEditor
|
<EuiCodeEditor
|
||||||
|
@ -24,6 +25,7 @@ export const ExpandedRowJsonPane: FC<Props> = ({ json }) => {
|
||||||
mode="json"
|
mode="json"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
theme="textmate"
|
theme="textmate"
|
||||||
|
data-test-subj={`mlAnalyticsDetailsJsonPreview`}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem grow={false}> </EuiFlexItem>
|
<EuiFlexItem grow={false}> </EuiFlexItem>
|
||||||
|
|
|
@ -17,9 +17,10 @@ import { useToastNotificationService } from '../../../../../services/toast_notif
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
analyticsId: string;
|
analyticsId: string;
|
||||||
|
dataTestSubj: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId }) => {
|
export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId, dataTestSubj }) => {
|
||||||
const [messages, setMessages] = useState<JobMessage[]>([]);
|
const [messages, setMessages] = useState<JobMessage[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [errorMessage, setErrorMessage] = useState('');
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
|
@ -58,7 +59,7 @@ export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId }) => {
|
||||||
useRefreshAnalyticsList({ onRefresh: getMessages });
|
useRefreshAnalyticsList({ onRefresh: getMessages });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mlExpandedRowJobMessages">
|
<div className="mlExpandedRowJobMessages" data-test-subj={dataTestSubj}>
|
||||||
<JobMessages
|
<JobMessages
|
||||||
messages={messages}
|
messages={messages}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
|
||||||
export default function ({ getService }: FtrProviderContext) {
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
|
@ -25,11 +26,12 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await ml.api.cleanMlIndices();
|
await ml.api.cleanMlIndices();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const jobId = `bm_1_${Date.now()}`;
|
||||||
const testDataList = [
|
const testDataList = [
|
||||||
{
|
{
|
||||||
suiteTitle: 'bank marketing',
|
suiteTitle: 'bank marketing',
|
||||||
jobType: 'classification',
|
jobType: 'classification',
|
||||||
jobId: `bm_1_${Date.now()}`,
|
jobId,
|
||||||
jobDescription:
|
jobDescription:
|
||||||
"Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",
|
"Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",
|
||||||
source: 'ft_bank_marketing',
|
source: 'ft_bank_marketing',
|
||||||
|
@ -68,6 +70,30 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: 'stopped',
|
status: 'stopped',
|
||||||
progress: '100',
|
progress: '100',
|
||||||
},
|
},
|
||||||
|
rowDetails: {
|
||||||
|
jobDetails: [
|
||||||
|
{
|
||||||
|
section: 'state',
|
||||||
|
expectedEntries: {
|
||||||
|
id: jobId,
|
||||||
|
state: 'stopped',
|
||||||
|
data_counts:
|
||||||
|
'{"training_docs_count":1862,"test_docs_count":7452,"skipped_docs_count":0}',
|
||||||
|
description:
|
||||||
|
"Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ section: 'progress', expectedEntries: { Phase: '8/8' } },
|
||||||
|
],
|
||||||
|
jobStats: [
|
||||||
|
{
|
||||||
|
section: 'stats',
|
||||||
|
expectedEntries: {
|
||||||
|
version: '8.0.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as AnalyticsTableRowDetails,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -230,6 +256,11 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: testData.expected.row.status,
|
status: testData.expected.row.status,
|
||||||
progress: testData.expected.row.progress,
|
progress: testData.expected.row.progress,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails(
|
||||||
|
testData.jobId,
|
||||||
|
testData.expected.rowDetails
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('edits the analytics job and displays it correctly in the job list', async () => {
|
it('edits the analytics job and displays it correctly in the job list', async () => {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||||
|
|
||||||
export default function ({ getService }: FtrProviderContext) {
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
const esArchiver = getService('esArchiver');
|
const esArchiver = getService('esArchiver');
|
||||||
|
@ -25,15 +26,17 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await ml.api.cleanMlIndices();
|
await ml.api.cleanMlIndices();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const jobId = `ihp_1_${Date.now()}`;
|
||||||
|
|
||||||
const testDataList = [
|
const testDataList = [
|
||||||
{
|
{
|
||||||
suiteTitle: 'iowa house prices',
|
suiteTitle: 'iowa house prices',
|
||||||
jobType: 'outlier_detection',
|
jobType: 'outlier_detection',
|
||||||
jobId: `ihp_1_${Date.now()}`,
|
jobId,
|
||||||
jobDescription: 'This is the job description',
|
jobDescription: 'Outlier detection job based on ft_ihp_outlier dataset with runtime fields',
|
||||||
source: 'ft_ihp_outlier',
|
source: 'ft_ihp_outlier',
|
||||||
get destinationIndex(): string {
|
get destinationIndex(): string {
|
||||||
return `user-${this.jobId}`;
|
return `user-${jobId}`;
|
||||||
},
|
},
|
||||||
runtimeFields: {
|
runtimeFields: {
|
||||||
lowercase_central_air: {
|
lowercase_central_air: {
|
||||||
|
@ -82,6 +85,30 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: 'stopped',
|
status: 'stopped',
|
||||||
progress: '100',
|
progress: '100',
|
||||||
},
|
},
|
||||||
|
rowDetails: {
|
||||||
|
jobDetails: [
|
||||||
|
{
|
||||||
|
section: 'state',
|
||||||
|
expectedEntries: {
|
||||||
|
id: jobId,
|
||||||
|
state: 'stopped',
|
||||||
|
data_counts:
|
||||||
|
'{"training_docs_count":1460,"test_docs_count":0,"skipped_docs_count":0}',
|
||||||
|
description:
|
||||||
|
'Outlier detection job based on ft_ihp_outlier dataset with runtime fields',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ section: 'progress', expectedEntries: { Phase: '4/4' } },
|
||||||
|
],
|
||||||
|
jobStats: [
|
||||||
|
{
|
||||||
|
section: 'stats',
|
||||||
|
expectedEntries: {
|
||||||
|
version: '8.0.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as AnalyticsTableRowDetails,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -246,6 +273,11 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: testData.expected.row.status,
|
status: testData.expected.row.status,
|
||||||
progress: testData.expected.row.progress,
|
progress: testData.expected.row.progress,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails(
|
||||||
|
testData.jobId,
|
||||||
|
testData.expected.rowDetails
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('edits the analytics job and displays it correctly in the job list', async () => {
|
it('edits the analytics job and displays it correctly in the job list', async () => {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||||
|
|
||||||
export default function ({ getService }: FtrProviderContext) {
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
const esArchiver = getService('esArchiver');
|
const esArchiver = getService('esArchiver');
|
||||||
|
@ -25,15 +26,16 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await ml.api.cleanMlIndices();
|
await ml.api.cleanMlIndices();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const jobId = `egs_1_${Date.now()}`;
|
||||||
const testDataList = [
|
const testDataList = [
|
||||||
{
|
{
|
||||||
suiteTitle: 'electrical grid stability',
|
suiteTitle: 'electrical grid stability',
|
||||||
jobType: 'regression',
|
jobType: 'regression',
|
||||||
jobId: `egs_1_${Date.now()}`,
|
jobId,
|
||||||
jobDescription: 'This is the job description',
|
jobDescription: 'Regression job based on ft_egs_regression dataset with runtime fields',
|
||||||
source: 'ft_egs_regression',
|
source: 'ft_egs_regression',
|
||||||
get destinationIndex(): string {
|
get destinationIndex(): string {
|
||||||
return `user-${this.jobId}`;
|
return `user-${jobId}`;
|
||||||
},
|
},
|
||||||
runtimeFields: {
|
runtimeFields: {
|
||||||
uppercase_stab: {
|
uppercase_stab: {
|
||||||
|
@ -61,6 +63,30 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: 'stopped',
|
status: 'stopped',
|
||||||
progress: '100',
|
progress: '100',
|
||||||
},
|
},
|
||||||
|
rowDetails: {
|
||||||
|
jobDetails: [
|
||||||
|
{
|
||||||
|
section: 'state',
|
||||||
|
expectedEntries: {
|
||||||
|
id: jobId,
|
||||||
|
state: 'stopped',
|
||||||
|
data_counts:
|
||||||
|
'{"training_docs_count":400,"test_docs_count":1600,"skipped_docs_count":0}',
|
||||||
|
description:
|
||||||
|
'Regression job based on ft_egs_regression dataset with runtime fields',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ section: 'progress', expectedEntries: { Phase: '8/8' } },
|
||||||
|
],
|
||||||
|
jobStats: [
|
||||||
|
{
|
||||||
|
section: 'stats',
|
||||||
|
expectedEntries: {
|
||||||
|
version: '8.0.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as AnalyticsTableRowDetails,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -219,6 +245,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
status: testData.expected.row.status,
|
status: testData.expected.row.status,
|
||||||
progress: testData.expected.row.progress,
|
progress: testData.expected.row.progress,
|
||||||
});
|
});
|
||||||
|
await ml.dataFrameAnalyticsTable.assertAnalyticsRowDetails(
|
||||||
|
testData.jobId,
|
||||||
|
testData.expected.rowDetails
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('edits the analytics job and displays it correctly in the job list', async () => {
|
it('edits the analytics job and displays it correctly in the job list', async () => {
|
||||||
|
|
|
@ -309,7 +309,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
'should display enabled DFA job view and action menu'
|
'should display enabled DFA job view and action menu'
|
||||||
);
|
);
|
||||||
await ml.dataFrameAnalyticsTable.assertJobRowViewButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobRowViewButtonEnabled(dfaJobId, true);
|
||||||
await ml.dataFrameAnalyticsTable.assertJowRowActionsMenuButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobRowActionsMenuButtonEnabled(dfaJobId, true);
|
||||||
await ml.dataFrameAnalyticsTable.assertJobActionViewButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobActionViewButtonEnabled(dfaJobId, true);
|
||||||
|
|
||||||
await ml.testExecution.logTestStep('should display enabled DFA job row action buttons');
|
await ml.testExecution.logTestStep('should display enabled DFA job row action buttons');
|
||||||
|
|
|
@ -300,7 +300,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
'should display enabled DFA job view and action menu'
|
'should display enabled DFA job view and action menu'
|
||||||
);
|
);
|
||||||
await ml.dataFrameAnalyticsTable.assertJobRowViewButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobRowViewButtonEnabled(dfaJobId, true);
|
||||||
await ml.dataFrameAnalyticsTable.assertJowRowActionsMenuButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobRowActionsMenuButtonEnabled(dfaJobId, true);
|
||||||
await ml.dataFrameAnalyticsTable.assertJobActionViewButtonEnabled(dfaJobId, true);
|
await ml.dataFrameAnalyticsTable.assertJobActionViewButtonEnabled(dfaJobId, true);
|
||||||
|
|
||||||
await ml.testExecution.logTestStep(
|
await ml.testExecution.logTestStep(
|
||||||
|
|
|
@ -10,6 +10,13 @@ import expect from '@kbn/expect';
|
||||||
import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper';
|
import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper';
|
||||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
|
type ExpectedSectionTableEntries = Record<string, string>;
|
||||||
|
export interface ExpectedSectionTable {
|
||||||
|
section: string;
|
||||||
|
expectedEntries: ExpectedSectionTableEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AnalyticsTableRowDetails = Record<'jobDetails' | 'jobStats', ExpectedSectionTable[]>;
|
||||||
export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: FtrProviderContext) {
|
export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: FtrProviderContext) {
|
||||||
const find = getService('find');
|
const find = getService('find');
|
||||||
const retry = getService('retry');
|
const retry = getService('retry');
|
||||||
|
@ -160,7 +167,7 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async assertJowRowActionsMenuButtonEnabled(analyticsId: string, expectedValue: boolean) {
|
public async assertJobRowActionsMenuButtonEnabled(analyticsId: string, expectedValue: boolean) {
|
||||||
const isEnabled = await testSubjects.isEnabled(
|
const isEnabled = await testSubjects.isEnabled(
|
||||||
this.rowSelector(analyticsId, 'euiCollapsedItemActionsButton')
|
this.rowSelector(analyticsId, 'euiCollapsedItemActionsButton')
|
||||||
);
|
);
|
||||||
|
@ -259,5 +266,175 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F
|
||||||
await testSubjects.click(`mlAnalyticsJobCloneButton`);
|
await testSubjects.click(`mlAnalyticsJobCloneButton`);
|
||||||
await testSubjects.existOrFail('mlAnalyticsCreationContainer');
|
await testSubjects.existOrFail('mlAnalyticsCreationContainer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public detailsSelector(jobId: string, subSelector?: string) {
|
||||||
|
const row = `mlAnalyticsTableRowDetails-${jobId}`;
|
||||||
|
return !subSelector ? row : `${row} > ${subSelector}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertRowDetailsTabExist(jobId: string, tabId: string) {
|
||||||
|
const selector = `~mlAnalyticsTableRowDetailsTab > ~${tabId} > ${jobId}`;
|
||||||
|
await testSubjects.existOrFail(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async withDetailsOpen<T>(jobId: string, block: () => Promise<T>): Promise<T> {
|
||||||
|
await this.ensureDetailsOpen(jobId);
|
||||||
|
try {
|
||||||
|
return await block();
|
||||||
|
} finally {
|
||||||
|
await this.ensureDetailsClosed(jobId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ensureDetailsOpen(jobId: string) {
|
||||||
|
await retry.tryForTime(10000, async () => {
|
||||||
|
if (!(await testSubjects.exists(this.detailsSelector(jobId)))) {
|
||||||
|
await testSubjects.click(this.rowSelector(jobId, 'mlAnalyticsTableRowDetailsToggle'));
|
||||||
|
await testSubjects.existOrFail(this.detailsSelector(jobId), { timeout: 1000 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ensureDetailsClosed(jobId: string) {
|
||||||
|
await retry.tryForTime(10000, async () => {
|
||||||
|
if (await testSubjects.exists(this.detailsSelector(jobId))) {
|
||||||
|
await testSubjects.click(this.rowSelector(jobId, 'mlAnalyticsTableRowDetailsToggle'));
|
||||||
|
await testSubjects.missingOrFail(this.detailsSelector(jobId), { timeout: 1000 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertRowDetailsTabsExist(tabTypeSubject: string, areaSubjects: string[]) {
|
||||||
|
await retry.tryForTime(10000, async () => {
|
||||||
|
const allTabs = await testSubjects.findAll(`~${tabTypeSubject}`, 3);
|
||||||
|
expect(allTabs).to.have.length(
|
||||||
|
areaSubjects.length,
|
||||||
|
`Expected number of '${tabTypeSubject}' to be '${areaSubjects.length}' (got '${allTabs.length}')`
|
||||||
|
);
|
||||||
|
for (const areaSubj of areaSubjects) {
|
||||||
|
await testSubjects.existOrFail(`~${tabTypeSubject}&~${areaSubj}`, { timeout: 1000 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertRowDetailsTabEnabled(tabSubject: string, expectedValue: boolean) {
|
||||||
|
const isEnabled = await testSubjects.isEnabled(tabSubject);
|
||||||
|
expect(isEnabled).to.eql(
|
||||||
|
expectedValue,
|
||||||
|
`Expected Analytics details tab '${tabSubject}' to be '${
|
||||||
|
expectedValue ? 'enabled' : 'disabled'
|
||||||
|
}' (got '${isEnabled ? 'enabled' : 'disabled'}')`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ensureDetailsTabOpen(jobId: string, tabSubject: string) {
|
||||||
|
const tabSelector = `~mlAnalyticsTableRowDetailsTab&~${tabSubject}&~${jobId}`;
|
||||||
|
const tabContentSelector = `~mlAnalyticsTableRowDetailsTabContent&~${tabSubject}&~${jobId}`;
|
||||||
|
|
||||||
|
await retry.tryForTime(10000, async () => {
|
||||||
|
if (!(await testSubjects.exists(tabContentSelector))) {
|
||||||
|
await this.assertRowDetailsTabEnabled(tabSelector, true);
|
||||||
|
await testSubjects.click(tabSelector);
|
||||||
|
await testSubjects.existOrFail(tabContentSelector, { timeout: 1000 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public detailsSectionSelector(jobId: string, sectionSubject: string) {
|
||||||
|
const subSelector = `~mlAnalyticsTableRowDetailsSection&~${sectionSubject}`;
|
||||||
|
return this.detailsSelector(jobId, subSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertDetailsSectionExists(jobId: string, sectionSubject: string) {
|
||||||
|
const selector = this.detailsSectionSelector(jobId, sectionSubject);
|
||||||
|
await retry.tryForTime(10000, async () => {
|
||||||
|
await testSubjects.existOrFail(selector, { timeout: 1000 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async parseDetailsSectionTable(el: WebElementWrapper) {
|
||||||
|
const $ = await el.parseDomContent();
|
||||||
|
const vars: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const row of $('tr').toArray()) {
|
||||||
|
const [name, value] = $(row).find('td').toArray();
|
||||||
|
|
||||||
|
vars[$(name).text().trim()] = $(value).text().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertRowDetailsSectionContent(
|
||||||
|
jobId: string,
|
||||||
|
sectionSubject: string,
|
||||||
|
expectedEntries: ExpectedSectionTable['expectedEntries']
|
||||||
|
) {
|
||||||
|
const sectionSelector = this.detailsSectionSelector(jobId, sectionSubject);
|
||||||
|
await this.assertDetailsSectionExists(jobId, sectionSubject);
|
||||||
|
|
||||||
|
const sectionTable = await testSubjects.find(`${sectionSelector}-table`);
|
||||||
|
const parsedSectionTableEntries = await this.parseDetailsSectionTable(sectionTable);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(expectedEntries)) {
|
||||||
|
expect(parsedSectionTableEntries)
|
||||||
|
.to.have.property(key)
|
||||||
|
.eql(
|
||||||
|
value,
|
||||||
|
`Expected ${sectionSubject} property '${key}' to exist with value '${value}'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertJobDetailsTabContent(jobId: string, sections: ExpectedSectionTable[]) {
|
||||||
|
const tabSubject = 'job-details';
|
||||||
|
await this.ensureDetailsTabOpen(jobId, tabSubject);
|
||||||
|
|
||||||
|
for (const { section, expectedEntries } of sections) {
|
||||||
|
await this.assertRowDetailsSectionContent(jobId, section, expectedEntries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertJobStatsTabContent(jobId: string, sections: ExpectedSectionTable[]) {
|
||||||
|
const tabSubject = 'job-stats';
|
||||||
|
await this.ensureDetailsTabOpen(jobId, tabSubject);
|
||||||
|
await this.assertDetailsSectionExists(jobId, 'stats');
|
||||||
|
|
||||||
|
for (const { section, expectedEntries } of sections) {
|
||||||
|
await this.assertRowDetailsSectionContent(jobId, section, expectedEntries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertJsonTabContent(jobId: string) {
|
||||||
|
const tabSubject = 'json';
|
||||||
|
await this.ensureDetailsTabOpen(jobId, tabSubject);
|
||||||
|
await testSubjects.existOrFail(this.detailsSelector(jobId, 'mlAnalyticsDetailsJsonPreview'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertJobMessagesTabContent(jobId: string) {
|
||||||
|
const tabSubject = 'job-messages';
|
||||||
|
await this.ensureDetailsTabOpen(jobId, tabSubject);
|
||||||
|
await testSubjects.existOrFail(
|
||||||
|
this.detailsSelector(jobId, 'mlAnalyticsDetailsJobMessagesTable')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertAnalyticsRowDetails(
|
||||||
|
jobId: string,
|
||||||
|
expectedRowDetails: AnalyticsTableRowDetails
|
||||||
|
) {
|
||||||
|
return await this.withDetailsOpen(jobId, async () => {
|
||||||
|
await this.assertRowDetailsTabsExist('mlAnalyticsTableRowDetailsTab', [
|
||||||
|
'job-details',
|
||||||
|
'job-stats',
|
||||||
|
'json',
|
||||||
|
'job-messages',
|
||||||
|
]);
|
||||||
|
await this.assertJobDetailsTabContent(jobId, expectedRowDetails.jobDetails);
|
||||||
|
await this.assertJobStatsTabContent(jobId, expectedRowDetails.jobStats);
|
||||||
|
await this.assertJsonTabContent(jobId);
|
||||||
|
await this.assertJobMessagesTabContent(jobId);
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue