diff --git a/src/features/formData/FormData.test.tsx b/src/features/formData/FormData.test.tsx index d8d0276dcc..5bde53479c 100644 --- a/src/features/formData/FormData.test.tsx +++ b/src/features/formData/FormData.test.tsx @@ -21,6 +21,7 @@ import { RulesProvider } from 'src/features/form/rules/RulesContext'; import { GlobalFormDataReadersProvider } from 'src/features/formData/FormDataReaders'; import { FD, FormDataWriteProvider } from 'src/features/formData/FormDataWrite'; import { FormDataWriteProxyProvider } from 'src/features/formData/FormDataWriteProxies'; +import { DEFAULT_DEBOUNCE_TIMEOUT } from 'src/features/formData/types'; import { useDataModelBindings } from 'src/features/formData/useDataModelBindings'; import { fetchApplicationMetadata } from 'src/queries/queries'; import { @@ -753,4 +754,63 @@ describe('FormData', () => { expect(screen.getByTestId('valid-obj3.prop1')).toHaveValue(''); }); }); + + // Regression test for https://github.com/Altinn/app-frontend-react/issues/4053 + describe('List data model bindings regression, issue #4053', () => { + const listSchema: JSONSchema7 = { + type: 'object', + properties: { + designs: { + type: 'array', + items: { + type: 'object', + properties: { + attachmentId: { + type: 'array', + items: { type: 'string' }, + }, + }, + }, + }, + }, + }; + + function ListWriter() { + const { formData, setValue } = useDataModelBindings( + { list: { field: 'designs[0].attachmentId', dataType: defaultDataTypeMock } }, + DEFAULT_DEBOUNCE_TIMEOUT, + 'raw', + ); + const list = (formData.list ?? []) as string[]; + + return ( + <> +
{list.join(',')}
+ + + ); + } + + async function render() { + return statefulRender({ + renderer: , + queries: { + fetchDataModelSchema: async () => listSchema, + fetchFormData: async () => ({ designs: [{ attachmentId: ['id-1', 'id-2'] }] }), + }, + }); + } + + it('writing a list binding that is already pre-populated with 2+ values should not throw', async () => { + const user = userEvent.setup(); + await render(); + expect(screen.getByTestId('list-value')).toHaveTextContent('id-1,id-2'); + // This is what MaintainListDataModelBinding does on load when the order of the mapped + // attachments differs from the order stored in the data model. Before the fix this throws + // "Trying to redefine non-empty obj['attachmentId']". + await user.click(screen.getByRole('button', { name: 'Update list' })); + + await waitFor(() => expect(screen.getByTestId('list-value')).toHaveTextContent('id-2,id-1')); + }); + }); }); diff --git a/src/features/formData/FormDataWriteStateMachine.tsx b/src/features/formData/FormDataWriteStateMachine.tsx index 22a5bf11c9..1e959c8bb3 100644 --- a/src/features/formData/FormDataWriteStateMachine.tsx +++ b/src/features/formData/FormDataWriteStateMachine.tsx @@ -367,6 +367,7 @@ function makeActions( dot.str(reference.field, newValue, state.dataModels[reference.dataType].invalidCurrentData); } else { dot.delete(reference.field, state.dataModels[reference.dataType].invalidCurrentData); + dot.delete(reference.field, state.dataModels[reference.dataType].currentData); dot.str(reference.field, convertedValue, state.dataModels[reference.dataType].currentData); } return { newValue, convertedValue, error, hadError };