Skip to content

Commit

Permalink
[Cases] Fix template bugs (#187493)
Browse files Browse the repository at this point in the history
## Summary

This PR fixes the following bugs in templates:

1. Remove duplicate template tags
2. Set the connector to `none` if the connect is deleted when editing or
selecting a template

## Testing

### Scenario 1

1. Create a couple of templates with the same template tags.
2. Create a template and click to select template tags. In the list of
available template tags, you should not see duplicates.

### Scenario 2

1. Create a template with a connector.
2. Delete the connector.
3. Edit the template and verify that the `none` connector is shown.
4. Go to the create case form and select the template created in step 1.
5. The selected connector should be the `none` connector.

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
cnasikas and elasticmachine authored Jul 4, 2024
1 parent ef52a4b commit 358dece
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,90 @@
*/

import React from 'react';
import { mount } from 'enzyme';
import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { UseField, Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { screen } from '@testing-library/react';
import { ConnectorSelector } from './form';
import { connectorsMock } from '../../containers/mock';
import { getFormMock } from '../__mock__/form';
import { useKibana } from '../../common/lib/kibana';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { FormTestComponent } from '../../common/test_utils';
import { connectorsMock } from '../../containers/mock';

jest.mock('@kbn/es-ui-shared-plugin/static/forms/hook_form_lib/hooks/use_form');
jest.mock('../../common/lib/kibana');

const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>;
const useFormMock = useForm as jest.Mock;

describe('ConnectorSelector', () => {
const formHookMock = getFormMock({ connectorId: connectorsMock[0].id });
const handleChange = jest.fn();
const defaultProps = {
connectors: [],
handleChange,
dataTestSubj: 'connectors',
disabled: false,
idAria: 'connectors',
isLoading: false,
};

let appMock: AppMockRenderer;

beforeEach(() => {
appMock = createAppMockRenderer();
jest.clearAllMocks();
});

beforeEach(() => {
useFormMock.mockImplementation(() => ({ form: formHookMock }));
useKibanaMock().services.triggersActionsUi.actionTypeRegistry.get = jest.fn().mockReturnValue({
actionTypeTitle: 'test',
iconClass: 'logoSecurity',
});
});

it('it should render', async () => {
const wrapper = mount(
<Form form={formHookMock as unknown as FormHook}>
it('should render', async () => {
appMock.render(
<FormTestComponent>
<UseField
path="connectorId"
component={ConnectorSelector}
componentProps={{
...defaultProps,
}}
/>
</FormTestComponent>
);

expect(await screen.findByTestId(defaultProps.dataTestSubj));
});

it('should set the selected connector to none if the connector is not available', async () => {
appMock.render(
<FormTestComponent formDefaultValue={{ connectorId: 'foo' }}>
<UseField
path="connectorId"
component={ConnectorSelector}
componentProps={{
...defaultProps,
}}
/>
</FormTestComponent>
);

expect(await screen.findByText('No connector selected'));
});

it('should set the selected connector correctly', async () => {
appMock.render(
<FormTestComponent formDefaultValue={{ connectorId: connectorsMock[0].id }}>
<UseField
path="connectorId"
component={ConnectorSelector}
componentProps={{
...defaultProps,
connectors: connectorsMock,
dataTestSubj: 'caseConnectors',
disabled: false,
idAria: 'caseConnectors',
isLoading: false,
}}
/>
</Form>
</FormTestComponent>
);

expect(wrapper.find(`[data-test-subj="caseConnectors"]`).exists()).toBeTruthy();
expect(await screen.findByText(connectorsMock[0].name));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export const ConnectorSelector = ({
[handleChange, field]
);

const isConnectorAvailable = Boolean(
connectors.find((connector) => connector.id === field.value)
);

return (
<EuiFormRow
css={css`
Expand All @@ -66,7 +70,7 @@ export const ConnectorSelector = ({
disabled={disabled}
isLoading={isLoading}
onChange={onChange}
selectedConnector={isEmpty(field.value) ? 'none' : field.value}
selectedConnector={isEmpty(field.value) || !isConnectorAvailable ? 'none' : field.value}
/>
</EuiFormRow>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useGetChoicesResponse } from '../create/mock';
import { connectorsMock, customFieldsConfigurationMock } from '../../containers/mock';
import { TEMPLATE_FIELDS, CASE_FIELDS, CONNECTOR_FIELDS, CASE_SETTINGS } from './translations';
import { FormFields } from './form_fields';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';

jest.mock('../connectors/servicenow/use_get_choices');

Expand Down Expand Up @@ -395,4 +396,47 @@ describe('form fields', () => {
);
});
});

it('does not render duplicate template tags', async () => {
const newProps = {
...defaultProps,
currentConfiguration: {
...defaultProps.currentConfiguration,
templates: [
{
key: 'test_template_1',
name: 'Test',
tags: ['one', 'two'],
caseFields: {},
},
{
key: 'test_template_2',
name: 'Test 2',
tags: ['one', 'three'],
caseFields: {},
},
],
},
};

appMockRenderer.render(
<FormTestComponent onSubmit={onSubmit} formDefaultValue={formDefaultValue}>
<FormFields {...newProps} />
</FormTestComponent>
);

const caseTags = await screen.findByTestId('template-tags');

userEvent.click(within(caseTags).getByTestId('comboBoxToggleListButton'));
await waitForEuiPopoverOpen();

/**
* RTL will throw an error if there are more that one
* element matching the text. This ensures that duplicated
* tags are removed. Docs: https://testing-library.com/docs/queries/about
*/
expect(await screen.findByText('one'));
expect(await screen.findByText('two'));
expect(await screen.findByText('three'));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React, { memo, useMemo } from 'react';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { EuiSteps } from '@elastic/eui';
import { uniq } from 'lodash';
import { CaseFormFields } from '../case_form_fields';
import * as i18n from './translations';
import type { ActionConnector } from '../../containers/configure/types';
Expand All @@ -33,9 +34,7 @@ const FormFieldsComponent: React.FC<FormFieldsProps> = ({
}) => {
const { isSyncAlertsEnabled } = useCasesFeatures();
const { customFields: configurationCustomFields, templates } = currentConfiguration;
const configurationTemplateTags = templates
.map((template) => (template?.tags?.length ? template.tags : []))
.flat();
const configurationTemplateTags = getTemplateTags(templates);

const firstStep = useMemo(
() => ({
Expand Down Expand Up @@ -103,3 +102,6 @@ const FormFieldsComponent: React.FC<FormFieldsProps> = ({
FormFieldsComponent.displayName = 'FormFields';

export const FormFields = memo(FormFieldsComponent);

const getTemplateTags = (templates: CasesConfigurationUI['templates']) =>
uniq(templates.map((template) => (template?.tags?.length ? template.tags : [])).flat());

0 comments on commit 358dece

Please sign in to comment.