Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AO] - Add functional tests for the new Rules page #129349

Merged
merged 34 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ba4a1d6
WIP
fkanout Apr 4, 2022
01170a1
Add permissions tests
fkanout Apr 4, 2022
7544337
Clean up
fkanout Apr 4, 2022
b53c055
Clean up
fkanout Apr 4, 2022
261bb50
Add create rule flyout test
fkanout Apr 4, 2022
edfbfba
Add rule creating and check rules table
fkanout Apr 6, 2022
b86f24a
Update wording
fkanout Apr 6, 2022
8da061a
Enable tests
fkanout Apr 6, 2022
f584667
Add rules table tests
fkanout Apr 11, 2022
7cd098e
Merge branch 'main' into new-o11y-rules-page-functional-tests
fkanout Apr 11, 2022
d967595
disable "only"
fkanout Apr 11, 2022
35baf49
Merge branch 'main' into new-o11y-rules-page-functional-tests
fkanout Apr 12, 2022
cb5d3f1
Merge branch 'main' into new-o11y-rules-page-functional-tests
kibanamachine Apr 12, 2022
86de56b
Add enabled/disabled test case
fkanout Apr 12, 2022
d2b3bd0
fix style
fkanout Apr 12, 2022
33cc1d6
Merge branch 'main' into new-o11y-rules-page-functional-tests
fkanout Apr 12, 2022
204718b
Fix failed test
fkanout Apr 13, 2022
120e9cc
Code review
fkanout Apr 19, 2022
b3a8be9
Update permission
fkanout Apr 19, 2022
fd6adf6
Remove unwanted file
fkanout Apr 19, 2022
986e656
Merge branch 'main' into new-o11y-rules-page-functional-tests
kibanamachine Apr 19, 2022
b71f30b
Update rule_add.tsx
fkanout Apr 29, 2022
d6572c8
Update rules_page.ts
fkanout Apr 29, 2022
62ea3b5
Update to fix conflicts
fkanout May 10, 2022
6c2c5ce
Merge branch 'main' into new-o11y-rules-page-functional-tests
fkanout May 10, 2022
4eb22a1
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine May 10, 2022
08ae944
Fix tests
fkanout May 10, 2022
c4db139
Fix failing tests
fkanout May 11, 2022
94992f5
Use and the data test subj for ui triggersAction UI
fkanout May 11, 2022
dee22e1
remove unsed service
fkanout May 11, 2022
bbb4198
Merge branch 'main' into new-o11y-rules-page-functional-tests
kibanamachine May 12, 2022
6532a14
Merge branch 'main' into new-o11y-rules-page-functional-tests
kibanamachine May 16, 2022
89ad376
Code review
fkanout May 17, 2022
9fb6aa5
Merge branch 'main' into new-o11y-rules-page-functional-tests
kibanamachine May 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export const renderRuleStats = (
snoozedStatsComponent,
errorStatsComponent,
<Divider />,
<EuiButtonEmpty href={manageRulesHref}>
<EuiButtonEmpty data-test-subj="manageRulesPageButton" href={manageRulesHref}>
{i18n.translate('xpack.observability.alerts.manageRulesButtonLabel', {
defaultMessage: 'Manage Rules',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function NoPermissionPrompt() {
return (
<EuiPageTemplate
template="centeredContent"
data-test-subj="noPermissionPrompt"
pageContentProps={{
paddingSize: 'none',
role: null, // For passing a11y tests in EUI docs only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function RulesTable({
[onPageChange, onSortChange]
);
return (
<section data-test-subj="rulesList">
<section>
<EuiSpacer size="xs" />
<>
<EuiSpacer size="xs" />
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/observability/public/pages/rules/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ function RulesPage() {
field: 'enabled',
name: STATUS_COLUMN_TITLE,
sortable: true,
'data-test-subj': 'rulesTableCell-ContextStatus',
render: (_enabled: boolean, item: RuleTableItem) => {
return triggersActionsUi.getRuleStatusDropdown({
rule: item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,13 @@ const RuleStatusMenu: React.FunctionComponent<RuleStatusMenuProps> = ({
name: ENABLED,
icon: isEnabled && !isSnoozed ? 'check' : 'empty',
onClick: enableRule,
'data-test-subj': 'statusDropdownEnabledItem',
},
{
name: DISABLED,
icon: !isEnabled ? 'check' : 'empty',
onClick: disableRule,
'data-test-subj': 'statusDropdownDisabledItem',
},
{
name: snoozeButtonTitle,
Expand Down
10 changes: 10 additions & 0 deletions x-pack/test/functional/services/observability/alerts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ export function ObservabilityAlertsCommonProvider({
);
};

const navigateToRulesPage = async () => {
return await pageObjects.common.navigateToUrlWithBrowserHistory(
'observability',
'/alerts/rules',
'?',
{ ensureCurrentUrl: false }
);
};

const navigateWithoutFilter = async () => {
return await pageObjects.common.navigateToUrlWithBrowserHistory(
'observability',
Expand Down Expand Up @@ -326,5 +335,6 @@ export function ObservabilityAlertsCommonProvider({
viewRuleDetailsLinkClick,
getAlertsFlyoutViewRuleDetailsLinkOrFail,
getRuleStatValue,
navigateToRulesPage,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@
import { ObservabilityAlertsPaginationProvider } from './pagination';
import { ObservabilityAlertsCommonProvider } from './common';
import { ObservabilityAlertsAddToCaseProvider } from './add_to_case';
import { ObservabilityAlertsRulesProvider } from './rules_page';

import { FtrProviderContext } from '../../../ftr_provider_context';

export function ObservabilityAlertsProvider(context: FtrProviderContext) {
const common = ObservabilityAlertsCommonProvider(context);
const pagination = ObservabilityAlertsPaginationProvider(context);
const addToCase = ObservabilityAlertsAddToCaseProvider(context);
const rulesPage = ObservabilityAlertsRulesProvider(context);

return {
common,
pagination,
addToCase,
rulesPage,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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';

export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');

const getManageRulesPageHref = async () => {
const manageRulesPageButton = await testSubjects.find('manageRulesPageButton');
return manageRulesPageButton.getAttribute('href');
};

const clickCreateRuleButton = async () => {
const createRuleButton = await testSubjects.find('createRuleButton');
return createRuleButton.click();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't run these tests but want to point out that in many cases when clicking to create something we need to wait for some indication that it completed. For example, there might be a loading indicator. While a test might pass without it, it can cause flakiness. Tests can also fail on Cloud if there is a bit more latency and the action doesn't complete very quickly.

You can simulate this to some extent by running the tests locally with TEST_THROTTLE_NETWORK=1 as described here https://www.elastic.co/guide/en/kibana/master/development-tests.html#_running_functional_tests

};

const clickRuleStatusDropDownMenu = async () => testSubjects.click('statusDropdown');

const clickDisableFromDropDownMenu = async () => testSubjects.click('statusDropdownDisabledItem');

return {
getManageRulesPageHref,
clickCreateRuleButton,
clickRuleStatusDropDownMenu,
clickDisableFromDropDownMenu,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';

export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
const testSubjects = getService('testSubjects');
const supertest = getService('supertest');
const find = getService('find');
const retry = getService('retry');
const RULE_ENDPOINT = '/api/alerting/rule';

async function createRule(rule: any): Promise<string> {
const ruleResponse = await supertest.post(RULE_ENDPOINT).set('kbn-xsrf', 'foo').send(rule);
expect(ruleResponse.status).to.eql(200);
return ruleResponse.body.id;
}
async function deleteRuleById(ruleId: string) {
const ruleResponse = await supertest
.delete(`${RULE_ENDPOINT}/${ruleId}`)
.set('kbn-xsrf', 'foo');
expect(ruleResponse.status).to.eql(204);
return true;
}

const getRulesList = async (tableRows: any[]) => {
const rows = [];
for (const euiTableRow of tableRows) {
const $ = await euiTableRow.parseDomContent();
rows.push({
name: $.findTestSubjects('rulesTableCell-name').find('a').text(),
enabled: $.findTestSubjects('rulesTableCell-ContextStatus').find('button').attr('title'),
});
}
return rows;
};

describe('Observability Rules page', function () {
this.tags('includeFirefox');

const observability = getService('observability');

before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts');
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await observability.alerts.common.navigateWithoutFilter();
});

after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts');
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
});

describe('Feature flag', () => {
// Related to the config inside x-pack/test/observability_functional/with_rac_write.config.ts
it('Link point to O11y Rules pages by default or when "xpack.observability.unsafe.rules.enabled: true"', async () => {
const manageRulesPageHref = await observability.alerts.rulesPage.getManageRulesPageHref();
expect(new URL(manageRulesPageHref).pathname).equal('/app/observability/alerts/rules');
});
});

describe('Create rule button', () => {
it('Show Create Rule flyout when Create Rule button is clicked', async () => {
await observability.alerts.common.navigateToRulesPage();
await retry.waitFor(
'Create Rule button is visible',
async () => await testSubjects.exists('createRuleButton')
);
await observability.alerts.rulesPage.clickCreateRuleButton();
await retry.waitFor(
'Create Rule flyout is visible',
async () => await testSubjects.exists('addRuleFlyoutTitle')
);
});
});

describe('Rules table', () => {
let uptimeRuleId: string;
let logThresholdRuleId: string;
before(async () => {
const uptimeRule = {
params: {
search: '',
numTimes: 5,
timerangeUnit: 'm',
timerangeCount: 15,
shouldCheckStatus: true,
shouldCheckAvailability: true,
availability: { range: 30, rangeUnit: 'd', threshold: '99' },
},
consumer: 'alerts',
schedule: { interval: '1m' },
tags: [],
name: 'uptime',
rule_type_id: 'xpack.uptime.alerts.monitorStatus',
notify_when: 'onActionGroupChange',
actions: [],
};
const logThresholdRule = {
params: {
timeSize: 5,
timeUnit: 'm',
count: { value: 75, comparator: 'more than' },
criteria: [{ field: 'log.level', comparator: 'equals', value: 'error' }],
},
consumer: 'alerts',
schedule: { interval: '1m' },
tags: [],
name: 'error-log',
rule_type_id: 'logs.alert.document.count',
notify_when: 'onActionGroupChange',
actions: [],
};
uptimeRuleId = await createRule(uptimeRule);
logThresholdRuleId = await createRule(logThresholdRule);
await observability.alerts.common.navigateToRulesPage();
});
after(async () => {
await deleteRuleById(uptimeRuleId);
await deleteRuleById(logThresholdRuleId);
});

it('shows the rules table ', async () => {
await testSubjects.existOrFail('rulesList');
await testSubjects.waitForDeleted('centerJustifiedSpinner');
const tableRows = await find.allByCssSelector('.euiTableRow');
const rows = await getRulesList(tableRows);
expect(rows.length).to.be(2);
expect(rows[0].name).to.be('error-log');
expect(rows[0].enabled).to.be('Enabled');
expect(rows[1].name).to.be('uptime');
expect(rows[1].enabled).to.be('Enabled');
});

it('changes the rule status to "disabled"', async () => {
await testSubjects.existOrFail('rulesList');
await observability.alerts.rulesPage.clickRuleStatusDropDownMenu();
await observability.alerts.rulesPage.clickDisableFromDropDownMenu();
await retry.waitFor('The rule to be disabled', async () => {
const tableRows = await find.allByCssSelector('.euiTableRow');
const rows = await getRulesList(tableRows);
expect(rows[0].enabled).to.be('Disabled');
return true;
});
});
});

describe('User permissions', () => {
it('shows the Create Rule button when user has permissions', async () => {
await observability.alerts.common.navigateToRulesPage();
await retry.waitFor(
'Create rule button',
async () => await testSubjects.exists('createRuleButton')
);
});

it(`shows the no permission prompt when the user has no permissions`, async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
logs: ['read'],
})
);
await observability.alerts.common.navigateToRulesPage();
await retry.waitFor(
'No permissions prompt',
async () => await testSubjects.exists('noPermissionPrompt')
);
});
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./alerts/table_storage'));
loadTestFile(require.resolve('./exploratory_view'));
loadTestFile(require.resolve('./feature_controls'));
loadTestFile(require.resolve('./alerts/rules_page'));
});
}