diff --git a/test/functional/services/common/find.ts b/test/functional/services/common/find.ts index 0b405d20c4db33..682c79047a7253 100644 --- a/test/functional/services/common/find.ts +++ b/test/functional/services/common/find.ts @@ -307,6 +307,16 @@ export class FindService extends FtrService { }, timeout); } + public async existsByXpath( + selector: string, + timeout: number = this.WAIT_FOR_EXISTS_TIME + ): Promise { + this.log.debug(`Find.existsByXpath('${selector}') with timeout=${timeout}`); + return await this.exists(async (drive) => { + return this.wrapAll(await drive.findElements(By.xpath(selector))); + }, timeout); + } + public async clickByCssSelectorWhenNotDisabled(selector: string, opts?: TimeoutOpt) { const timeout = opts?.timeout ?? this.defaultFindTimeout; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index f5245cd85fb533..bf2a144921d9c4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -25,6 +25,7 @@ import { RuleActionFrequency, RuleActionParam, } from '@kbn/alerting-plugin/common'; +import { v4 as uuidv4 } from 'uuid'; import { betaBadgeProps } from './beta_badge_props'; import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api'; import { @@ -242,6 +243,7 @@ export const ActionForm = ({ group: defaultActionGroupId, params: {}, frequency: defaultRuleFrequency, + uuid: uuidv4(), }); setActionIdByIndex(actionTypeConnectors[0].id, actions.length - 1); } else { @@ -255,6 +257,7 @@ export const ActionForm = ({ group: defaultActionGroupId, params: {}, frequency: DEFAULT_FREQUENCY, + uuid: uuidv4(), }); setActionIdByIndex(actionTypeConnectors[0].id, actions.length - 1); } @@ -427,7 +430,7 @@ export const ActionForm = ({ actionItem={actionItem} actionConnector={actionConnector} index={index} - key={`action-form-action-at-${index}`} + key={`action-form-action-at-${actionItem.uuid}`} setActionParamsProperty={setActionParamsProperty} setActionFrequencyProperty={setActionFrequencyProperty} setActionAlertsFilterProperty={setActionAlertsFilterProperty} diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index 273c39adbf4314..e475e8e6464505 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -85,6 +85,41 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('rulesTab'); }); + it('should delete the right action when the same action has been added twice', async () => { + // create a new rule + const ruleName = generateUniqueKey(); + await rules.common.defineIndexThresholdAlert(ruleName); + + // create webhook connector + await testSubjects.click('.webhook-alerting-ActionTypeSelectOption'); + await testSubjects.click('createActionConnectorButton-0'); + await testSubjects.setValue('nameInput', 'webhook-test'); + await testSubjects.setValue('webhookUrlText', 'https://test.test'); + await testSubjects.setValue('webhookUserInput', 'fakeuser'); + await testSubjects.setValue('webhookPasswordInput', 'fakepassword'); + + // save rule + await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); + await find.setValueByClass('kibanaCodeEditor', 'myUniqueKey'); + await testSubjects.click('saveRuleButton'); + + // add new action and remove first one + await testSubjects.click('ruleSidebarEditAction'); + await testSubjects.click('.webhook-alerting-ActionTypeSelectOption'); + await find.clickByCssSelector( + '[data-test-subj="alertActionAccordion-0"] [aria-label="Delete"]' + ); + + // check that the removed action is the right one + const doesExist = await find.existsByXpath(".//*[text()='myUniqueKey']"); + expect(doesExist).to.eql(false); + + // clean up created alert + const alertsToDelete = await getAlertsByName(ruleName); + await deleteAlerts(alertsToDelete.map((rule: { id: string }) => rule.id)); + expect(true).to.eql(true); + }); + it('should create an alert', async () => { const alertName = generateUniqueKey(); await rules.common.defineIndexThresholdAlert(alertName);