[ML] Functional tests for Analytics list row expansion content (#98678)
This commit is contained in:
parent
18213b673f
commit
762c57b995
|
@ -93,6 +93,7 @@ export const JobMessages: FC<JobMessagesProps> = ({ messages, loading, error, re
|
|||
compressed={true}
|
||||
loading={loading}
|
||||
error={error}
|
||||
data-test-subj={'mlAnalyticsDetailsJobMessagesTable'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -192,6 +192,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
}),
|
||||
items: stateItems as SectionItem[],
|
||||
position: 'left',
|
||||
dataTestSubj: 'mlAnalyticsTableRowDetailsSection state',
|
||||
};
|
||||
|
||||
const { currentPhase, totalPhases } = getDataFrameAnalyticsProgressPhase(item.stats);
|
||||
|
@ -217,6 +218,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
}),
|
||||
],
|
||||
position: 'right',
|
||||
dataTestSubj: 'mlAnalyticsTableRowDetailsSection progress',
|
||||
};
|
||||
|
||||
const stats: SectionConfig = {
|
||||
|
@ -234,6 +236,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
{ title: 'version', description: item.config.version },
|
||||
],
|
||||
position: 'left',
|
||||
dataTestSubj: 'mlAnalyticsTableRowDetailsSection stats',
|
||||
};
|
||||
|
||||
const analysisStats: SectionConfig | undefined = analysisStatsValues
|
||||
|
@ -263,6 +266,7 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
}),
|
||||
],
|
||||
position: 'right',
|
||||
dataTestSubj: 'mlAnalyticsTableRowDetailsSection analysisStats',
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
@ -364,7 +368,13 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
name: i18n.translate('xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettingsLabel', {
|
||||
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',
|
||||
|
@ -374,12 +384,24 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
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',
|
||||
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',
|
||||
|
@ -389,7 +411,13 @@ export const ExpandedRow: FC<Props> = ({ item }) => {
|
|||
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={() => {}}
|
||||
expand={false}
|
||||
style={{ width: '100%' }}
|
||||
data-test-subj={`mlAnalyticsTableRowDetails-${item.config.id}`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ export interface SectionConfig {
|
|||
title: string;
|
||||
position: 'left' | 'right';
|
||||
items: SectionItem[];
|
||||
dataTestSubj: string;
|
||||
}
|
||||
|
||||
interface SectionProps {
|
||||
|
@ -44,7 +45,7 @@ export const Section: FC<SectionProps> = ({ section }) => {
|
|||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-test-subj={section.dataTestSubj}>
|
||||
<EuiTitle size="xs">
|
||||
<span>{section.title}</span>
|
||||
</EuiTitle>
|
||||
|
@ -55,18 +56,23 @@ export const Section: FC<SectionProps> = ({ section }) => {
|
|||
tableCaption={section.title}
|
||||
tableLayout="auto"
|
||||
className="mlExpandedRowDetailsSection"
|
||||
data-test-subj={`${section.dataTestSubj}-table`}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ExpandedRowDetailsPaneProps {
|
||||
sections: SectionConfig[];
|
||||
dataTestSubj: string;
|
||||
}
|
||||
|
||||
export const ExpandedRowDetailsPane: FC<ExpandedRowDetailsPaneProps> = ({ sections }) => {
|
||||
export const ExpandedRowDetailsPane: FC<ExpandedRowDetailsPaneProps> = ({
|
||||
sections,
|
||||
dataTestSubj,
|
||||
}) => {
|
||||
return (
|
||||
<EuiFlexGroup className="mlExpandedRowDetails">
|
||||
<EuiFlexGroup className="mlExpandedRowDetails" data-test-subj={dataTestSubj}>
|
||||
<EuiFlexItem style={{ width: '50%' }}>
|
||||
{sections
|
||||
.filter((s) => s.position === 'left')
|
||||
|
|
|
@ -11,11 +11,12 @@ import { EuiCodeEditor, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eu
|
|||
|
||||
interface Props {
|
||||
json: object;
|
||||
dataTestSubj: string;
|
||||
}
|
||||
|
||||
export const ExpandedRowJsonPane: FC<Props> = ({ json }) => {
|
||||
export const ExpandedRowJsonPane: FC<Props> = ({ json, dataTestSubj }) => {
|
||||
return (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexGroup data-test-subj={dataTestSubj}>
|
||||
<EuiFlexItem>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeEditor
|
||||
|
@ -24,6 +25,7 @@ export const ExpandedRowJsonPane: FC<Props> = ({ json }) => {
|
|||
mode="json"
|
||||
style={{ width: '100%' }}
|
||||
theme="textmate"
|
||||
data-test-subj={`mlAnalyticsDetailsJsonPreview`}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}> </EuiFlexItem>
|
||||
|
|
|
@ -17,9 +17,10 @@ import { useToastNotificationService } from '../../../../../services/toast_notif
|
|||
|
||||
interface Props {
|
||||
analyticsId: string;
|
||||
dataTestSubj: string;
|
||||
}
|
||||
|
||||
export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId }) => {
|
||||
export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId, dataTestSubj }) => {
|
||||
const [messages, setMessages] = useState<JobMessage[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
@ -58,7 +59,7 @@ export const ExpandedRowMessagesPane: FC<Props> = ({ analyticsId }) => {
|
|||
useRefreshAnalyticsList({ onRefresh: getMessages });
|
||||
|
||||
return (
|
||||
<div className="mlExpandedRowJobMessages">
|
||||
<div className="mlExpandedRowJobMessages" data-test-subj={dataTestSubj}>
|
||||
<JobMessages
|
||||
messages={messages}
|
||||
loading={isLoading}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
|
@ -25,11 +26,12 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.api.cleanMlIndices();
|
||||
});
|
||||
|
||||
const jobId = `bm_1_${Date.now()}`;
|
||||
const testDataList = [
|
||||
{
|
||||
suiteTitle: 'bank marketing',
|
||||
jobType: 'classification',
|
||||
jobId: `bm_1_${Date.now()}`,
|
||||
jobId,
|
||||
jobDescription:
|
||||
"Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",
|
||||
source: 'ft_bank_marketing',
|
||||
|
@ -68,6 +70,30 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
status: 'stopped',
|
||||
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,
|
||||
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 () => {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
@ -25,15 +26,17 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.api.cleanMlIndices();
|
||||
});
|
||||
|
||||
const jobId = `ihp_1_${Date.now()}`;
|
||||
|
||||
const testDataList = [
|
||||
{
|
||||
suiteTitle: 'iowa house prices',
|
||||
jobType: 'outlier_detection',
|
||||
jobId: `ihp_1_${Date.now()}`,
|
||||
jobDescription: 'This is the job description',
|
||||
jobId,
|
||||
jobDescription: 'Outlier detection job based on ft_ihp_outlier dataset with runtime fields',
|
||||
source: 'ft_ihp_outlier',
|
||||
get destinationIndex(): string {
|
||||
return `user-${this.jobId}`;
|
||||
return `user-${jobId}`;
|
||||
},
|
||||
runtimeFields: {
|
||||
lowercase_central_air: {
|
||||
|
@ -82,6 +85,30 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
status: 'stopped',
|
||||
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,
|
||||
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 () => {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { AnalyticsTableRowDetails } from '../../../services/ml/data_frame_analytics_table';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
@ -25,15 +26,16 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.api.cleanMlIndices();
|
||||
});
|
||||
|
||||
const jobId = `egs_1_${Date.now()}`;
|
||||
const testDataList = [
|
||||
{
|
||||
suiteTitle: 'electrical grid stability',
|
||||
jobType: 'regression',
|
||||
jobId: `egs_1_${Date.now()}`,
|
||||
jobDescription: 'This is the job description',
|
||||
jobId,
|
||||
jobDescription: 'Regression job based on ft_egs_regression dataset with runtime fields',
|
||||
source: 'ft_egs_regression',
|
||||
get destinationIndex(): string {
|
||||
return `user-${this.jobId}`;
|
||||
return `user-${jobId}`;
|
||||
},
|
||||
runtimeFields: {
|
||||
uppercase_stab: {
|
||||
|
@ -61,6 +63,30 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
status: 'stopped',
|
||||
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,
|
||||
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 () => {
|
||||
|
|
|
@ -309,7 +309,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
'should display enabled DFA job view and action menu'
|
||||
);
|
||||
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.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'
|
||||
);
|
||||
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.testExecution.logTestStep(
|
||||
|
|
|
@ -10,6 +10,13 @@ import expect from '@kbn/expect';
|
|||
import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper';
|
||||
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) {
|
||||
const find = getService('find');
|
||||
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(
|
||||
this.rowSelector(analyticsId, 'euiCollapsedItemActionsButton')
|
||||
);
|
||||
|
@ -259,5 +266,175 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F
|
|||
await testSubjects.click(`mlAnalyticsJobCloneButton`);
|
||||
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