Skip to content

Commit 18761ba

Browse files
FIO-10588: fixed an issue where logic with the result variable does not work properly on server side (#288)
1 parent bca752f commit 18761ba

3 files changed

Lines changed: 200 additions & 3 deletions

File tree

src/process/__tests__/process.test.ts

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5106,6 +5106,191 @@ describe('Process Tests', function () {
51065106
processSync(context);
51075107
expect((context.scope as ValidationScope).errors).to.have.length(1);
51085108
});
5109+
5110+
it('Should not return the error for required component with logic where result var is used', async function () {
5111+
const form = {
5112+
components: [
5113+
{
5114+
label: 'Registration number required',
5115+
applyMaskOn: 'change',
5116+
tableView: true,
5117+
case: 'uppercase',
5118+
validate: {
5119+
required: true,
5120+
maxLength: 50,
5121+
},
5122+
validateWhenHidden: false,
5123+
key: 'plateNumber2',
5124+
logic: [
5125+
{
5126+
name: 'keep letter and number',
5127+
trigger: {
5128+
type: 'javascript',
5129+
javascript: 'result=row[component.key];',
5130+
},
5131+
actions: [
5132+
{
5133+
name: 'set',
5134+
type: 'value',
5135+
value: "value=result.replace(/[^a-zA-Z0-9]/g, '');\n",
5136+
},
5137+
],
5138+
},
5139+
],
5140+
type: 'textfield',
5141+
input: true,
5142+
keyModified: true,
5143+
},
5144+
{
5145+
label: 'Submit',
5146+
showValidations: false,
5147+
tableView: false,
5148+
key: 'submit',
5149+
type: 'button',
5150+
input: true,
5151+
},
5152+
],
5153+
};
5154+
const submission = {
5155+
data: { plateNumber2: 'TEST', submit: true },
5156+
};
5157+
const context = {
5158+
form,
5159+
submission,
5160+
data: submission.data,
5161+
components: form.components,
5162+
processors: ProcessTargets.submission,
5163+
scope: {},
5164+
};
5165+
processSync(context as any);
5166+
context.processors = ProcessTargets.evaluator;
5167+
processSync(context as any);
5168+
assert.equal(context.data.plateNumber2, 'TEST');
5169+
assert.equal((context.scope as any).errors.length, 0);
5170+
});
5171+
5172+
it('Should return the value formatted by logic where result var is used', async function () {
5173+
const form = {
5174+
components: [
5175+
{
5176+
label: 'Registration number required',
5177+
applyMaskOn: 'change',
5178+
tableView: true,
5179+
case: 'uppercase',
5180+
validate: {
5181+
required: true,
5182+
maxLength: 50,
5183+
},
5184+
validateWhenHidden: false,
5185+
key: 'plateNumber2',
5186+
logic: [
5187+
{
5188+
name: 'keep letter and number',
5189+
trigger: {
5190+
type: 'javascript',
5191+
javascript: 'result=row[component.key];',
5192+
},
5193+
actions: [
5194+
{
5195+
name: 'set',
5196+
type: 'value',
5197+
value: "value=result.replace(/[^a-zA-Z0-9]/g, '');\n",
5198+
},
5199+
],
5200+
},
5201+
],
5202+
type: 'textfield',
5203+
input: true,
5204+
keyModified: true,
5205+
},
5206+
{
5207+
label: 'Submit',
5208+
showValidations: false,
5209+
tableView: false,
5210+
key: 'submit',
5211+
type: 'button',
5212+
input: true,
5213+
},
5214+
],
5215+
};
5216+
const submission = {
5217+
data: { plateNumber2: 'TEST 123 TEST', submit: true },
5218+
};
5219+
const context = {
5220+
form,
5221+
submission,
5222+
data: submission.data,
5223+
components: form.components,
5224+
processors: ProcessTargets.submission,
5225+
scope: {},
5226+
};
5227+
processSync(context as any);
5228+
context.processors = ProcessTargets.evaluator;
5229+
processSync(context as any);
5230+
assert.equal(context.data.plateNumber2, 'TEST123TEST');
5231+
assert.equal((context.scope as any).errors.length, 0);
5232+
});
5233+
5234+
it('Should return the error for required component with logic where result var is used', async function () {
5235+
const form = {
5236+
components: [
5237+
{
5238+
label: 'Registration number required',
5239+
applyMaskOn: 'change',
5240+
tableView: true,
5241+
case: 'uppercase',
5242+
validate: {
5243+
required: true,
5244+
maxLength: 50,
5245+
},
5246+
validateWhenHidden: false,
5247+
key: 'plateNumber2',
5248+
logic: [
5249+
{
5250+
name: 'keep letter and number',
5251+
trigger: {
5252+
type: 'javascript',
5253+
javascript: 'result=row[component.key];',
5254+
},
5255+
actions: [
5256+
{
5257+
name: 'set',
5258+
type: 'value',
5259+
value: "value=result.replace(/[^a-zA-Z0-9]/g, '');\n",
5260+
},
5261+
],
5262+
},
5263+
],
5264+
type: 'textfield',
5265+
input: true,
5266+
keyModified: true,
5267+
},
5268+
{
5269+
label: 'Submit',
5270+
showValidations: false,
5271+
tableView: false,
5272+
key: 'submit',
5273+
type: 'button',
5274+
input: true,
5275+
},
5276+
],
5277+
};
5278+
const submission = {
5279+
data: { plateNumber2: '', submit: true },
5280+
};
5281+
const context = {
5282+
form,
5283+
submission,
5284+
data: submission.data,
5285+
components: form.components,
5286+
processors: ProcessTargets.submission,
5287+
scope: {},
5288+
};
5289+
processSync(context as any);
5290+
context.processors = ProcessTargets.evaluator;
5291+
processSync(context as any);
5292+
assert.equal((context.scope as any).errors.length, 1);
5293+
});
51095294
});
51105295
});
51115296

src/types/process/logic/LogicContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ import { ProcessorContext } from '../ProcessorContext';
22
import { LogicScope } from './LogicScope';
33
export type LogicContext = ProcessorContext<LogicScope> & {
44
populated?: any;
5+
result?: any;
56
};

src/utils/logic.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
LogicActionPropertyString,
1616
LogicActionValue,
1717
} from 'types/AdvancedLogic';
18-
import { get, set, clone, isEqual, assign } from 'lodash';
18+
import { get, set, clone, isEqual, assign, unset } from 'lodash';
1919
import { evaluate, interpolate } from 'modules/jsonlogic';
2020
import { registerEphermalState } from './utils';
2121
import { getComponentAbsolutePath } from './formUtil';
@@ -31,6 +31,9 @@ export const hasLogic = (context: LogicContext): boolean => {
3131

3232
export const checkTrigger = (context: LogicContext, trigger: any): boolean => {
3333
let shouldTrigger: boolean | null = false;
34+
if (!trigger) {
35+
return false;
36+
}
3437
switch (trigger.type) {
3538
case 'simple':
3639
if (isLegacyConditional(trigger.simple)) {
@@ -136,6 +139,7 @@ export function setValueProperty(context: LogicContext, action: LogicActionValue
136139
const oldValue = get(data, path);
137140
const newValue = evaluate(context, action.value, 'value', (evalContext: any) => {
138141
evalContext.value = clone(oldValue);
142+
evalContext.result = context.result;
139143
});
140144
if (
141145
!isEqual(oldValue, newValue) &&
@@ -159,6 +163,7 @@ export function setMergeComponentSchema(
159163
'schema',
160164
(evalContext: any) => {
161165
evalContext.value = clone(oldValue);
166+
evalContext.result = context.result;
162167
},
163168
);
164169
const merged = assign({}, component, schema);
@@ -181,10 +186,13 @@ export const applyActions = (context: LogicContext): boolean => {
181186
}
182187
return logic.reduce((changed, logicItem) => {
183188
const { actions, trigger } = logicItem;
184-
if (!trigger || !actions || !actions.length || !checkTrigger(context, trigger)) {
189+
const result = checkTrigger(context, trigger);
190+
if (!trigger || !actions || !actions.length || !result) {
185191
return changed;
186192
}
187-
return actions.reduce((changed, action) => {
193+
// remove trigger result of current logic block to the evaluation context
194+
context.result = result;
195+
const actionsResult = actions.reduce((changed, action) => {
188196
switch (action.type) {
189197
case 'property':
190198
if (setActionProperty(context, action)) {
@@ -204,5 +212,8 @@ export const applyActions = (context: LogicContext): boolean => {
204212
return changed;
205213
}
206214
}, changed);
215+
// remove result of current logic block from context
216+
unset(context, 'result');
217+
return actionsResult;
207218
}, false);
208219
};

0 commit comments

Comments
 (0)