Skip to content

Commit c30e2ac

Browse files
committed
widgetOperation: fix previous status when path is changed
fixes #1116 When a previous status exists for a widget name, but it does not have the same path as the one of the widget being prepared, do not return the previous status. This extracts the previous status fetch to a function which does this check. Add a unit test the validates this change.
1 parent ebf92ea commit c30e2ac

File tree

2 files changed

+62
-10
lines changed

2 files changed

+62
-10
lines changed

packages/evolution-frontend/src/actions/utils/WidgetOperation.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import { checkConditional, checkChoicesConditional } from './Conditional';
1717
import { checkValidations } from './Validation';
1818
import {
1919
isInputTypeWithArrayValue,
20-
UserRuntimeInterviewAttributes
20+
UserRuntimeInterviewAttributes,
21+
WidgetStatus
2122
} from 'evolution-common/lib/services/questionnaire/types';
2223
import { CliUser } from 'chaire-lib-common/lib/services/user/userType';
2324
import { GroupConfig } from 'evolution-common/lib/services/questionnaire/types';
@@ -72,6 +73,22 @@ const prepareGroupWidgets = (
7273
}
7374
};
7475

76+
// Get the previous status for a widget
77+
const getPreviousWidgetStatus = (
78+
interview: UserRuntimeInterviewAttributes,
79+
widgetShortname: string,
80+
path: string,
81+
groupShortname?: string,
82+
parentGroupedObjectId?: string
83+
): WidgetStatus | undefined => {
84+
const previousStatusForWidget = groupShortname
85+
? parentGroupedObjectId
86+
? interview.previousGroups?.[groupShortname]?.[parentGroupedObjectId]?.[widgetShortname]
87+
: undefined
88+
: interview.previousWidgets?.[widgetShortname];
89+
return previousStatusForWidget && previousStatusForWidget.path === path ? previousStatusForWidget : undefined;
90+
};
91+
7592
const prepareSimpleWidget = (
7693
data: CurrentPreparationData,
7794
widgetData: WidgetPreparationData,
@@ -86,15 +103,13 @@ const prepareSimpleWidget = (
86103
: undefined;
87104
// get previous status:
88105
const parentGroupedObjectId = widgetData.parentGroupedObject ? widgetData.parentGroupedObject._uuid : undefined;
89-
const previousStatus = widgetData.groupShortname
90-
? data.interview.previousGroups &&
91-
data.interview.previousGroups[widgetData.groupShortname] &&
92-
data.interview.previousGroups[widgetData.groupShortname][parentGroupedObjectId]
93-
? data.interview.previousGroups[widgetData.groupShortname][parentGroupedObjectId][widgetShortname]
94-
: undefined
95-
: data.interview.previousWidgets
96-
? data.interview.previousWidgets[widgetShortname]
97-
: undefined;
106+
const previousStatus = getPreviousWidgetStatus(
107+
data.interview,
108+
widgetShortname,
109+
path,
110+
widgetData.groupShortname,
111+
parentGroupedObjectId
112+
);
98113

99114
// verify conditional visibility:
100115
const [isVisible, invisibleValue, customInvisibleValue] = checkConditional(

packages/evolution-frontend/src/actions/utils/__tests__/WidgetOperation.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,43 @@ describe('Test with previous status', () => {
382382

383383
});
384384

385+
test('Should set widget status if previous path does not match current one', () => {
386+
// Prepare test data: override previous status for widget1 with a different path
387+
const testInterviewAttributes = _cloneDeep(runtimeInterviewAttributes);
388+
const previousStatuses = _cloneDeep(previousWidgetStatuses);
389+
previousStatuses.widget1.path = 'not.the.same.path';
390+
previousStatuses.widget1.value = 'previous value of other path';
391+
testInterviewAttributes.widgets = previousStatuses;
392+
393+
// Test, the 2 widgets should still be valid and visible
394+
const { updatedInterview, updatedValuesByPath, needUpdate } = prepareSectionWidgets(mainSection, testInterviewAttributes, { 'response.section1.q2': true }, {});
395+
396+
// Interview data should correspond to expected
397+
expect(updatedInterview).toEqual(expect.objectContaining(interviewAttributes));
398+
expect(updatedValuesByPath).toEqual({});
399+
expect(needUpdate).toEqual(false);
400+
401+
// Check calls of the validation function, should have been called for both widget: widget 2 because it is affected and widget 1 because it does not have a proper previous status.
402+
expect(mockedCheckValidations).toHaveBeenCalledTimes(2);
403+
expect(mockedCheckValidations).toHaveBeenCalledWith(undefined, interviewAttributes.response.section1.q1, undefined, testInterviewAttributes, 'section1.q1', undefined);
404+
expect(mockedCheckValidations).toHaveBeenCalledWith(widgets.widget2.validations, interviewAttributes.response.section1.q2, undefined, testInterviewAttributes, 'section1.q2', undefined);
405+
406+
// Check calls to the conditional function, called twice, once for each widget
407+
expect(mockedCheckConditional).toHaveBeenCalledTimes(2);
408+
expect(mockedCheckConditional).toHaveBeenCalledWith(undefined, testInterviewAttributes, 'section1.q1', undefined);
409+
expect(mockedCheckConditional).toHaveBeenCalledWith(undefined, testInterviewAttributes, 'section1.q2', undefined);
410+
411+
// Widget statuses should have been updated and match the one specified in the test, not the previous ones from the interview
412+
expect(updatedInterview.widgets).toEqual({
413+
widget1: previousWidgetStatuses.widget1,
414+
widget2: previousWidgetStatuses.widget2
415+
});
416+
417+
// Check the visible widgets and the allWidgetsValid flag
418+
expect(updatedInterview.visibleWidgets).toEqual(['section1.q1', 'section1.q2']);
419+
expect(updatedInterview.allWidgetsValid).toEqual(true);
420+
});
421+
385422
});
386423

387424
describe('Test with conditional', () => {

0 commit comments

Comments
 (0)