mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[SLO] Write functional tests for slo embeddables (#182568)
Fixes https://github.com/elastic/kibana/issues/182637 ## Summary This PR introduces our first functional tests for the SLO Overview Embeddable with a bunch of helper functions to interact with the different UI elements. Here are the basic scenarios that have been covered: - Add a single SLO Overview panel - Verify the configuration flyout opens - Verify the SLO selection dropdown exists - Verify the Save button is enabled - Verify an SLO Overview panel is added - Verify the title is present - Add a group SLO Overview panel - Verify the overview mode selector exists and opens the group configuration screen - Verify the Group by dropdown exists - Verify the Group dropdown exists - Verify the KQL bar exists - Verify an SLO Group Overview panel is added Here's a list of scenarios that need to be covered in a follow up PR (I will create a separate ticket with following acceptance criteria): - Check that clicking on the SLO card item opens the SLO details flyout - Check that clicking on the group expands the accordion and shows the respective SLOs - Check that `Edit criteria` link exists in the Group embeddable - Interact with edit criteria link - Check that selected group by is shown - Check that selected group is shown - Check that custom filter is shown in the kql bar - With Remote enabled ## How to test ``` node scripts/functional_tests_server.js --config x-pack/test/functional/apps/slo/embeddables/config.ts node scripts/functional_test_runner --config=x-pack/test/functional/apps/slo/embeddables/config.ts ```
This commit is contained in:
parent
8c20433bd0
commit
7536b91e33
11 changed files with 280 additions and 8 deletions
|
@ -321,6 +321,7 @@ enabled:
|
|||
- x-pack/test/functional/apps/saved_objects_management/config.ts
|
||||
- x-pack/test/functional/apps/saved_query_management/config.ts
|
||||
- x-pack/test/functional/apps/security/config.ts
|
||||
- x-pack/test/functional/apps/slo/embeddables/config.ts
|
||||
- x-pack/test/functional/apps/snapshot_restore/config.ts
|
||||
- x-pack/test/functional/apps/spaces/config.ts
|
||||
- x-pack/test/functional/apps/spaces/in_solution_navigation/config.ts
|
||||
|
|
|
@ -171,7 +171,7 @@ export function SloGroupFilters({ selectedFilters, onSelected }: Props) {
|
|||
>
|
||||
<EuiSelect
|
||||
fullWidth
|
||||
data-test-subj="o11ySloGroupConfigurationSelect"
|
||||
data-test-subj="sloGroupOverviewConfigurationGroupBy"
|
||||
options={groupByOptions}
|
||||
value={selectedGroupBy}
|
||||
onChange={(e) => {
|
||||
|
@ -207,7 +207,7 @@ export function SloGroupFilters({ selectedFilters, onSelected }: Props) {
|
|||
defaultMessage: 'Select a {selectedGroupByLabel}',
|
||||
values: { selectedGroupByLabel },
|
||||
})}
|
||||
data-test-subj="sloGroup"
|
||||
data-test-subj="sloGroupOverviewConfigurationGroup"
|
||||
options={groupOptions}
|
||||
selectedOptions={selectedGroupOptions}
|
||||
async
|
||||
|
@ -233,6 +233,7 @@ export function SloGroupFilters({ selectedFilters, onSelected }: Props) {
|
|||
}
|
||||
>
|
||||
<SearchBar
|
||||
dataTestSubj="sloGroupOverviewConfigurationKqlBar"
|
||||
appName={sloAppId}
|
||||
placeholder={PLACEHOLDER}
|
||||
indexPatterns={dataView ? [dataView] : []}
|
||||
|
|
|
@ -39,6 +39,7 @@ export interface OverviewModeSelectorProps {
|
|||
export function OverviewModeSelector({ value, onChange }: OverviewModeSelectorProps) {
|
||||
return (
|
||||
<EuiButtonGroup
|
||||
data-test-subj="sloOverviewModeSelector"
|
||||
isFullWidth
|
||||
legend="This is a basic group"
|
||||
options={overviewModeOptions}
|
||||
|
|
|
@ -73,7 +73,7 @@ function SingleSloConfiguration({ overviewMode, onCreate, onCancel }: SingleConf
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow>
|
||||
<EuiFlexItem data-test-subj="singleSloSelector" grow>
|
||||
<SloSelector
|
||||
singleSelection={true}
|
||||
hasError={hasError}
|
||||
|
@ -157,7 +157,7 @@ function GroupSloConfiguration({
|
|||
|
||||
return (
|
||||
<>
|
||||
<EuiFlyoutBody className="sloOverviewEmbeddable">
|
||||
<EuiFlyoutBody data-test-subj="sloGroupOverviewConfiguration">
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
|
@ -200,7 +200,7 @@ export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfig
|
|||
);
|
||||
|
||||
return (
|
||||
<EuiFlyout onClose={onCancel}>
|
||||
<EuiFlyout data-test-subj="sloSingleOverviewConfiguration" onClose={onCancel}>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem>
|
||||
|
|
|
@ -138,6 +138,7 @@ export const getOverviewEmbeddableFactory = (deps: SloEmbeddableDeps) => {
|
|||
return (
|
||||
<Wrapper>
|
||||
<EuiFlexGroup
|
||||
data-test-subj="sloGroupOverviewPanel"
|
||||
data-shared-item=""
|
||||
justifyContent="flexEnd"
|
||||
wrap
|
||||
|
@ -154,7 +155,7 @@ export const getOverviewEmbeddableFactory = (deps: SloEmbeddableDeps) => {
|
|||
embeddable: api,
|
||||
} as ActionExecutionContext);
|
||||
}}
|
||||
data-test-subj="o11ySloAlertsWrapperSlOsIncludedLink"
|
||||
data-test-subj="o11ySloOverviewEditCriteriaLink"
|
||||
>
|
||||
{i18n.translate('xpack.slo.overviewEmbeddable.editCriteriaLabel', {
|
||||
defaultMessage: 'Edit criteria',
|
||||
|
|
|
@ -105,7 +105,7 @@ export function SloOverview({ sloId, sloInstanceId, remoteName, reloadSubject }:
|
|||
const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value');
|
||||
|
||||
return (
|
||||
<div data-shared-item="" style={{ width: '100%' }}>
|
||||
<div data-test-subj="sloSingleOverviewPanel" data-shared-item="" style={{ width: '100%' }}>
|
||||
<SloCardChart
|
||||
slo={slo}
|
||||
historicalSliData={historicalSliData ?? []}
|
||||
|
|
17
x-pack/test/functional/apps/slo/embeddables/config.ts
Normal file
17
x-pack/test/functional/apps/slo/embeddables/config.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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 { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js'));
|
||||
|
||||
return {
|
||||
...functionalConfig.getAll(),
|
||||
testFiles: [require.resolve('./overview_embeddable')],
|
||||
};
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { cleanup } from '@kbn/infra-forge';
|
||||
import { loadTestData } from '../../../../api_integration/apis/slos/helper/load_test_data';
|
||||
import { SloEsClient } from '../../../../api_integration/apis/slos/helper/es';
|
||||
import { sloData } from '../../../../api_integration/apis/slos/fixtures/create_slo';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const PageObjects = getPageObjects(['common', 'dashboard']);
|
||||
const esClient = getService('es');
|
||||
const sloEsClient = new SloEsClient(esClient);
|
||||
const logger = getService('log');
|
||||
const slo = getService('slo');
|
||||
const sloUi = getService('sloUi');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
|
||||
describe('overview embeddable', function () {
|
||||
before(async () => {
|
||||
await loadTestData(getService);
|
||||
await slo.deleteAllSLOs();
|
||||
await slo.create(sloData);
|
||||
await PageObjects.dashboard.navigateToApp();
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
await cleanup({ esClient, logger });
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
});
|
||||
|
||||
describe('Single SLO', function () {
|
||||
it('should open SLO configuration flyout', async () => {
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickEmbeddableFactoryGroupButton('slos');
|
||||
await dashboardAddPanel.clickAddNewPanelFromUIActionLink('SLO Overview');
|
||||
await sloUi.common.assertSloOverviewConfigurationExists();
|
||||
});
|
||||
|
||||
it('should have an overview mode selector', async () => {
|
||||
await sloUi.common.assertOverviewModeSelectorExists();
|
||||
});
|
||||
|
||||
it('can select an SLO', async () => {
|
||||
await sloUi.common.assertOverviewSloSelectorExists();
|
||||
await sloUi.common.setComboBoxSloSelection();
|
||||
await sloUi.common.clickOverviewCofigurationSaveButton();
|
||||
});
|
||||
|
||||
it('creates an overview panel', async () => {
|
||||
await sloUi.common.assertSingleOverviewPanelExists();
|
||||
await sloUi.common.dismissAllToasts();
|
||||
});
|
||||
|
||||
it('renders SLO card item chart', async () => {
|
||||
await sloUi.common.assertSingleOverviewPanelContentExists();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Group of SLOs', function () {
|
||||
it('can select Group Overview mode in the Flyout configuration', async () => {
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickEmbeddableFactoryGroupButton('slos');
|
||||
await dashboardAddPanel.clickAddNewPanelFromUIActionLink('SLO Overview');
|
||||
await sloUi.common.clickOverviewMode();
|
||||
await sloUi.common.assertSloConfigurationGroupOverviewModeIsSelected();
|
||||
});
|
||||
|
||||
it('can select a group by', async () => {
|
||||
await sloUi.common.assertGroupOverviewConfigurationGroupByExists();
|
||||
});
|
||||
|
||||
it('can optionally select a group', async () => {
|
||||
await sloUi.common.assertGroupOverviewConfigurationGroupExists();
|
||||
});
|
||||
|
||||
it('can optionally search for custom query', async () => {
|
||||
await sloUi.common.assertGroupOverviewConfigurationKqlBarExists();
|
||||
});
|
||||
|
||||
it('creates a group overview panel', async () => {
|
||||
await sloUi.common.clickOverviewCofigurationSaveButton();
|
||||
await sloUi.common.assertGroupOverviewPanelExists();
|
||||
await sloUi.common.dismissAllToasts();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -69,7 +69,7 @@ import { RulesServiceProvider } from './rules';
|
|||
import { AiopsProvider } from './aiops';
|
||||
import { SampleDataServiceProvider } from './sample_data';
|
||||
import { DataStreamProvider } from './data_stream';
|
||||
|
||||
import { SloUiServiceProvider } from './slo';
|
||||
// define the name and providers for services that should be
|
||||
// available to your tests. If you don't specify anything here
|
||||
// only the built-in services will be available
|
||||
|
@ -131,4 +131,7 @@ export const services = {
|
|||
aiops: AiopsProvider,
|
||||
sampleData: SampleDataServiceProvider,
|
||||
dataStreams: DataStreamProvider,
|
||||
slo: kibanaXPackApiIntegrationServices.slo,
|
||||
dataViewApi: kibanaXPackApiIntegrationServices.dataViewApi,
|
||||
sloUi: SloUiServiceProvider,
|
||||
};
|
||||
|
|
138
x-pack/test/functional/services/slo/common.ts
Normal file
138
x-pack/test/functional/services/slo/common.ts
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { sloData } from '../../../api_integration/apis/slos/fixtures/create_slo';
|
||||
|
||||
const OVERVIEW_MODE_SELECTOR = 'sloOverviewModeSelector';
|
||||
const SLO_CONFIRM_BUTTON = 'sloConfirmButton';
|
||||
const SINGLE_SLO_SELECTOR = 'singleSloSelector';
|
||||
const SLO_SINGLE_OVERVIEW_CONFIGURATION = 'sloSingleOverviewConfiguration';
|
||||
const SLO_GROUP_OVERVIEW_CONFIGURATION = 'sloGroupOverviewConfiguration';
|
||||
const SLO_GROUP_OVERVIEW_CONFIGURATION_GROUP_BY = 'sloGroupOverviewConfigurationGroupBy';
|
||||
const SLO_GROUP_OVERVIEW_CONFIGURATION_GROUP = 'sloGroupOverviewConfigurationGroup';
|
||||
const SLO_GROUP_OVERVIEW_CONFIGURATION_KQLBAR = 'sloGroupOverviewConfigurationKqlBar';
|
||||
const SLO_SINGLE_OVERVIEW_PANEL = 'sloSingleOverviewPanel';
|
||||
const SLO_GROUP_OVERVIEW_PANEL = 'sloGroupOverviewPanel';
|
||||
|
||||
export function SloUiCommonServiceProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const comboBox = getService('comboBox');
|
||||
const find = getService('find');
|
||||
const toasts = getService('toasts');
|
||||
const retry = getService('retry');
|
||||
|
||||
return {
|
||||
async assertSloOverviewConfigurationExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_SINGLE_OVERVIEW_CONFIGURATION);
|
||||
});
|
||||
},
|
||||
async assertOverviewSloSelectorExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SINGLE_SLO_SELECTOR);
|
||||
});
|
||||
},
|
||||
async setComboBoxSloSelection() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.click('sloSelector');
|
||||
await comboBox.set('sloSelector > comboBoxInput', sloData.name);
|
||||
});
|
||||
},
|
||||
async assertOverviewConfigurationSaveButtonIsEnabled(subj: string) {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(subj);
|
||||
await testSubjects.isEnabled(subj);
|
||||
});
|
||||
},
|
||||
async clickOverviewCofigurationSaveButton() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await this.assertOverviewConfigurationSaveButtonIsEnabled(SLO_CONFIRM_BUTTON);
|
||||
await testSubjects.clickWhenNotDisabledWithoutRetry(SLO_CONFIRM_BUTTON);
|
||||
});
|
||||
},
|
||||
|
||||
async assertOverviewModeSelectorExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(OVERVIEW_MODE_SELECTOR);
|
||||
});
|
||||
},
|
||||
|
||||
async clickOverviewMode() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await this.assertOverviewModeSelectorExists();
|
||||
await testSubjects.click(OVERVIEW_MODE_SELECTOR);
|
||||
});
|
||||
},
|
||||
|
||||
async assertSloConfigurationGroupOverviewModeIsSelected() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_GROUP_OVERVIEW_CONFIGURATION);
|
||||
});
|
||||
},
|
||||
|
||||
async assertGroupOverviewConfigurationGroupByExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_GROUP_OVERVIEW_CONFIGURATION_GROUP_BY);
|
||||
});
|
||||
},
|
||||
|
||||
async assertGroupOverviewConfigurationGroupExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_GROUP_OVERVIEW_CONFIGURATION_GROUP);
|
||||
});
|
||||
},
|
||||
|
||||
async assertGroupOverviewConfigurationKqlBarExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_GROUP_OVERVIEW_CONFIGURATION_KQLBAR);
|
||||
});
|
||||
},
|
||||
|
||||
async dismissAllToasts() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await toasts.dismissAll();
|
||||
});
|
||||
},
|
||||
|
||||
async assertSingleOverviewPanelExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_SINGLE_OVERVIEW_PANEL);
|
||||
});
|
||||
},
|
||||
|
||||
async getSloCardTitle() {
|
||||
const container = await testSubjects.find(SLO_SINGLE_OVERVIEW_PANEL);
|
||||
return await (await container.findByClassName('echMetricText__title')).getVisibleText();
|
||||
},
|
||||
|
||||
async assertSingleOverviewPanelContentExists() {
|
||||
await retry.tryForTime(2000, async () => {
|
||||
expect(
|
||||
await find.existsByCssSelector(
|
||||
`[data-test-subj="${SLO_SINGLE_OVERVIEW_PANEL}"] .echChart`
|
||||
)
|
||||
).to.eql(true);
|
||||
|
||||
expect(
|
||||
await find.existsByCssSelector(
|
||||
`[data-test-subj="${SLO_SINGLE_OVERVIEW_PANEL}"] .echMetricText__title`
|
||||
)
|
||||
).to.eql(true);
|
||||
|
||||
expect(await this.getSloCardTitle()).to.eql(sloData.name);
|
||||
});
|
||||
},
|
||||
|
||||
async assertGroupOverviewPanelExists() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await testSubjects.existOrFail(SLO_GROUP_OVERVIEW_PANEL);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
15
x-pack/test/functional/services/slo/index.ts
Normal file
15
x-pack/test/functional/services/slo/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 { SloUiCommonServiceProvider } from './common';
|
||||
|
||||
export function SloUiServiceProvider(context: FtrProviderContext) {
|
||||
return {
|
||||
common: SloUiCommonServiceProvider(context),
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue