From bdd7fdc3f347a791e886ba2ee75dbfda21294aa2 Mon Sep 17 00:00:00 2001 From: Brendan Bond Date: Tue, 10 Sep 2024 03:08:25 -0500 Subject: [PATCH] FIO-8912 update to model types (#5800) * update normalization to utilize component model types if applicable; fix tests * update to core dependency * add tests * minor update to tests * update deps, fix tests --- .../_classes/multivalue/Multivalue.js | 15 ++++---- src/components/day/Day.js | 2 +- src/components/file/File.unit.js | 36 +++++++++++++++++++ src/components/hidden/Hidden.unit.js | 20 +++++++++++ src/utils/formUtils.js | 2 -- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/components/_classes/multivalue/Multivalue.js b/src/components/_classes/multivalue/Multivalue.js index e9022732d3..abc102d571 100644 --- a/src/components/_classes/multivalue/Multivalue.js +++ b/src/components/_classes/multivalue/Multivalue.js @@ -1,31 +1,34 @@ import Field from '../field/Field'; import _ from 'lodash'; +import { Utils } from '@formio/core'; export default class Multivalue extends Field { /** * Normalize values coming into updateValue. * @param {*} value - The value to normalize before setting. - * @param {Object} flags - Flags to use when normalizing the value. + * @param {object} flags - Flags to use when normalizing the value. * @param {*} emptyValue - The empty value for the field. * @returns {*} - The normalized value. */ normalizeValue(value, flags = {}, emptyValue = this.emptyValue) { + const underlyingValueShouldBeArray = Utils.getModelType(this.component) === 'array' || this.component.storeas === 'array' || Array.isArray(emptyValue); if (this.component.multiple) { if (Array.isArray(value)) { + if (underlyingValueShouldBeArray) { + if (value.length === 0 || !Array.isArray(value[0])) { + return [value]; + } + } if (value.length === 0) { return [emptyValue]; } - if (this.component.storeas === 'array') { - return super.normalizeValue([value], flags); - } - return super.normalizeValue(value, flags); } else { return super.normalizeValue(value == null ? [emptyValue] : [value], flags); } } else { - if (Array.isArray(value) && !Array.isArray(emptyValue)) { + if (Array.isArray(value) && !underlyingValueShouldBeArray) { if (this.component.storeas === 'string') { return super.normalizeValue(value.join(this.delimiter || ''), flags); } diff --git a/src/components/day/Day.js b/src/components/day/Day.js index 2fe50948ce..978b83d7f3 100644 --- a/src/components/day/Day.js +++ b/src/components/day/Day.js @@ -673,7 +673,7 @@ export default class DayComponent extends Field { isPartialDay(value) { if (!value) { - return false; + return true; } const [DAY, MONTH, YEAR] = this.component.dayFirst ? [0, 1, 2] : [1, 0, 2]; const values = value.split('/'); diff --git a/src/components/file/File.unit.js b/src/components/file/File.unit.js index 0affe77b13..f90b14a996 100644 --- a/src/components/file/File.unit.js +++ b/src/components/file/File.unit.js @@ -197,6 +197,42 @@ describe('File Component', () => { }).catch(done); }); + it('Should not incorrectly validate a non-multiple File component', () => { + comp1.multiple = false; + return Harness.testCreate(FileComponent, comp1).then((component) => { + assert(component.checkValidity(), 'Item should be valid'); + component.setValue([ + { + storage: 'base64', + name: 'IMG_5235-ce0abe18-5d3e-4ab4-84ca-b3e06684bc86.jpg', + url: 'data:image/jpg;base64,AAAAIGZ0eXBoZWljAAAAAG1pZjF', + size: 1159732, + type: 'image/jpeg', + originalName: 'IMG_5235.jpg', + } + ]); + assert(component.checkValidity(), 'Item should be valid'); + }); + }) + + it('Should not incorrectly validate a multiple File Component', () => { + comp1.multiple = true; + return Harness.testCreate(FileComponent, comp1).then((component) => { + assert(component.checkValidity(), 'Item should be valid'); + component.setValue([ + { + storage: 'base64', + name: 'IMG_5235-ce0abe18-5d3e-4ab4-84ca-b3e06684bc86.jpg', + url: 'data:image/jpg;base64,AAAAIGZ0eXBoZWljAAAAAG1pZjF', + size: 1159732, + type: 'image/jpeg', + originalName: 'IMG_5235.jpg', + } + ]); + assert(component.checkValidity(), 'Item should be valid'); + }); + }); + it('Should abort the correct file when user clicks the file remove button', (done) => { const cmp = _.cloneDeep(comp1); const abortedFiles = []; diff --git a/src/components/hidden/Hidden.unit.js b/src/components/hidden/Hidden.unit.js index ba3e6b7805..466f3ab528 100644 --- a/src/components/hidden/Hidden.unit.js +++ b/src/components/hidden/Hidden.unit.js @@ -1,5 +1,8 @@ + + import Harness from '../../../test/harness'; import HiddenComponent from './Hidden'; +import assert from 'power-assert'; import { comp1 @@ -9,4 +12,21 @@ describe('Hidden Component', () => { it('Should build a hidden component', () => { return Harness.testCreate(HiddenComponent, comp1); }); + + it('Should not incorrectly validate multiple when hidden component has an array value', () => { + return Harness.testCreate(HiddenComponent, comp1).then((component) => { + assert(component.checkValidity(), 'Item should be valid'); + component.setValue([ + { + key: 'foo', + value: 'bar' + }, + { + key: 'hello', + value: 'world' + } + ]); + assert(component.checkValidity(), 'Item should be valid after setting value'); + }); + }); }); diff --git a/src/utils/formUtils.js b/src/utils/formUtils.js index 30d6d1ba41..9bd0f6e7ba 100644 --- a/src/utils/formUtils.js +++ b/src/utils/formUtils.js @@ -7,7 +7,6 @@ const { getModelType, getComponentAbsolutePath, getComponentPath, - isComponentModelType, isComponentNestedDataType, componentPath, componentChildPath, @@ -58,7 +57,6 @@ export { getModelType, getComponentAbsolutePath, getComponentPath, - isComponentModelType, isComponentNestedDataType, componentPath, componentChildPath,