From 56a0b79459c08751a1d3e7fda2c63f4a247fe6dc Mon Sep 17 00:00:00 2001 From: Christopher Martin Date: Fri, 30 Oct 2020 19:06:34 +0000 Subject: [PATCH] [#271] only clear errors for the changed field --- src/client/backup/remote/AddBackup.tsx | 13 ++++++----- src/client/common/forms/Validation.ts | 12 ++++++++-- .../backup/remote/RemoteBackups.test.tsx | 22 +++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/client/backup/remote/AddBackup.tsx b/src/client/backup/remote/AddBackup.tsx index de3900dd..e61379c7 100644 --- a/src/client/backup/remote/AddBackup.tsx +++ b/src/client/backup/remote/AddBackup.tsx @@ -15,7 +15,7 @@ import {encrypt, EncryptResponse} from '../../gateways/SecurityGateway' import styles from './add-backup.scss' import {isHttp} from '../../domain/Url' import {RemoteLocationLogo} from './RemoteLocationLogo' -import {firstError, FormErrors} from '../../common/forms/Validation' +import {firstError, FormErrors, removeErrorFromState} from '../../common/forms/Validation' import {ErrorMessages} from '../../common/Messages' type Fields = 'url' | 'accessToken' @@ -102,12 +102,13 @@ export function AddBackup(): ReactElement { { - setValidationErrors([]) + setValidationErrors(removeErrorFromState('url')) setUrl(target.value) }} autoComplete='url' - error={firstError('url', validationErrors)} - disabled={adding}> + error={firstError('url', validationErrors)} + disabled={adding} + data-locator='url'> URL { - setValidationErrors([]) + setValidationErrors(removeErrorFromState('accessToken')) setAccessToken(target.value) }} - error={firstError('accessToken', validationErrors)} + error={firstError('accessToken', validationErrors)} disabled={adding || isCustomServer} aria-hidden={isCustomServer} data-locator='access-token'> diff --git a/src/client/common/forms/Validation.ts b/src/client/common/forms/Validation.ts index 72827302..eafe0e8f 100644 --- a/src/client/common/forms/Validation.ts +++ b/src/client/common/forms/Validation.ts @@ -1,8 +1,16 @@ -export type FormErrors = Array<{ +export type FormErrors = Array<{ readonly field: Fields; readonly message: string; }> -export function firstError(field: string, errors: Readonly>): string { +export function firstError(field: Fields, errors: Readonly>): string { return errors.find((e) => e.field === field)?.message ?? '' } + +export function removeError(field: Fields, errors: Readonly>): Readonly> { + return errors.filter((e) => e.field !== field) +} + +export function removeErrorFromState(field: Fields): (errors: Readonly>) => Readonly> { + return (errors: Readonly>) => removeError(field, errors) +} diff --git a/test/client/backup/remote/RemoteBackups.test.tsx b/test/client/backup/remote/RemoteBackups.test.tsx index 5786c82c..662424cf 100644 --- a/test/client/backup/remote/RemoteBackups.test.tsx +++ b/test/client/backup/remote/RemoteBackups.test.tsx @@ -97,3 +97,25 @@ it('should not be able to add a remote GitHub gist backup with a blank access to expect(queryByText('Please enter an access token')).toBeInTheDocument() }) }) + +it('should only clear errors for the changed field on type', async () => { + const {getByText, getByLabelText, queryByText, getByTestId} = render() + + userEvent.click(getByText('Add location')) + + userEvent.selectOptions(getByLabelText('Where'), 'github') + userEvent.clear(getByLabelText('URL')) + userEvent.click(within(getByTestId('modal')).getByText('Add location')) + + await waitFor(() => { + expect(queryByText('Please enter the URL')).toBeInTheDocument() + expect(queryByText('Please enter an access token')).toBeInTheDocument() + }) + + await userEvent.type(getByTestId('url'), 'h') + + await waitFor(() => { + expect(queryByText('Please enter the URL')).not.toBeInTheDocument() + expect(queryByText('Please enter an access token')).toBeInTheDocument() + }) +})