From b473af398430665e463809825c0aae420ac5edb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=B8egh?= Date: Fri, 8 Nov 2024 22:03:50 +0100 Subject: [PATCH] fix(Forms): ensure Field.Upload handles `required` properly in Wizard --- .../extensions/forms/Field/Upload/Upload.tsx | 37 +++--- .../Field/Upload/__tests__/Upload.test.tsx | 116 +++++++++++++++++- 2 files changed, 133 insertions(+), 20 deletions(-) diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Upload/Upload.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/Upload/Upload.tsx index 29099b27da8..f6447fb4be1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Upload/Upload.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Upload/Upload.tsx @@ -36,23 +36,24 @@ export type Props = FieldHelpProps & | 'skeleton' > -function UploadComponent(props: Props) { - const validateRequired = useCallback( - (value: UploadValue, { required, isChanged, error }) => { - const hasError = value?.some((file) => file.errorMessage) - if (hasError) { - return new FormError('Upload.errorInvalidFiles') - } - - if (required && (!isChanged || !(value.length > 0))) { - return error - } - - return undefined - }, - [] - ) +const validateRequired = ( + value: UploadValue, + { required, isChanged, error } +) => { + const hasError = value?.some((file) => file.errorMessage) + if (hasError) { + return new FormError('Upload.errorInvalidFiles') + } + const hasFiles = value?.length > 0 + if (required && ((!isChanged && !hasFiles) || !hasFiles)) { + return error + } + + return undefined +} + +function UploadComponent(props: Props) { const sharedTr = useSharedTranslation().Upload const formsTr = useFormsTranslation().Upload @@ -101,7 +102,7 @@ function UploadComponent(props: Props) { useEffect(() => { setFiles(value) - }, [handleBlur, setFiles, value]) + }, [setFiles, value]) const changeHandler = useCallback( ({ files }: { files: UploadValue }) => { @@ -116,7 +117,7 @@ function UploadComponent(props: Props) { const width = widthProp as FieldBlockWidth const fieldBlockProps: FieldBlockProps = { id, - forId: id, + forId: `${id}-input`, labelSrOnly: true, className, width, diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Upload/__tests__/Upload.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/Upload/__tests__/Upload.test.tsx index 05578348667..08603e4698e 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Upload/__tests__/Upload.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Upload/__tests__/Upload.test.tsx @@ -1,6 +1,6 @@ import React from 'react' import { fireEvent, render, waitFor, screen } from '@testing-library/react' -import { Field, Form } from '../../..' +import { Field, Form, Wizard } from '../../..' import { BYTES_IN_A_MEGA_BYTE } from '../../../../../components/upload/UploadVerify' import { createMockFile } from '../../../../../components/upload/__tests__/testHelpers' @@ -74,7 +74,6 @@ describe('Field.Upload', () => { it('should render files given in data context', () => { render( console.log('onChange', data)} data={{ myFiles: [ { file: createMockFile('fileName-1.png', 100, 'image/png') }, @@ -782,4 +781,117 @@ describe('Field.Upload', () => { ) }) }) + + describe('In Wizard', () => { + const previousButton = () => { + return document.querySelector('.dnb-forms-previous-button') + } + const nextButton = () => { + return document.querySelector('.dnb-forms-next-button') + } + const output = () => { + return document.querySelector('output') + } + + it('should keep files between steps', async () => { + const onStepChange = jest.fn() + + render( + + + + Step 1 + + + + + + Step 2 + + + + + ) + + const element = getRootElement() + const file = createMockFile('fileName-1.png', 100, 'image/png') + + await waitFor(() => + fireEvent.drop(element, { + dataTransfer: { + files: [file], + }, + }) + ) + + expect(output()).toHaveTextContent('Step 1') + + await userEvent.click(nextButton()) + expect(output()).toHaveTextContent('Step 2') + + await userEvent.click(previousButton()) + expect(output()).toHaveTextContent('Step 1') + + await userEvent.click(nextButton()) + expect(output()).toHaveTextContent('Step 2') + }) + + it('should show required error when "required" is set', async () => { + const onStepChange = jest.fn() + + render( + + + + Step 1 + + + + + + Step 2 + + + + + ) + + const element = getRootElement() + const file = createMockFile('fileName-1.png', 100, 'image/png') + + await waitFor(() => + fireEvent.drop(element, { + dataTransfer: { + files: [file], + }, + }) + ) + + expect(output()).toHaveTextContent('Step 1') + + await userEvent.click(nextButton()) + expect(output()).toHaveTextContent('Step 2') + + await userEvent.click(previousButton()) + expect(output()).toHaveTextContent('Step 1') + + expect( + document.querySelector('.dnb-form-status') + ).not.toBeInTheDocument() + + const deleteButton = screen.queryByRole('button', { + name: nbShared.Upload.deleteButton, + }) + + await userEvent.click(deleteButton) + await userEvent.click(nextButton()) + + expect(output()).toHaveTextContent('Step 1') + expect( + document.querySelector( + '.dnb-forms-field-block__status .dnb-form-status' + ) + ).toHaveTextContent(nbForms.Upload.errorRequired) + }) + }) })