Skip to content

Commit

Permalink
FIO-9280 updated validation of value property (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
HannaKurban authored Nov 4, 2024
1 parent 642240b commit 2278307
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { expect } from 'chai';
import { set } from 'lodash';
import { FieldError } from 'error';
import { SelectBoxesComponent } from 'types';
import {
simpleRadioField,
simpleSelectBoxes
} from './fixtures/components';
import { generateProcessorContext } from './fixtures/util';
import { validateValueProperty } from '../validateValueProperty';

describe('validateValueProperty', function () {
it('Validating a component with support for different types will return null', async function () {
const component = simpleRadioField;
const data = {
component: 'test',
};
const context = generateProcessorContext(component, data);
const result = await validateValueProperty(context);
expect(result).to.equal(null);
});

it('Validating a select boxes component with values data source will return null', async function () {
const component = simpleSelectBoxes;
const data = {
component: {
foo: false,
bar: false,
baz: false,
biz: false,
},
};
const context = generateProcessorContext(component, data);
const result = await validateValueProperty(context);
expect(result).to.equal(null);
});

it('Validating a select boxes component with url data source without options building will return null', async function () {
const component: SelectBoxesComponent = {
...simpleSelectBoxes,
dataSrc: 'url',
values: [],
data: {
url: 'http://localhost:8080/numbers',
headers: [],
},
};
const data = {component: { 'true': true }};

const context = generateProcessorContext(component, data);
const result = await validateValueProperty(context);
expect(result).to.equal(null);
});

it('Validating a select boxes component with url data source without options building will return error', async function () {
const component: SelectBoxesComponent = {
...simpleSelectBoxes,
dataSrc: 'url',
values: [],
data: {
url: 'http://localhost:8080/numbers',
headers: [],
},
};
const data = {component: { 'true': true }};

const context = generateProcessorContext(component, data);
set(context, 'instance.options.building', true);
const result = await validateValueProperty(context);
expect(result).to.be.instanceOf(FieldError);
expect(result?.errorKeyOrMessage).to.equal('invalidValueProperty');
});
});
39 changes: 12 additions & 27 deletions src/process/validation/rules/validateValueProperty.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isEmpty, isUndefined, isObject } from 'lodash';
import { FieldError } from 'error';
import { ListComponent, RuleFn, RuleFnSync, ValidationContext } from 'types';
import { ProcessorInfo } from 'types/process/ProcessorInfo';
Expand All @@ -7,58 +6,44 @@ const isValidatableListComponent = (comp: any): comp is ListComponent => {
return (
comp &&
comp.type &&
(comp.type === 'radio' || comp.type === 'selectboxes' || comp.type === 'select')
comp.type === 'selectboxes'
);
};

export const shouldValidate = (context: ValidationContext) => {
const { component, value } = context;
const { component, instance} = context;
if (!isValidatableListComponent(component)) {
return false;
}
if (component.dataSrc !== 'url') {
return false;
}
if (!value || (typeof value === 'object' && isEmpty(value))) {
return false;
}
const valueProperty = component.valueProperty;
if (!valueProperty) {
return false;
if ((instance as any)?.options?.building) {
return true;
}
return true;
return false;
};

export const validateValueProperty: RuleFn = async (context: ValidationContext) => {
return validateValuePropertySync(context);
};

export const validateValuePropertySync: RuleFnSync = (context: ValidationContext) => {
const { component, value } = context;
const { value, instance } = context;
if (!shouldValidate(context)) {
return null;
}
const error = new FieldError('invalidValueProperty', context);
// TODO: at some point in the radio component's change pipeline, object values are coerced into strings; testing for
// '[object Object]' is an ugly way to determine whether or not the ValueProperty is invalid, but it'll have to do
// for now

if (
component.inputType === 'radio' &&
(isUndefined(value) || isObject(value) || value === '[object Object]')
Object.entries(value as any).some(
([key, value]) => value && (key === '[object Object]' || key === 'true' || key === 'false'),
) ||
(instance && instance.loadedOptions?.some(option => option.invalid))
) {
return error;
}
// TODO: a cousin to the above issue, but sometimes ValueProperty will resolve to a boolean value so the keys in
// e.g. SelectBoxes components will strings coerced from booleans; again, not pretty, but good enough for now
else if (component.inputType !== 'radio') {
if (
Object.entries(value as any).some(
([key, value]) => value && (key === '[object Object]' || key === 'true' || key === 'false'),
)
) {
return error;
}
}

return null;
};

Expand Down
1 change: 1 addition & 0 deletions src/types/PassedComponentInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export type PassedComponentInstance = {
evaluate: (expression: string, additionalContext?: Record<string, any>) => any;
interpolate: (text: string, additionalContext?: Record<string, any>) => string;
shouldSkipValidation: (data?: DataObject, row?: DataObject) => boolean;
loadedOptions?: Array<{invalid: boolean, value: any, label: string}>
};

0 comments on commit 2278307

Please sign in to comment.