Skip to content

Commit

Permalink
adding error message in the connector form
Browse files Browse the repository at this point in the history
  • Loading branch information
Samiul-TheSoccerFan committed Dec 10, 2024
1 parent cbb8fb6 commit 01110f3
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ describe('ConnectorForm', () => {
let appMockRenderer: AppMockRenderer;
const onChange = jest.fn();
const onFormModifiedChange = jest.fn();
const resetErrorMessage = jest.fn();

const connector = {
actionTypeId: 'test',
Expand Down Expand Up @@ -100,7 +99,6 @@ describe('ConnectorForm', () => {
connector={connector}
onChange={onChange}
onFormModifiedChange={onFormModifiedChange}
resetErrorMessage={resetErrorMessage}
/>
);

Expand All @@ -120,8 +118,6 @@ describe('ConnectorForm', () => {
preSubmitValidator: expect.anything(),
submit: expect.anything(),
});

expect(resetErrorMessage).not.toHaveBeenCalled();
});

it('registers the pre submit validator correctly', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ interface Props {
/** Handler to receive update on the form "isModified" state */
onFormModifiedChange?: (isModified: boolean) => void;
setResetForm?: (value: ResetForm) => void;
resetErrorMessage?: () => void;
}
/**
* The serializer and deserializer are needed to transform the headers of
Expand Down Expand Up @@ -114,7 +113,6 @@ const ConnectorFormComponent: React.FC<Props> = ({
onChange,
onFormModifiedChange,
setResetForm,
resetErrorMessage,
}) => {
const { form } = useForm({
defaultValue: connector,
Expand All @@ -138,19 +136,8 @@ const ConnectorFormComponent: React.FC<Props> = ({
useEffect(() => {
if (onChange) {
onChange({ isValid: isFormValid, isSubmitted, isSubmitting, submit, preSubmitValidator });
if (isFormValid) {
resetErrorMessage?.();
}
}
}, [
onChange,
isFormValid,
isSubmitted,
isSubmitting,
submit,
preSubmitValidator,
resetErrorMessage,
]);
}, [onChange, isFormValid, isSubmitted, isSubmitting, submit, preSubmitValidator]);

useEffect(() => {
if (onFormModifiedChange) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, { lazy } from 'react';

import { actionTypeRegistryMock } from '../../../action_type_registry.mock';
import userEvent from '@testing-library/user-event';
import { waitFor, act } from '@testing-library/react';
import { waitFor, act, screen } from '@testing-library/react';
import CreateConnectorFlyout from '.';
import { AppMockRenderer, createAppMockRenderer } from '../../test_utils';
import { TECH_PREVIEW_LABEL } from '../../translations';
Expand Down Expand Up @@ -469,35 +469,68 @@ describe('CreateConnectorFlyout', () => {
name: 'My test',
secrets: {},
});
expect(queryByTestId('required-field-error-label')).not.toBeInTheDocument();
expect(queryByTestId('connector-form-header-error-label')).not.toBeInTheDocument();
});

it('show Required all fields message', async () => {
const { getByTestId } = appMockRenderer.render(
it('show error message in the form header', async () => {
appMockRenderer.render(
<CreateConnectorFlyout
actionTypeRegistry={actionTypeRegistry}
onClose={onClose}
onConnectorCreated={onConnectorCreated}
onTestConnector={onTestConnector}
/>
);
await act(() => Promise.resolve());

await userEvent.click(getByTestId(`${actionTypeModel.id}-card`));
await userEvent.click(await screen.findByTestId(`${actionTypeModel.id}-card`));
expect(await screen.findByTestId('test-connector-text-field')).toBeInTheDocument();

await waitFor(() => {
expect(getByTestId('test-connector-text-field')).toBeInTheDocument();
});
await userEvent.type(
await screen.findByTestId('test-connector-text-field'),
'My text field',
{
delay: 100,
}
);

await userEvent.type(getByTestId('test-connector-text-field'), 'My text field', {
delay: 100,
});
await userEvent.click(await screen.findByTestId('create-connector-flyout-save-btn'));
expect(onClose).not.toHaveBeenCalled();
expect(onConnectorCreated).not.toHaveBeenCalled();
expect(await screen.findByTestId('connector-form-header-error-label')).toBeInTheDocument();
});

await userEvent.click(getByTestId('create-connector-flyout-save-btn'));
it('removes error message from the form header', async () => {
appMockRenderer.render(
<CreateConnectorFlyout
actionTypeRegistry={actionTypeRegistry}
onClose={onClose}
onConnectorCreated={onConnectorCreated}
onTestConnector={onTestConnector}
/>
);

await userEvent.click(await screen.findByTestId(`${actionTypeModel.id}-card`));
expect(await screen.findByTestId('test-connector-text-field')).toBeInTheDocument();

await userEvent.type(
await screen.findByTestId('test-connector-text-field'),
'My text field',
{
delay: 100,
}
);

await userEvent.click(await screen.findByTestId('create-connector-flyout-save-btn'));
expect(onClose).not.toHaveBeenCalled();
expect(onConnectorCreated).not.toHaveBeenCalled();
expect(getByTestId('required-field-error-label')).toBeInTheDocument();
expect(await screen.findByTestId('connector-form-header-error-label')).toBeInTheDocument();

await userEvent.type(await screen.findByTestId('nameInput'), 'My test', {
delay: 100,
});

await userEvent.click(await screen.findByTestId('create-connector-flyout-save-btn'));
expect(screen.queryByTestId('connector-form-header-error-label')).not.toBeInTheDocument();
});

it('runs pre submit validator correctly', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({
const [actionType, setActionType] = useState<ActionType | null>(null);
const [hasActionsUpgradeableByTrial, setHasActionsUpgradeableByTrial] = useState<boolean>(false);
const canSave = hasSaveActionsCapability(capabilities);
const [isRequiredFieldError, setIsRequiredFieldError] = useState<boolean>(false);

const [preSubmitValidationErrorMessage, setPreSubmitValidationErrorMessage] =
useState<ReactNode>(null);
Expand Down Expand Up @@ -109,7 +108,6 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({

const setResetForm = (reset: ResetForm) => {
resetConnectorForm.current = reset;
setIsRequiredFieldError(false);
};

const onChangeGroupAction = (id: string) => {
Expand All @@ -129,11 +127,6 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({
}
};

// Hide All fields required error message
const resetRequiredFieldsErrorMessage = useCallback(() => {
setIsRequiredFieldError(false);
}, []);

const validateAndCreateConnector = useCallback(async () => {
setPreSubmitValidationErrorMessage(null);

Expand Down Expand Up @@ -168,11 +161,6 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({

const createdConnector = await createConnector(validConnector);
return createdConnector;
} else {
if (Object.keys(data).length === 0) {
setIsRequiredFieldError(true);
}
return;
}
}, [submit, preSubmitValidator, createConnector]);

Expand Down Expand Up @@ -242,17 +230,17 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({
<EuiSpacer size="xs" />
</>
)}
{isRequiredFieldError && (
{!!hasErrors && (
<>
<EuiCallOut
size="s"
color="danger"
iconType="warning"
data-test-subj="required-field-error-label"
data-test-subj="connector-form-header-error-label"
title={i18n.translate(
'xpack.triggersActionsUI.sections.actionConnectorAdd.requiredFieldError',
'xpack.triggersActionsUI.sections.actionConnectorAdd.headerFormLabel',
{
defaultMessage: 'All fields are required',
defaultMessage: 'There are errors in the form',
}
)}
/>
Expand All @@ -265,7 +253,6 @@ const CreateConnectorFlyoutComponent: React.FC<CreateConnectorFlyoutProps> = ({
isEdit={false}
onChange={setFormState}
setResetForm={setResetForm}
resetErrorMessage={resetRequiredFieldsErrorMessage}
/>
{!!preSubmitValidationErrorMessage && <p>{preSubmitValidationErrorMessage}</p>}
<EuiFlexItem grow={false}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, { lazy } from 'react';

import { actionTypeRegistryMock } from '../../../action_type_registry.mock';
import userEvent from '@testing-library/user-event';
import { waitFor, act } from '@testing-library/react';
import { waitFor, act, screen } from '@testing-library/react';
import EditConnectorFlyout from '.';
import { ActionConnector, EditConnectorTabs, GenericValidationResult } from '../../../../types';
import { AppMockRenderer, createAppMockRenderer } from '../../test_utils';
Expand Down Expand Up @@ -415,7 +415,7 @@ describe('EditConnectorFlyout', () => {

describe('Submitting', () => {
it('updates the connector correctly', async () => {
const { getByTestId } = appMockRenderer.render(
const { getByTestId, queryByTestId } = appMockRenderer.render(
<EditConnectorFlyout
actionTypeRegistry={actionTypeRegistry}
onClose={onClose}
Expand Down Expand Up @@ -459,6 +459,7 @@ describe('EditConnectorFlyout', () => {
name: 'My test',
secrets: {},
});
expect(queryByTestId('connector-form-header-error-label')).not.toBeInTheDocument();
});

it('updates connector form field with latest value', async () => {
Expand Down Expand Up @@ -555,6 +556,39 @@ describe('EditConnectorFlyout', () => {
});
});

it('show error message in the form header', async () => {
appMockRenderer.render(
<EditConnectorFlyout
actionTypeRegistry={actionTypeRegistry}
onClose={onClose}
connector={connector}
onConnectorUpdated={onConnectorUpdated}
/>
);

expect(await screen.findByTestId('test-connector-text-field')).toBeInTheDocument();
await userEvent.clear(screen.getByTestId('nameInput'));
await userEvent.click(screen.getByTestId('edit-connector-flyout-save-btn'));
expect(await screen.findByTestId('connector-form-header-error-label')).toBeInTheDocument();
});

it('removes error message from the form header', async () => {
appMockRenderer.render(
<EditConnectorFlyout
actionTypeRegistry={actionTypeRegistry}
onClose={onClose}
connector={connector}
onConnectorUpdated={onConnectorUpdated}
/>
);

await userEvent.clear(screen.getByTestId('nameInput'));
await userEvent.type(screen.getByTestId('nameInput'), 'My new name');
await userEvent.type(screen.getByTestId('test-connector-secret-text-field'), 'password');
await userEvent.click(screen.getByTestId('edit-connector-flyout-save-btn'));
expect(screen.queryByTestId('connector-form-header-error-label')).not.toBeInTheDocument();
});

it('runs pre submit validator correctly', async () => {
const errorActionTypeModel = actionTypeRegistryMock.createMockActionTypeModel({
actionConnectorFields: lazy(() => import('../connector_error_mock')),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
*/

import React, { memo, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { EuiFlyout, EuiFlyoutBody, EuiButton, EuiConfirmModal } from '@elastic/eui';
import {
EuiFlyout,
EuiFlyoutBody,
EuiButton,
EuiConfirmModal,
EuiCallOut,
EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { ActionTypeExecutorResult, isActionTypeExecutorResult } from '@kbn/actions-plugin/common';
Expand Down Expand Up @@ -218,6 +225,23 @@ const EditConnectorFlyoutComponent: React.FC<EditConnectorFlyoutProps> = ({
<>
{isEdit && (
<>
{!!hasErrors && (
<>
<EuiCallOut
size="s"
color="danger"
iconType="warning"
data-test-subj="connector-form-header-error-label"
title={i18n.translate(
'xpack.triggersActionsUI.sections.editConnectorForm.headerFormLabel',
{
defaultMessage: 'There are errors in the form',
}
)}
/>
<EuiSpacer size="m" />
</>
)}
<ConnectorForm
actionTypeModel={actionTypeModel}
connector={getConnectorWithoutSecrets(connector)}
Expand Down

0 comments on commit 01110f3

Please sign in to comment.