Skip to content

Commit

Permalink
Refactor email input handling to format comma-separated addresses (#1…
Browse files Browse the repository at this point in the history
…93128)

## Summary
This pull request fixes #189968 

- Introduced `getFormattedEmailOptions` to split and trim
comma-separated email values
- Updated `EuiComboBox` to handle email entries for `to`, `cc`, and
`bcc` fields


https://github.com/user-attachments/assets/45a70132-8fd7-426e-81cf-62a6bf216408

---------

Signed-off-by: Oyelola Victoria <oyelolaabimbola23@gmail.com>
Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 2, 2024
1 parent 574af41 commit 9174588
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { render, fireEvent, screen } from '@testing-library/react';
import { render, fireEvent, screen, within } from '@testing-library/react';
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks';
import EmailParamsFields from './email_params';
import { getIsExperimentalFeatureEnabled } from '../../common/get_experimental_features';
import { getFormattedEmailOptions } from './email_params';

jest.mock('@kbn/kibana-react-plugin/public', () => ({
useKibana: jest.fn(),
Expand All @@ -28,6 +29,24 @@ const mockKibana = () => {
});
};

const emailTestCases = [
{
field: 'to',
fieldValue: 'new1@test.com, new2@test.com , new1@test.com, ',
expected: ['test@test.com', 'new1@test.com', 'new2@test.com'],
},
{
field: 'cc',
fieldValue: 'newcc1@test.com, newcc2@test.com , newcc1@test.com, ',
expected: ['cc@test.com', 'newcc1@test.com', 'newcc2@test.com'],
},
{
field: 'bcc',
fieldValue: 'newbcc1@test.com, newbcc2@test.com , newbcc1@test.com, ',
expected: ['bcc@test.com', 'newbcc1@test.com', 'newbcc2@test.com'],
},
];

describe('EmailParamsFields renders', () => {
beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -62,6 +81,40 @@ describe('EmailParamsFields renders', () => {
expect(await screen.findByTestId('messageTextArea')).toBeVisible();
});

emailTestCases.forEach(({ field, fieldValue, expected }) => {
test(`"${field}" field value updates correctly when comma-separated emails are pasted`, async () => {
const actionParams = {
cc: ['cc@test.com'],
bcc: ['bcc@test.com'],
to: ['test@test.com'],
subject: 'test',
message: 'test message',
};

const editAction = jest.fn();

render(
<IntlProvider locale="en">
<EmailParamsFields
actionParams={actionParams}
errors={{ to: [], cc: [], bcc: [], subject: [], message: [] }}
editAction={editAction}
defaultMessage={'Some default message'}
index={0}
/>
</IntlProvider>
);

const euiComboBox = screen.getByTestId(`${field}EmailAddressInput`);
const input = within(euiComboBox).getByTestId('comboBoxSearchInput');
fireEvent.change(input, { target: { value: fieldValue } });
expect(input).toHaveValue(fieldValue);

fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
expect(editAction).toHaveBeenCalledWith(field, expected, 0);
});
});

test('message param field is rendered with default value if not set', () => {
const actionParams = {
cc: [],
Expand Down Expand Up @@ -234,3 +287,48 @@ describe('EmailParamsFields renders', () => {
expect(editAction).not.toHaveBeenCalled();
});
});

describe('getFormattedEmailOptions', () => {
test('should return new options added to previous options', () => {
const searchValue = 'test@test.com, other@test.com';
const previousOptions = [{ label: 'existing@test.com' }];
const newOptions = getFormattedEmailOptions(searchValue, previousOptions);

expect(newOptions).toEqual([
{ label: 'existing@test.com' },
{ label: 'test@test.com' },
{ label: 'other@test.com' },
]);
});

test('should trim extra spaces in search value', () => {
const searchValue = ' test@test.com , other@test.com , ';
const previousOptions: Array<{ label: string }> = [];
const newOptions = getFormattedEmailOptions(searchValue, previousOptions);

expect(newOptions).toEqual([{ label: 'test@test.com' }, { label: 'other@test.com' }]);
});

test('should prevent duplicate email addresses', () => {
const searchValue = 'duplicate@test.com, duplicate@test.com';
const previousOptions = [{ label: 'existing@test.com' }, { label: 'duplicate@test.com' }];
const newOptions = getFormattedEmailOptions(searchValue, previousOptions);

expect(newOptions).toEqual([{ label: 'existing@test.com' }, { label: 'duplicate@test.com' }]);
});

test('should return previous options if search value is empty', () => {
const searchValue = '';
const previousOptions = [{ label: 'existing@test.com' }];
const newOptions = getFormattedEmailOptions(searchValue, previousOptions);
expect(newOptions).toEqual([{ label: 'existing@test.com' }]);
});

test('should handle single email without comma', () => {
const searchValue = 'single@test.com';
const previousOptions = [{ label: 'existing@test.com' }];
const newOptions = getFormattedEmailOptions(searchValue, previousOptions);

expect(newOptions).toEqual([{ label: 'existing@test.com' }, { label: 'single@test.com' }]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ import { EmailActionParams } from '../types';

const noop = () => {};

export const getFormattedEmailOptions = (
searchValue: string,
previousOptions: Array<{ label: string }>
): Array<{ label: string }> => {
if (!searchValue.trim()) return previousOptions;
const previousEmails: string[] = previousOptions.map((option) => option.label);
const allUniqueEmails: Set<string> = new Set(previousEmails);
searchValue.split(',').forEach((email) => {
const trimmedEmail = email.trim();
if (trimmedEmail) allUniqueEmails.add(trimmedEmail);
});
const formattedOptions = Array.from(allUniqueEmails).map((email) => ({ label: email }));
return formattedOptions;
};

export const EmailParamsFields = ({
actionParams,
editAction,
Expand Down Expand Up @@ -105,7 +120,7 @@ export const EmailParamsFields = ({
data-test-subj="toEmailAddressInput"
selectedOptions={toOptions}
onCreateOption={(searchValue: string) => {
const newOptions = [...toOptions, { label: searchValue }];
const newOptions = getFormattedEmailOptions(searchValue, toOptions);
editAction(
'to',
newOptions.map((newOption) => newOption.label),
Expand Down Expand Up @@ -148,7 +163,7 @@ export const EmailParamsFields = ({
data-test-subj="ccEmailAddressInput"
selectedOptions={ccOptions}
onCreateOption={(searchValue: string) => {
const newOptions = [...ccOptions, { label: searchValue }];
const newOptions = getFormattedEmailOptions(searchValue, ccOptions);
editAction(
'cc',
newOptions.map((newOption) => newOption.label),
Expand Down Expand Up @@ -192,7 +207,7 @@ export const EmailParamsFields = ({
data-test-subj="bccEmailAddressInput"
selectedOptions={bccOptions}
onCreateOption={(searchValue: string) => {
const newOptions = [...bccOptions, { label: searchValue }];
const newOptions = getFormattedEmailOptions(searchValue, bccOptions);
editAction(
'bcc',
newOptions.map((newOption) => newOption.label),
Expand Down

0 comments on commit 9174588

Please sign in to comment.