[ML] Adds functional tests for anomaly detection job custom URLs (#100455)
* [ML] Adds functional tests for anomaly detection job custom URLs * [ML] Remove debug test tag from custom URL tests * [ML] Update custom URL editor Jest snapshots * [ML] Clean up in embeddables tests to fix dashboard test * [ML] Delete test dashboard after test suites complete * [ML] Edits to custom URL tests following review Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c5f8aeeb43
commit
f77ff2d396
|
@ -18,6 +18,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -63,6 +64,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="KIBANA_DASHBOARD"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -100,6 +102,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlDashboardNameInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -134,6 +137,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe
|
|||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
|
||||
fullWidth={false}
|
||||
isClearable={true}
|
||||
onChange={[Function]}
|
||||
|
@ -175,6 +179,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -215,6 +220,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -260,6 +266,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="KIBANA_DISCOVER"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -297,6 +304,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlDiscoverIndexPatternInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -331,6 +339,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
|
||||
fullWidth={false}
|
||||
isClearable={true}
|
||||
onChange={[Function]}
|
||||
|
@ -378,6 +387,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -420,6 +430,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with an enti
|
|||
>
|
||||
<EuiFieldText
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeIntervalInput"
|
||||
isInvalid={true}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
|
@ -449,6 +460,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -494,6 +506,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="KIBANA_DISCOVER"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -531,6 +544,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlDiscoverIndexPatternInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -565,6 +579,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
|
||||
fullWidth={false}
|
||||
isClearable={true}
|
||||
onChange={[Function]}
|
||||
|
@ -612,6 +627,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -650,6 +666,7 @@ exports[`CustomUrlEditor renders the editor for a discover type URL with valid t
|
|||
>
|
||||
<EuiFieldText
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeIntervalInput"
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
value="1h"
|
||||
|
@ -679,6 +696,7 @@ exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -728,6 +746,7 @@ exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="KIBANA_DASHBOARD"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -765,6 +784,7 @@ exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlDashboardNameInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -799,6 +819,7 @@ exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no
|
|||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
|
||||
fullWidth={false}
|
||||
isClearable={true}
|
||||
onChange={[Function]}
|
||||
|
@ -840,6 +861,7 @@ exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no
|
|||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeInput"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
|
@ -880,6 +902,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with duplicate
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -929,6 +952,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with duplicate
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="OTHER"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -966,6 +990,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with duplicate
|
|||
>
|
||||
<EuiTextArea
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlOtherTypeUrlInput"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
rows={2}
|
||||
|
@ -994,6 +1019,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with unique la
|
|||
/>
|
||||
<EuiForm
|
||||
className="ml-edit-url-form"
|
||||
data-test-subj="mlJobCustomUrlForm"
|
||||
>
|
||||
<EuiFormRow
|
||||
className="url-label"
|
||||
|
@ -1039,6 +1065,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with unique la
|
|||
>
|
||||
<EuiRadioGroup
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
idSelected="OTHER"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
|
@ -1076,6 +1103,7 @@ exports[`CustomUrlEditor renders the editor for other type of URL with unique la
|
|||
>
|
||||
<EuiTextArea
|
||||
compressed={true}
|
||||
data-test-subj="mlJobCustomUrlOtherTypeUrlInput"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
rows={2}
|
||||
|
|
|
@ -12,6 +12,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
grow={false}
|
||||
>
|
||||
<EuiFormRow
|
||||
data-test-subj="mlJobEditCustomUrlItemLabel"
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
error={Array []}
|
||||
|
@ -114,6 +115,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Test custom URL"
|
||||
color="primary"
|
||||
data-test-subj="mlJobEditTestCustomUrlButton"
|
||||
iconType="popout"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
@ -146,6 +148,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Delete custom URL"
|
||||
color="danger"
|
||||
data-test-subj="mlJobEditDeleteCustomUrlButton_0"
|
||||
iconType="trash"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
@ -162,6 +165,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
grow={false}
|
||||
>
|
||||
<EuiFormRow
|
||||
data-test-subj="mlJobEditCustomUrlItemLabel"
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
error={Array []}
|
||||
|
@ -264,6 +268,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Test custom URL"
|
||||
color="primary"
|
||||
data-test-subj="mlJobEditTestCustomUrlButton"
|
||||
iconType="popout"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
@ -296,6 +301,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Delete custom URL"
|
||||
color="danger"
|
||||
data-test-subj="mlJobEditDeleteCustomUrlButton_1"
|
||||
iconType="trash"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
@ -312,6 +318,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
grow={false}
|
||||
>
|
||||
<EuiFormRow
|
||||
data-test-subj="mlJobEditCustomUrlItemLabel"
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
error={Array []}
|
||||
|
@ -414,6 +421,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Test custom URL"
|
||||
color="primary"
|
||||
data-test-subj="mlJobEditTestCustomUrlButton"
|
||||
iconType="popout"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
@ -446,6 +454,7 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
|
|||
<EuiButtonIcon
|
||||
aria-label="Delete custom URL"
|
||||
color="danger"
|
||||
data-test-subj="mlJobEditDeleteCustomUrlButton_2"
|
||||
iconType="trash"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
|
|
|
@ -209,7 +209,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiForm className="ml-edit-url-form">
|
||||
<EuiForm className="ml-edit-url-form" data-test-subj="mlJobCustomUrlForm">
|
||||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage id="xpack.ml.customUrlsEditor.labelLabel" defaultMessage="Label" />
|
||||
|
@ -239,6 +239,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
idSelected={type}
|
||||
onChange={onTypeChange}
|
||||
className="url-link-to-radio"
|
||||
data-test-subj="mlJobCustomUrlLinkToTypeInput"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
|
@ -256,6 +257,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
options={dashboardOptions}
|
||||
value={kibanaSettings.dashboardId}
|
||||
onChange={onDashboardChange}
|
||||
data-test-subj="mlJobCustomUrlDashboardNameInput"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -275,6 +277,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
options={indexPatternOptions}
|
||||
value={kibanaSettings.discoverIndexPatternId}
|
||||
onChange={onDiscoverIndexPatternChange}
|
||||
data-test-subj="mlJobCustomUrlDiscoverIndexPatternInput"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -298,6 +301,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
selectedOptions={selectedEntityOptions}
|
||||
onChange={onQueryEntitiesChange}
|
||||
isClearable={true}
|
||||
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
|
@ -321,6 +325,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
options={timeRangeOptions}
|
||||
value={timeRange.type}
|
||||
onChange={onTimeRangeTypeChange}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeInput"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -343,6 +348,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
value={timeRange.interval}
|
||||
onChange={onTimeRangeIntervalChange}
|
||||
isInvalid={isInvalidTimeRange}
|
||||
data-test-subj="mlJobCustomUrlTimeRangeIntervalInput"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -365,6 +371,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
|
|||
rows={2}
|
||||
value={otherUrlSettings.urlValue}
|
||||
onChange={onOtherUrlValueChange}
|
||||
data-test-subj="mlJobCustomUrlOtherTypeUrlInput"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -160,6 +160,7 @@ export const CustomUrlList: FC<CustomUrlListProps> = ({ job, customUrls, setCust
|
|||
}
|
||||
isInvalid={isInvalidLabel}
|
||||
error={invalidLabelError}
|
||||
data-test-subj="mlJobEditCustomUrlItemLabel"
|
||||
>
|
||||
<EuiFieldText
|
||||
value={label}
|
||||
|
@ -239,6 +240,7 @@ export const CustomUrlList: FC<CustomUrlListProps> = ({ job, customUrls, setCust
|
|||
aria-label={i18n.translate('xpack.ml.customUrlEditorList.testCustomUrlAriaLabel', {
|
||||
defaultMessage: 'Test custom URL',
|
||||
})}
|
||||
data-test-subj="mlJobEditTestCustomUrlButton"
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
|
@ -264,6 +266,7 @@ export const CustomUrlList: FC<CustomUrlListProps> = ({ job, customUrls, setCust
|
|||
defaultMessage: 'Delete custom URL',
|
||||
}
|
||||
)}
|
||||
data-test-subj={`mlJobEditDeleteCustomUrlButton_${index}`}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -326,6 +326,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
const tabs = [
|
||||
{
|
||||
id: 'job-details',
|
||||
'data-test-subj': 'mlEditJobFlyout-jobDetails',
|
||||
name: i18n.translate('xpack.ml.jobsList.editJobFlyout.jobDetailsTitle', {
|
||||
defaultMessage: 'Job details',
|
||||
}),
|
||||
|
@ -346,6 +347,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
},
|
||||
{
|
||||
id: 'detectors',
|
||||
'data-test-subj': 'mlEditJobFlyout-detectors',
|
||||
name: i18n.translate('xpack.ml.jobsList.editJobFlyout.detectorsTitle', {
|
||||
defaultMessage: 'Detectors',
|
||||
}),
|
||||
|
@ -359,6 +361,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
},
|
||||
{
|
||||
id: 'datafeed',
|
||||
'data-test-subj': 'mlEditJobFlyout-datafeed',
|
||||
name: i18n.translate('xpack.ml.jobsList.editJobFlyout.datafeedTitle', {
|
||||
defaultMessage: 'Datafeed',
|
||||
}),
|
||||
|
@ -376,6 +379,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
},
|
||||
{
|
||||
id: 'custom-urls',
|
||||
'data-test-subj': 'mlEditJobFlyout-customUrls',
|
||||
name: i18n.translate('xpack.ml.jobsList.editJobFlyout.customUrlsTitle', {
|
||||
defaultMessage: 'Custom URLs',
|
||||
}),
|
||||
|
@ -395,6 +399,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
this.closeFlyout();
|
||||
}}
|
||||
size="m"
|
||||
data-test-subj="mlJobEditFlyout"
|
||||
>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiTitle>
|
||||
|
@ -419,6 +424,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
this.closeFlyout();
|
||||
}}
|
||||
flush="left"
|
||||
data-test-subj="mlEditJobFlyoutCloseButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.jobsList.editJobFlyout.closeButtonLabel"
|
||||
|
@ -431,6 +437,7 @@ export class EditJobFlyoutUI extends Component {
|
|||
onClick={this.save}
|
||||
fill
|
||||
isDisabled={isValidJobDetails === false || isValidJobCustomUrls === false}
|
||||
data-test-subj="mlEditJobFlyoutSaveButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.jobsList.editJobFlyout.saveButtonLabel"
|
||||
|
|
|
@ -613,7 +613,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen();
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists custom urls');
|
||||
await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard');
|
||||
await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard');
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists assigned calendars');
|
||||
await ml.jobWizardCommon.assertCalendarsSelection([calendarId]);
|
||||
|
|
|
@ -74,6 +74,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.securityUI.loginAsMlPowerUser();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.testResources.deleteMLTestDashboard();
|
||||
});
|
||||
|
||||
for (const testData of testDataList) {
|
||||
describe(testData.suiteSuffix, function () {
|
||||
before(async () => {
|
||||
|
|
|
@ -278,7 +278,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen();
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists custom urls');
|
||||
await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard');
|
||||
await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard');
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists assigned calendars');
|
||||
await ml.jobWizardCommon.assertCalendarsSelection([calendarId]);
|
||||
|
|
188
x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts
Normal file
188
x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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 { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { Job, Datafeed } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs';
|
||||
import {
|
||||
TimeRangeType,
|
||||
TIME_RANGE_TYPE,
|
||||
} from '../../../../../plugins/ml/public/application/jobs/components/custom_url_editor/constants';
|
||||
|
||||
interface DiscoverUrlConfig {
|
||||
label: string;
|
||||
indexPattern: string;
|
||||
queryEntityFieldNames: string[];
|
||||
timeRange: TimeRangeType;
|
||||
timeRangeInterval?: string;
|
||||
}
|
||||
|
||||
interface DashboardUrlConfig {
|
||||
label: string;
|
||||
dashboardName: string;
|
||||
queryEntityFieldNames: string[];
|
||||
timeRange: TimeRangeType;
|
||||
timeRangeInterval?: string;
|
||||
}
|
||||
|
||||
interface OtherUrlConfig {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// @ts-expect-error doesn't implement the full interface
|
||||
const JOB_CONFIG: Job = {
|
||||
job_id: `fq_multi_1_custom_urls`,
|
||||
description: 'mean(responsetime) partition=airline on farequote dataset with 30m bucket span',
|
||||
groups: ['farequote', 'automated', 'multi-metric'],
|
||||
analysis_config: {
|
||||
bucket_span: '30m',
|
||||
influencers: ['airline'],
|
||||
detectors: [{ function: 'mean', field_name: 'responsetime', partition_field_name: 'airline' }],
|
||||
},
|
||||
data_description: { time_field: '@timestamp' },
|
||||
analysis_limits: { model_memory_limit: '20mb' },
|
||||
model_plot_config: { enabled: true },
|
||||
};
|
||||
|
||||
// @ts-expect-error doesn't implement the full interface
|
||||
const DATAFEED_CONFIG: Datafeed = {
|
||||
datafeed_id: 'datafeed-fq_multi_1_custom_urls',
|
||||
indices: ['ft_farequote'],
|
||||
job_id: 'fq_multi_1_custom_urls',
|
||||
query: { bool: { must: [{ match_all: {} }] } },
|
||||
};
|
||||
|
||||
const testDiscoverCustomUrl: DiscoverUrlConfig = {
|
||||
label: 'Show data',
|
||||
indexPattern: 'ft_farequote',
|
||||
queryEntityFieldNames: ['airline'],
|
||||
timeRange: TIME_RANGE_TYPE.AUTO,
|
||||
};
|
||||
|
||||
const testDashboardCustomUrl: DashboardUrlConfig = {
|
||||
label: 'Show dashboard',
|
||||
dashboardName: 'ML Test',
|
||||
queryEntityFieldNames: [],
|
||||
timeRange: TIME_RANGE_TYPE.INTERVAL,
|
||||
timeRangeInterval: '1h',
|
||||
};
|
||||
|
||||
const testOtherCustomUrl: OtherUrlConfig = {
|
||||
label: 'elastic.co',
|
||||
url: 'https://www.elastic.co/',
|
||||
};
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const ml = getService('ml');
|
||||
const browser = getService('browser');
|
||||
|
||||
describe('custom urls', function () {
|
||||
this.tags(['mlqa']);
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('ml/farequote');
|
||||
await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp');
|
||||
await ml.testResources.createMLTestDashboardIfNeeded();
|
||||
await ml.testResources.setKibanaTimeZoneToUTC();
|
||||
|
||||
await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG);
|
||||
await ml.securityUI.loginAsMlPowerUser();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.testResources.deleteMLTestDashboard();
|
||||
await ml.api.cleanMlIndices();
|
||||
});
|
||||
|
||||
it('opens the custom URLs tab in the edit job flyout', async () => {
|
||||
await ml.testExecution.logTestStep('load the job management page');
|
||||
await ml.navigation.navigateToMl();
|
||||
await ml.navigation.navigateToJobManagement();
|
||||
|
||||
await ml.testExecution.logTestStep('open the custom URLs tab in the edit job flyout');
|
||||
await ml.jobTable.openEditCustomUrlsForJobTab(JOB_CONFIG.job_id);
|
||||
await ml.jobTable.closeEditJobFlyout();
|
||||
});
|
||||
|
||||
it('adds a custom URL with query entities to Discover in the edit job flyout', async () => {
|
||||
await ml.jobTable.addDiscoverCustomUrl(JOB_CONFIG.job_id, testDiscoverCustomUrl);
|
||||
});
|
||||
|
||||
it('adds a custom URL to Dashboard in the edit job flyout', async () => {
|
||||
await ml.jobTable.addDashboardCustomUrl(JOB_CONFIG.job_id, testDashboardCustomUrl);
|
||||
});
|
||||
|
||||
it('adds a custom URL to an external page in the edit job flyout', async () => {
|
||||
await ml.jobTable.addOtherTypeCustomUrl(JOB_CONFIG.job_id, testOtherCustomUrl);
|
||||
});
|
||||
|
||||
it('tests other type custom URL', async () => {
|
||||
await ml.jobTable.testOtherTypeCustomUrlAction(JOB_CONFIG.job_id, 2, testOtherCustomUrl.url);
|
||||
});
|
||||
|
||||
it('edits other type custom URL', async () => {
|
||||
const edit = {
|
||||
label: `${testOtherCustomUrl.url} edited`,
|
||||
url: `${testOtherCustomUrl.url}guide/index.html`,
|
||||
};
|
||||
await ml.testExecution.logTestStep('edit the custom URL in the edit job flyout');
|
||||
await ml.jobTable.editCustomUrl(JOB_CONFIG.job_id, 2, edit);
|
||||
|
||||
await ml.testExecution.logTestStep('tests custom URL edit has been applied');
|
||||
await ml.jobTable.testOtherTypeCustomUrlAction(JOB_CONFIG.job_id, 2, edit.url);
|
||||
await ml.jobTable.closeEditJobFlyout();
|
||||
});
|
||||
|
||||
it('deletes a custom URL', async () => {
|
||||
await ml.jobTable.deleteCustomUrl(JOB_CONFIG.job_id, 2);
|
||||
});
|
||||
|
||||
// wrapping into own describe to make sure new tab is cleaned up even if test failed
|
||||
// see: https://github.com/elastic/kibana/pull/67280#discussion_r430528122
|
||||
describe('tests Discover type custom URL', () => {
|
||||
let tabsCount = 1;
|
||||
const docCountFormatted = '268';
|
||||
|
||||
it('opens Discover page from test link in the edit job flyout', async () => {
|
||||
await ml.jobTable.openTestCustomUrl(JOB_CONFIG.job_id, 0);
|
||||
await browser.switchTab(1);
|
||||
tabsCount++;
|
||||
await ml.jobTable.testDiscoverCustomUrlAction(docCountFormatted);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
if (tabsCount > 1) {
|
||||
await browser.closeCurrentWindow();
|
||||
await browser.switchTab(0);
|
||||
await ml.jobTable.closeEditJobFlyout();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// wrapping into own describe to make sure new tab is cleaned up even if test failed
|
||||
// see: https://github.com/elastic/kibana/pull/67280#discussion_r430528122
|
||||
describe('tests Dashboard type custom URL', () => {
|
||||
let tabsCount = 1;
|
||||
const testDashboardPanelCount = 0; // ML Test dashboard has no content.
|
||||
|
||||
it('opens Dashboard page from test link in the edit job flyout', async () => {
|
||||
await ml.jobTable.openTestCustomUrl(JOB_CONFIG.job_id, 1);
|
||||
await browser.switchTab(1);
|
||||
tabsCount++;
|
||||
await ml.jobTable.testDashboardCustomUrlAction(testDashboardPanelCount);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
if (tabsCount > 1) {
|
||||
await browser.closeCurrentWindow();
|
||||
await browser.switchTab(0);
|
||||
await ml.jobTable.closeEditJobFlyout();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -23,5 +23,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./date_nanos_job'));
|
||||
loadTestFile(require.resolve('./annotations'));
|
||||
loadTestFile(require.resolve('./aggregated_scripted_job'));
|
||||
loadTestFile(require.resolve('./custom_urls'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen();
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists custom urls');
|
||||
await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard');
|
||||
await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard');
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists assigned calendars');
|
||||
await ml.jobWizardCommon.assertCalendarsSelection([calendarId]);
|
||||
|
|
|
@ -336,7 +336,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen();
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists custom urls');
|
||||
await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard');
|
||||
await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard');
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists assigned calendars');
|
||||
await ml.jobWizardCommon.assertCalendarsSelection([calendarId]);
|
||||
|
|
|
@ -262,7 +262,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen();
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists custom urls');
|
||||
await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard');
|
||||
await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard');
|
||||
|
||||
await ml.testExecution.logTestStep('job cloning persists assigned calendars');
|
||||
await ml.jobWizardCommon.assertCalendarsSelection([calendarId]);
|
||||
|
|
|
@ -123,6 +123,25 @@ export function MachineLearningCommonUIProvider({ getService }: FtrProviderConte
|
|||
await this.assertRadioGroupValue(testSubject, value);
|
||||
},
|
||||
|
||||
async assertSelectSelectedOptionVisibleText(testSubject: string, visibleText: string) {
|
||||
// Need to validate the selected option text, as the option value may be different to the visible text.
|
||||
const selectControl = await testSubjects.find(testSubject);
|
||||
const selectedValue = await selectControl.getAttribute('value');
|
||||
const selectedOption = await selectControl.findByCssSelector(`[value="${selectedValue}"]`);
|
||||
const selectedOptionText = await selectedOption.getVisibleText();
|
||||
expect(selectedOptionText).to.eql(
|
||||
visibleText,
|
||||
`Expected selected option visible text to be '${visibleText}' (got '${selectedOptionText}')`
|
||||
);
|
||||
},
|
||||
|
||||
async selectSelectValueByVisibleText(testSubject: string, visibleText: string) {
|
||||
// Cannot use await testSubjects.selectValue as the option value may be different to the text.
|
||||
const selectControl = await testSubjects.find(testSubject);
|
||||
await selectControl.type(visibleText);
|
||||
await this.assertSelectSelectedOptionVisibleText(testSubject, visibleText);
|
||||
},
|
||||
|
||||
async setMultiSelectFilter(testDataSubj: string, fieldTypes: string[]) {
|
||||
await testSubjects.clickWhenNotDisabled(`${testDataSubj}-button`);
|
||||
await testSubjects.existOrFail(`${testDataSubj}-popover`);
|
||||
|
|
|
@ -12,10 +12,25 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
|
||||
export type MlCustomUrls = ProvidedType<typeof MachineLearningCustomUrlsProvider>;
|
||||
|
||||
export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderContext) {
|
||||
export function MachineLearningCustomUrlsProvider({
|
||||
getService,
|
||||
getPageObjects,
|
||||
}: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const retry = getService('retry');
|
||||
const comboBox = getService('comboBox');
|
||||
const PageObjects = getPageObjects(['dashboard', 'discover', 'header']);
|
||||
|
||||
return {
|
||||
async assertCustomUrlsLength(expectedLength: number) {
|
||||
const customUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
const actualLength = customUrls.length;
|
||||
expect(expectedLength).to.eql(
|
||||
actualLength,
|
||||
`Expected number of custom urls to be '${expectedLength}' (got '${actualLength}')`
|
||||
);
|
||||
},
|
||||
|
||||
async assertCustomUrlLabelValue(expectedValue: string) {
|
||||
const actualCustomUrlLabel = await testSubjects.getAttribute(
|
||||
'mlJobCustomUrlLabelInput',
|
||||
|
@ -27,15 +42,68 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon
|
|||
);
|
||||
},
|
||||
|
||||
async setCustomUrlLabel(customUrlsLabel: string) {
|
||||
await testSubjects.setValue('mlJobCustomUrlLabelInput', customUrlsLabel, {
|
||||
async setCustomUrlLabel(customUrlLabel: string) {
|
||||
await testSubjects.setValue('mlJobCustomUrlLabelInput', customUrlLabel, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
await this.assertCustomUrlLabelValue(customUrlsLabel);
|
||||
await this.assertCustomUrlLabelValue(customUrlLabel);
|
||||
},
|
||||
|
||||
async assertCustomUrlItem(index: number, expectedLabel: string) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlItem_${index}`);
|
||||
async assertCustomUrlQueryEntitySelection(expectedFieldNames: string[]) {
|
||||
const actualFieldNames = await comboBox.getComboBoxSelectedOptions(
|
||||
'mlJobCustomUrlQueryEntitiesInput > comboBoxInput'
|
||||
);
|
||||
expect(actualFieldNames).to.eql(
|
||||
expectedFieldNames,
|
||||
`Expected query entity selection to be '${expectedFieldNames}' (got '${actualFieldNames}')`
|
||||
);
|
||||
},
|
||||
|
||||
async setCustomUrlQueryEntityFieldNames(fieldNames: string[]) {
|
||||
for (const fieldName of fieldNames) {
|
||||
await comboBox.set('mlJobCustomUrlQueryEntitiesInput > comboBoxInput', fieldName);
|
||||
}
|
||||
await this.assertCustomUrlQueryEntitySelection(fieldNames);
|
||||
},
|
||||
|
||||
async assertCustomUrlTimeRangeIntervalValue(expectedInterval: string) {
|
||||
const actualCustomUrlTimeRangeInterval = await testSubjects.getAttribute(
|
||||
'mlJobCustomUrlTimeRangeIntervalInput',
|
||||
'value'
|
||||
);
|
||||
expect(actualCustomUrlTimeRangeInterval).to.eql(
|
||||
expectedInterval,
|
||||
`Expected custom url time range interval to be '${expectedInterval}' (got '${actualCustomUrlTimeRangeInterval}')`
|
||||
);
|
||||
},
|
||||
|
||||
async setCustomUrlTimeRangeInterval(interval: string) {
|
||||
await testSubjects.setValue('mlJobCustomUrlTimeRangeIntervalInput', interval, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
await this.assertCustomUrlTimeRangeIntervalValue(interval);
|
||||
},
|
||||
|
||||
async assertCustomUrlOtherTypeUrlValue(expectedUrl: string) {
|
||||
const actualCustomUrlValue = await testSubjects.getAttribute(
|
||||
'mlJobCustomUrlOtherTypeUrlInput',
|
||||
'value'
|
||||
);
|
||||
expect(actualCustomUrlValue).to.eql(
|
||||
expectedUrl,
|
||||
`Expected other type custom url value to be '${expectedUrl}' (got '${actualCustomUrlValue}')`
|
||||
);
|
||||
},
|
||||
|
||||
async setCustomUrlOtherTypeUrl(url: string) {
|
||||
await testSubjects.setValue('mlJobCustomUrlOtherTypeUrlInput', url, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
await this.assertCustomUrlOtherTypeUrlValue(url);
|
||||
},
|
||||
|
||||
async assertCustomUrlLabel(index: number, expectedLabel: string) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlLabelInput_${index}`);
|
||||
const actualLabel = await testSubjects.getAttribute(
|
||||
`mlJobEditCustomUrlLabelInput_${index}`,
|
||||
'value'
|
||||
|
@ -46,6 +114,44 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon
|
|||
);
|
||||
},
|
||||
|
||||
async assertCustomUrlUrlValue(index: number, expectedUrl: string) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlInput_${index}`);
|
||||
const actualUrl = await testSubjects.getAttribute(
|
||||
`mlJobEditCustomUrlInput_${index}`,
|
||||
'value'
|
||||
);
|
||||
expect(actualUrl).to.eql(
|
||||
expectedUrl,
|
||||
`Expected custom url item to be '${expectedUrl}' (got '${actualUrl}')`
|
||||
);
|
||||
},
|
||||
|
||||
async editCustomUrlLabel(index: number, label: string) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlLabelInput_${index}`);
|
||||
await testSubjects.setValue(`mlJobEditCustomUrlLabelInput_${index}`, label, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
await this.assertCustomUrlLabel(index, label);
|
||||
},
|
||||
|
||||
async editCustomUrlUrlValue(index: number, urlValue: string) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlInput_${index}`);
|
||||
await testSubjects.setValue(`mlJobEditCustomUrlInput_${index}`, urlValue, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
||||
// Click away, so the textarea reverts back to the standard input.
|
||||
await testSubjects.click(`mlJobEditCustomUrlLabelInput_${index}`);
|
||||
await this.assertCustomUrlUrlValue(index, urlValue);
|
||||
},
|
||||
|
||||
async deleteCustomUrl(index: number) {
|
||||
await testSubjects.existOrFail(`mlJobEditDeleteCustomUrlButton_${index}`);
|
||||
const beforeCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
await testSubjects.click(`mlJobEditDeleteCustomUrlButton_${index}`);
|
||||
await this.assertCustomUrlsLength(beforeCustomUrls.length - 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Submits the custom url form and adds it to the list.
|
||||
* @param formContainerSelector - selector for the element that wraps the custom url creation form.
|
||||
|
@ -54,5 +160,33 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon
|
|||
await testSubjects.click('mlJobAddCustomUrl');
|
||||
await testSubjects.missingOrFail(formContainerSelector, { timeout: 10 * 1000 });
|
||||
},
|
||||
|
||||
async clickTestCustomUrl(index: number) {
|
||||
await testSubjects.existOrFail(`mlJobEditCustomUrlItem_${index}`);
|
||||
await testSubjects.click(`mlJobEditCustomUrlItem_${index} > mlJobEditTestCustomUrlButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
},
|
||||
|
||||
async assertDiscoverCustomUrlAction(expectedHitCountFormatted: string) {
|
||||
await PageObjects.discover.waitForDiscoverAppOnScreen();
|
||||
await retry.tryForTime(5000, async () => {
|
||||
const hitCount = await PageObjects.discover.getHitCount();
|
||||
expect(hitCount).to.eql(
|
||||
expectedHitCountFormatted,
|
||||
`Expected Discover hit count to be '${expectedHitCountFormatted}' (got '${hitCount}')`
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
async assertDashboardCustomUrlAction(expectedPanelCount: number) {
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await retry.tryForTime(5000, async () => {
|
||||
const panelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(panelCount).to.eql(
|
||||
expectedPanelCount,
|
||||
`Expected Dashboard panel count to be '${expectedPanelCount}' (got '${panelCount}')`
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ export function MachineLearningProvider(context: FtrProviderContext) {
|
|||
const jobManagement = MachineLearningJobManagementProvider(context, api);
|
||||
const jobSelection = MachineLearningJobSelectionProvider(context);
|
||||
const jobSourceSelection = MachineLearningJobSourceSelectionProvider(context);
|
||||
const jobTable = MachineLearningJobTableProvider(context);
|
||||
const jobTable = MachineLearningJobTableProvider(context, commonUI, customUrls);
|
||||
const jobTypeSelection = MachineLearningJobTypeSelectionProvider(context);
|
||||
const jobWizardAdvanced = MachineLearningJobWizardAdvancedProvider(context, commonUI);
|
||||
const jobWizardCategorization = MachineLearningJobWizardCategorizationProvider(context);
|
||||
|
|
|
@ -8,8 +8,20 @@
|
|||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { MlCommonUI } from './common_ui';
|
||||
import { MlCustomUrls } from './custom_urls';
|
||||
|
||||
export function MachineLearningJobTableProvider({ getService }: FtrProviderContext) {
|
||||
import {
|
||||
TimeRangeType,
|
||||
TIME_RANGE_TYPE,
|
||||
URL_TYPE,
|
||||
} from '../../../../plugins/ml/public/application/jobs/components/custom_url_editor/constants';
|
||||
|
||||
export function MachineLearningJobTableProvider(
|
||||
{ getService }: FtrProviderContext,
|
||||
mlCommonUI: MlCommonUI,
|
||||
customUrls: MlCustomUrls
|
||||
) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const retry = getService('retry');
|
||||
|
||||
|
@ -311,6 +323,12 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte
|
|||
await testSubjects.existOrFail('~mlPageJobWizard');
|
||||
}
|
||||
|
||||
public async clickEditJobAction(jobId: string) {
|
||||
await this.ensureJobActionsMenuOpen(jobId);
|
||||
await testSubjects.click('mlActionButtonEditJob');
|
||||
await testSubjects.existOrFail('mlJobEditFlyout');
|
||||
}
|
||||
|
||||
public async clickDeleteJobAction(jobId: string) {
|
||||
await this.ensureJobActionsMenuOpen(jobId);
|
||||
await testSubjects.click('mlActionButtonDeleteJob');
|
||||
|
@ -456,5 +474,189 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async openEditCustomUrlsForJobTab(jobId: string) {
|
||||
await this.clickEditJobAction(jobId);
|
||||
// click Custom URLs tab
|
||||
await testSubjects.click('mlEditJobFlyout-customUrls');
|
||||
await this.ensureEditCustomUrlTabOpen();
|
||||
}
|
||||
|
||||
public async ensureEditCustomUrlTabOpen() {
|
||||
await testSubjects.existOrFail('mlJobOpenCustomUrlFormButton', { timeout: 5000 });
|
||||
}
|
||||
|
||||
public async closeEditJobFlyout() {
|
||||
if (await testSubjects.exists('mlEditJobFlyoutCloseButton')) {
|
||||
await testSubjects.click('mlEditJobFlyoutCloseButton');
|
||||
await testSubjects.missingOrFail('mlJobEditFlyout');
|
||||
}
|
||||
}
|
||||
|
||||
public async saveEditJobFlyoutChanges() {
|
||||
await testSubjects.click('mlEditJobFlyoutSaveButton');
|
||||
await testSubjects.missingOrFail('mlJobEditFlyout', { timeout: 5000 });
|
||||
}
|
||||
|
||||
public async clickOpenCustomUrlEditor() {
|
||||
await this.ensureEditCustomUrlTabOpen();
|
||||
await testSubjects.click('mlJobOpenCustomUrlFormButton');
|
||||
await testSubjects.existOrFail('mlJobCustomUrlForm');
|
||||
}
|
||||
|
||||
public async addDiscoverCustomUrl(
|
||||
jobId: string,
|
||||
customUrl: {
|
||||
label: string;
|
||||
indexPattern: string;
|
||||
queryEntityFieldNames: string[];
|
||||
timeRange: TimeRangeType;
|
||||
timeRangeInterval?: string;
|
||||
}
|
||||
) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
|
||||
const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
|
||||
// Fill-in the form
|
||||
await this.clickOpenCustomUrlEditor();
|
||||
await customUrls.setCustomUrlLabel(customUrl.label);
|
||||
await mlCommonUI.selectRadioGroupValue(
|
||||
`mlJobCustomUrlLinkToTypeInput`,
|
||||
URL_TYPE.KIBANA_DISCOVER
|
||||
);
|
||||
await mlCommonUI.selectSelectValueByVisibleText(
|
||||
'mlJobCustomUrlDiscoverIndexPatternInput',
|
||||
customUrl.indexPattern
|
||||
);
|
||||
await customUrls.setCustomUrlQueryEntityFieldNames(customUrl.queryEntityFieldNames);
|
||||
await mlCommonUI.selectSelectValueByVisibleText(
|
||||
'mlJobCustomUrlTimeRangeInput',
|
||||
customUrl.timeRange
|
||||
);
|
||||
if (customUrl.timeRange === TIME_RANGE_TYPE.INTERVAL) {
|
||||
await customUrls.setCustomUrlTimeRangeInterval(customUrl.timeRangeInterval!);
|
||||
}
|
||||
|
||||
// Save custom URL
|
||||
await testSubjects.click('mlJobAddCustomUrl');
|
||||
const expectedIndex = existingCustomUrls.length;
|
||||
await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label);
|
||||
|
||||
// Save the job
|
||||
await this.saveEditJobFlyoutChanges();
|
||||
}
|
||||
|
||||
public async addDashboardCustomUrl(
|
||||
jobId: string,
|
||||
customUrl: {
|
||||
label: string;
|
||||
dashboardName: string;
|
||||
queryEntityFieldNames: string[];
|
||||
timeRange: TimeRangeType;
|
||||
timeRangeInterval?: string;
|
||||
}
|
||||
) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
|
||||
const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
|
||||
// Fill-in the form
|
||||
await this.clickOpenCustomUrlEditor();
|
||||
await customUrls.setCustomUrlLabel(customUrl.label);
|
||||
await mlCommonUI.selectRadioGroupValue(
|
||||
`mlJobCustomUrlLinkToTypeInput`,
|
||||
URL_TYPE.KIBANA_DASHBOARD
|
||||
);
|
||||
await mlCommonUI.selectSelectValueByVisibleText(
|
||||
'mlJobCustomUrlDashboardNameInput',
|
||||
customUrl.dashboardName
|
||||
);
|
||||
await customUrls.setCustomUrlQueryEntityFieldNames(customUrl.queryEntityFieldNames);
|
||||
await mlCommonUI.selectSelectValueByVisibleText(
|
||||
'mlJobCustomUrlTimeRangeInput',
|
||||
customUrl.timeRange
|
||||
);
|
||||
if (customUrl.timeRange === TIME_RANGE_TYPE.INTERVAL) {
|
||||
await customUrls.setCustomUrlTimeRangeInterval(customUrl.timeRangeInterval!);
|
||||
}
|
||||
|
||||
// Save custom URL
|
||||
await testSubjects.click('mlJobAddCustomUrl');
|
||||
const expectedIndex = existingCustomUrls.length;
|
||||
await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label);
|
||||
|
||||
// Save the job
|
||||
await this.saveEditJobFlyoutChanges();
|
||||
}
|
||||
|
||||
public async addOtherTypeCustomUrl(jobId: string, customUrl: { label: string; url: string }) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
|
||||
const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
|
||||
// Fill-in the form
|
||||
await this.clickOpenCustomUrlEditor();
|
||||
await customUrls.setCustomUrlLabel(customUrl.label);
|
||||
await mlCommonUI.selectRadioGroupValue(`mlJobCustomUrlLinkToTypeInput`, URL_TYPE.OTHER);
|
||||
await customUrls.setCustomUrlOtherTypeUrl(customUrl.url);
|
||||
|
||||
// Save custom URL
|
||||
await testSubjects.click('mlJobAddCustomUrl');
|
||||
const expectedIndex = existingCustomUrls.length;
|
||||
await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label);
|
||||
|
||||
// Save the job
|
||||
await this.saveEditJobFlyoutChanges();
|
||||
}
|
||||
|
||||
public async editCustomUrl(
|
||||
jobId: string,
|
||||
indexInList: number,
|
||||
customUrl: { label: string; url: string }
|
||||
) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
await customUrls.editCustomUrlLabel(indexInList, customUrl.label);
|
||||
await customUrls.editCustomUrlUrlValue(indexInList, customUrl.url);
|
||||
|
||||
// Save the edit
|
||||
await this.saveEditJobFlyoutChanges();
|
||||
}
|
||||
|
||||
public async deleteCustomUrl(jobId: string, indexInList: number) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
const beforeCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel');
|
||||
await customUrls.deleteCustomUrl(indexInList);
|
||||
|
||||
// Save the edit and check the custom URL has been deleted.
|
||||
await testSubjects.click('mlEditJobFlyoutSaveButton');
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
await customUrls.assertCustomUrlsLength(beforeCustomUrls.length - 1);
|
||||
await this.closeEditJobFlyout();
|
||||
}
|
||||
|
||||
public async openTestCustomUrl(jobId: string, indexInList: number) {
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
await customUrls.clickTestCustomUrl(indexInList);
|
||||
}
|
||||
|
||||
public async testDiscoverCustomUrlAction(expectedHitCountFormatted: string) {
|
||||
await customUrls.assertDiscoverCustomUrlAction(expectedHitCountFormatted);
|
||||
}
|
||||
|
||||
public async testDashboardCustomUrlAction(expectedPanelCount: number) {
|
||||
await customUrls.assertDashboardCustomUrlAction(expectedPanelCount);
|
||||
}
|
||||
|
||||
public async testOtherTypeCustomUrlAction(
|
||||
jobId: string,
|
||||
indexInList: number,
|
||||
expectedUrl: string
|
||||
) {
|
||||
// Can't test the contents of the external page, so just check the expected URL.
|
||||
await this.openEditCustomUrlsForJobTab(jobId);
|
||||
await customUrls.assertCustomUrlUrlValue(indexInList, expectedUrl);
|
||||
await this.closeEditJobFlyout();
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
|
@ -527,7 +527,7 @@ export function MachineLearningJobWizardCommonProvider(
|
|||
|
||||
const expectedIndex = existingCustomUrls.length;
|
||||
|
||||
await customUrls.assertCustomUrlItem(expectedIndex, customUrl.label);
|
||||
await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label);
|
||||
},
|
||||
|
||||
async ensureAdvancedSectionOpen() {
|
||||
|
|
|
@ -305,6 +305,10 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider
|
|||
await this.createDashboardIfNeeded(dashboards.mlTestDashboard);
|
||||
},
|
||||
|
||||
async deleteMLTestDashboard() {
|
||||
await this.deleteDashboardByTitle(dashboards.mlTestDashboard.requestBody.attributes.title);
|
||||
},
|
||||
|
||||
async createDashboardIfNeeded(dashboard: any) {
|
||||
const title = dashboard.requestBody.attributes.title;
|
||||
const dashboardId = await this.getDashboardId(title);
|
||||
|
|
Loading…
Reference in a new issue