Skip to content

Commit f877312

Browse files
authored
fix: Check page visibility while checking rules for element visibility/validation (#5678)
* Check page visibility while recusively checking rules for element visibility * Fix tests * uncomment test * Add a few tests * Write some more tests
1 parent 3e1d74d commit f877312

File tree

3 files changed

+662
-10
lines changed

3 files changed

+662
-10
lines changed

lib/formContext.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,34 @@ export const getElementById = (elements: FormElement[], id: string) => {
146146
return elements.find((el) => el.id.toString() === id);
147147
};
148148

149+
/**
150+
* Checks a page/group visibility based on the current form values groupHistory.
151+
*
152+
* @param formRecord - The form record containing the form and its groups.
153+
* @param element - The form element to check visibility for.
154+
* @param values - The current form values from Formik, which should include groupHistory.
155+
* @returns {boolean} - Returns true if the page/group is visible based on the groupHistory, false otherwise.
156+
*/
157+
export const checkPageVisibility = (
158+
formRecord: PublicFormRecord,
159+
element: FormElement,
160+
values: FormValues
161+
): boolean => {
162+
if (!formRecord.form.groups) {
163+
return true;
164+
}
165+
166+
const groups = formRecord.form.groups as GroupsType;
167+
168+
// Get the current element's group ID
169+
const groupId = Object.keys(groups).find((groupKey) => inGroup(groupKey, element.id, groups));
170+
171+
const groupHistory = Array.isArray(values.groupHistory)
172+
? values.groupHistory
173+
: [values.groupHistory];
174+
return !!groupHistory.find((visitedGroupId: string | undefined) => visitedGroupId === groupId);
175+
};
176+
149177
/**
150178
* Recursively determines the "visibility" of a form element for the purposes of validation
151179
* based on its conditional rules and the current form values.
@@ -161,14 +189,21 @@ export const getElementById = (elements: FormElement[], id: string) => {
161189
* @param formRecord - The form record.
162190
* @param element - The form element whose visibility is being determined.
163191
* @param values - The current form values from Formik.
164-
* @returns `true` if the element should be visible, `false` otherwise.
192+
* @returns {boolean} -Returns `true` if the element should be visible, `false` otherwise.
165193
*/
166194
export const checkVisibilityRecursive = (
167195
formRecord: PublicFormRecord,
168196
element: FormElement,
169197
values: FormValues,
170198
checked: Set<string> = new Set()
171199
): boolean => {
200+
// If the current page is not visible, the element is not visible
201+
const pageVisible = checkPageVisibility(formRecord, element, values);
202+
203+
if (!pageVisible) {
204+
return false;
205+
}
206+
172207
const rules = element.properties.conditionalRules;
173208
if (!rules || rules.length === 0) return true;
174209

@@ -191,7 +226,6 @@ export const checkVisibilityRecursive = (
191226
return (
192227
checkVisibilityRecursive(formRecord, ruleParent, values, checked) &&
193228
matchRule(rule, formElements, values)
194-
// @TODO: && checkPageVisibilityRecursive
195229
);
196230
});
197231
};
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { checkPageVisibility, FormValues, GroupsType } from "../formContext";
2+
import type { PublicFormRecord, FormElement } from "../types";
3+
4+
describe("checkPageVisibility", () => {
5+
const baseElement: FormElement = {
6+
id: 1,
7+
type: "textField",
8+
properties: { conditionalRules: [] }
9+
} as unknown as FormElement;
10+
11+
it("returns true if form has no groups", () => {
12+
const formRecord = {
13+
form: {
14+
elements: [baseElement]
15+
}
16+
} as PublicFormRecord;
17+
expect(checkPageVisibility(formRecord, baseElement, {})).toBe(true);
18+
});
19+
20+
it("returns true if element's group is in groupHistory (array)", () => {
21+
const groups: GroupsType = {
22+
groupA: { name: "A", titleEn: "", titleFr: "", elements: ["1"] }
23+
};
24+
const formRecord = {
25+
form: {
26+
elements: [baseElement],
27+
groups
28+
}
29+
} as PublicFormRecord;
30+
const values: FormValues = { groupHistory: ["groupA"] };
31+
expect(checkPageVisibility(formRecord, baseElement, values)).toBe(true);
32+
});
33+
34+
it("returns true if element's group is in groupHistory (string)", () => {
35+
const groups: GroupsType = {
36+
groupA: { name: "A", titleEn: "", titleFr: "", elements: ["1"] }
37+
};
38+
const formRecord = {
39+
form: {
40+
elements: [baseElement],
41+
groups
42+
}
43+
} as PublicFormRecord;
44+
const values: FormValues = { groupHistory: "groupA" };
45+
expect(checkPageVisibility(formRecord, baseElement, values)).toBe(true);
46+
});
47+
48+
it("returns false if element's group is not in groupHistory", () => {
49+
const groups: GroupsType = {
50+
groupA: { name: "A", titleEn: "", titleFr: "", elements: ["1"] }
51+
};
52+
const formRecord = {
53+
form: {
54+
elements: [baseElement],
55+
groups
56+
}
57+
} as PublicFormRecord;
58+
const values: FormValues = { groupHistory: ["groupB"] };
59+
expect(checkPageVisibility(formRecord, baseElement, values)).toBe(false);
60+
});
61+
62+
it("returns false if element is not in any group", () => {
63+
const groups: GroupsType = {
64+
groupA: { name: "A", titleEn: "", titleFr: "", elements: ["2"] }
65+
};
66+
const formRecord = {
67+
form: {
68+
elements: [baseElement],
69+
groups
70+
}
71+
} as PublicFormRecord;
72+
const values: FormValues = { groupHistory: ["groupA"] };
73+
expect(checkPageVisibility(formRecord, baseElement, values)).toBe(false);
74+
});
75+
});

0 commit comments

Comments
 (0)