You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
842 lines
33 KiB
842 lines
33 KiB
import { describe, it, expect } from "vitest";
|
|
import {
|
|
canonicalRule,
|
|
ruleMatches,
|
|
isQuestionVisible,
|
|
isQuestionRequired,
|
|
} from "./conditional-rules";
|
|
import type { QuestionField } from "./schema-adapter";
|
|
|
|
describe("Conditional Rules Evaluator", () => {
|
|
const dummyQuestion: QuestionField = {
|
|
id: "child.q",
|
|
title: "Child Question",
|
|
type: "text",
|
|
order: 1,
|
|
required: false,
|
|
baseRequired: false,
|
|
isVisible: true,
|
|
description: "",
|
|
tooltip: "",
|
|
extras: { placeHolder: "", range: [0, 0], options: [] },
|
|
options: [],
|
|
};
|
|
|
|
it("should evaluate single trigger option match correctly", () => {
|
|
const rule = {
|
|
parent_question_id: "appearance_health.physical_health_status",
|
|
trigger_option_ids: [
|
|
"appearance_health.physical_health_status.i_have_a_specific_or_chronic_illness",
|
|
"appearance_health.physical_health_status.i_have_a_physical_deformity_disability_or_limitation",
|
|
],
|
|
operator: "any_of",
|
|
};
|
|
|
|
// 1. When parent is not answered
|
|
expect(ruleMatches(rule, {})).toBe(false);
|
|
|
|
// 2. When parent is answered with non-matching option
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_am_in_perfect_health",
|
|
option_id: "appearance_health.physical_health_status.i_am_in_perfect_health",
|
|
},
|
|
}),
|
|
).toBe(false);
|
|
|
|
// 3. When parent is answered with matching option (full slug)
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_have_a_specific_or_chronic_illness",
|
|
option_id:
|
|
"appearance_health.physical_health_status.i_have_a_specific_or_chronic_illness",
|
|
},
|
|
}),
|
|
).toBe(true);
|
|
|
|
// 4. When parent value only contains the short value
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_have_a_physical_deformity_disability_or_limitation",
|
|
},
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("should evaluate complex nested conditions (e.g. number of children rule)", () => {
|
|
// marital_history.number_of_children:
|
|
// parent: children_and_guardianship_status (have_children_living_with_me, have_children_not_living_with_me)
|
|
// conditions: current_marital_status in (divorced_after_living_together, widowed)
|
|
const rule = {
|
|
parent_question_id: "marital_history.children_and_guardianship_status",
|
|
trigger_option_ids: [
|
|
"marital_history.children_and_guardianship_status.have_children_living_with_me",
|
|
"marital_history.children_and_guardianship_status.have_children_not_living_with_me",
|
|
],
|
|
operator: "any_of",
|
|
conditions: [
|
|
{
|
|
parent_question_id: "marital_history.current_marital_status",
|
|
trigger_option_ids: [
|
|
"marital_history.current_marital_status.divorced_after_living_together",
|
|
"marital_history.current_marital_status.widowed",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
],
|
|
conditions_operator: "all_of",
|
|
root_operator: "all_of",
|
|
};
|
|
|
|
// Case 1: Single, no children -> false
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"marital_history.current_marital_status": {
|
|
value: "single_never_married",
|
|
},
|
|
"marital_history.children_and_guardianship_status": {
|
|
value: "no_children",
|
|
},
|
|
}),
|
|
).toBe(false);
|
|
|
|
// Case 2: Divorced, but no children -> false
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"marital_history.current_marital_status": {
|
|
value: "divorced_after_living_together",
|
|
option_id:
|
|
"marital_history.current_marital_status.divorced_after_living_together",
|
|
},
|
|
"marital_history.children_and_guardianship_status": {
|
|
value: "no_children",
|
|
option_id:
|
|
"marital_history.children_and_guardianship_status.no_children",
|
|
},
|
|
}),
|
|
).toBe(false);
|
|
|
|
// Case 3: Divorced AND has children -> true
|
|
expect(
|
|
ruleMatches(rule, {
|
|
"marital_history.current_marital_status": {
|
|
value: "divorced_after_living_together",
|
|
option_id:
|
|
"marital_history.current_marital_status.divorced_after_living_together",
|
|
},
|
|
"marital_history.children_and_guardianship_status": {
|
|
value: "have_children_living_with_me",
|
|
option_id:
|
|
"marital_history.children_and_guardianship_status.have_children_living_with_me",
|
|
},
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("should evaluate audience rules by gender and age", () => {
|
|
const questionForMen: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "education_career.ability_to_support_marriage_expenses",
|
|
audience: {
|
|
genders: ["male"],
|
|
},
|
|
};
|
|
|
|
const questionForWomen: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "beliefs_lifestyle.makeup_in_public",
|
|
audience: {
|
|
genders: ["female"],
|
|
},
|
|
};
|
|
|
|
// Male user
|
|
expect(isQuestionVisible(questionForMen, {}, { gender: "male" })).toBe(true);
|
|
expect(isQuestionVisible(questionForWomen, {}, { gender: "male" })).toBe(false);
|
|
|
|
// Female user
|
|
expect(isQuestionVisible(questionForMen, {}, { gender: "female" })).toBe(false);
|
|
expect(isQuestionVisible(questionForWomen, {}, { gender: "female" })).toBe(true);
|
|
});
|
|
|
|
it("should evaluate dynamic requirement via requiredWhen", () => {
|
|
const q: QuestionField = {
|
|
...dummyQuestion,
|
|
required: false,
|
|
baseRequired: false,
|
|
requiredWhen: {
|
|
parent_question_id: "family_background.parents_marital_status",
|
|
trigger_option_ids: [
|
|
"family_background.parents_marital_status.i_have_special_family_circumstances_and_will_provide_the_details_in_the_description",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
conditionalRule: {
|
|
parent_question_id: "family_background.parents_marital_status",
|
|
trigger_option_ids: [
|
|
"family_background.parents_marital_status.i_have_special_family_circumstances_and_will_provide_the_details_in_the_description",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// When condition not met -> not visible, not required
|
|
expect(isQuestionVisible(q, {})).toBe(false);
|
|
expect(isQuestionRequired(q, {})).toBe(false);
|
|
|
|
// When condition met -> visible AND required
|
|
const matchingAnswers = {
|
|
"family_background.parents_marital_status": {
|
|
value:
|
|
"i_have_special_family_circumstances_and_will_provide_the_details_in_the_description",
|
|
option_id:
|
|
"family_background.parents_marital_status.i_have_special_family_circumstances_and_will_provide_the_details_in_the_description",
|
|
},
|
|
};
|
|
|
|
expect(isQuestionVisible(q, matchingAnswers)).toBe(true);
|
|
expect(isQuestionRequired(q, matchingAnswers)).toBe(true);
|
|
});
|
|
|
|
it("should evaluate representative questions as optional for men and conditional for women based on age", () => {
|
|
const repNameQuestion: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "contact_residence.representative_s_full_name",
|
|
title: "Representative's Full Name",
|
|
required: false,
|
|
baseRequired: false,
|
|
requiredWhen: {
|
|
genders: ["female"],
|
|
maxAge: 26,
|
|
},
|
|
};
|
|
|
|
const repPhoneQuestion: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "contact_residence.representative_s_contact_number",
|
|
title: "Representative's Contact Number",
|
|
type: "phone",
|
|
required: false,
|
|
baseRequired: false,
|
|
requiredWhen: {
|
|
genders: ["female"],
|
|
maxAge: 26,
|
|
},
|
|
};
|
|
|
|
const repRelQuestion: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "contact_residence.relationship_to_representative",
|
|
title: "Relationship to Representative",
|
|
type: "dropdown",
|
|
required: false,
|
|
baseRequired: false,
|
|
requiredWhen: {
|
|
genders: ["female"],
|
|
maxAge: 26,
|
|
},
|
|
};
|
|
|
|
const repQuestions = [repNameQuestion, repPhoneQuestion, repRelQuestion];
|
|
|
|
// For Male (regardless of age: 20, 26, 30): ALWAYS OPTIONAL
|
|
for (const age of [18, 20, 25, 26, 27, 35]) {
|
|
const maleContext = { gender: "male", age };
|
|
for (const question of repQuestions) {
|
|
expect(isQuestionRequired(question, {}, maleContext)).toBe(false);
|
|
}
|
|
}
|
|
|
|
// For Female <= 26: REQUIRED
|
|
for (const age of [18, 20, 25, 26]) {
|
|
const youngFemaleContext = { gender: "female", age };
|
|
for (const question of repQuestions) {
|
|
expect(isQuestionRequired(question, {}, youngFemaleContext)).toBe(true);
|
|
}
|
|
}
|
|
|
|
// For Female >= 27: OPTIONAL
|
|
for (const age of [27, 30, 35]) {
|
|
const olderFemaleContext = { gender: "female", age };
|
|
for (const question of repQuestions) {
|
|
expect(isQuestionRequired(question, {}, olderFemaleContext)).toBe(false);
|
|
}
|
|
}
|
|
|
|
// When gender is unknown: OPTIONAL
|
|
for (const question of repQuestions) {
|
|
expect(isQuestionRequired(question, {}, {})).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("should correctly handle physical health 4-option visibility and medication requirement", () => {
|
|
// 1. Physical Health Description
|
|
const physicalHealthDescription: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "appearance_health.physical_health_description",
|
|
title: "Physical Health Description",
|
|
required: false,
|
|
baseRequired: false,
|
|
visibility: {
|
|
parent_question_id: "appearance_health.physical_health_status",
|
|
trigger_option_ids: [
|
|
"appearance_health.physical_health_status.i_have_a_specific_or_chronic_illness",
|
|
"appearance_health.physical_health_status.i_have_a_disability_or_physical_limitation",
|
|
"appearance_health.physical_health_status.i_have_other_illness_or_physical_conditions",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id: "appearance_health.physical_health_status",
|
|
trigger_option_ids: [
|
|
"appearance_health.physical_health_status.i_have_a_specific_or_chronic_illness",
|
|
"appearance_health.physical_health_status.i_have_a_disability_or_physical_limitation",
|
|
"appearance_health.physical_health_status.i_have_other_illness_or_physical_conditions",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// Option A: No illness -> hidden and not required
|
|
const optionAAnswers = {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_currently_have_no_specific_illness_or_physical_limitation",
|
|
option_id:
|
|
"appearance_health.physical_health_status.i_currently_have_no_specific_illness_or_physical_limitation",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(physicalHealthDescription, optionAAnswers)).toBe(false);
|
|
expect(isQuestionRequired(physicalHealthDescription, optionAAnswers)).toBe(false);
|
|
|
|
// Options B, C, D -> visible and required
|
|
const optionBAnswers = {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_have_a_specific_or_chronic_illness",
|
|
option_id:
|
|
"appearance_health.physical_health_status.i_have_a_specific_or_chronic_illness",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(physicalHealthDescription, optionBAnswers)).toBe(true);
|
|
expect(isQuestionRequired(physicalHealthDescription, optionBAnswers)).toBe(true);
|
|
|
|
const optionCAnswers = {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_have_a_disability_or_physical_limitation",
|
|
option_id:
|
|
"appearance_health.physical_health_status.i_have_a_disability_or_physical_limitation",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(physicalHealthDescription, optionCAnswers)).toBe(true);
|
|
expect(isQuestionRequired(physicalHealthDescription, optionCAnswers)).toBe(true);
|
|
|
|
const optionDAnswers = {
|
|
"appearance_health.physical_health_status": {
|
|
value: "i_have_other_illness_or_physical_conditions",
|
|
option_id:
|
|
"appearance_health.physical_health_status.i_have_other_illness_or_physical_conditions",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(physicalHealthDescription, optionDAnswers)).toBe(true);
|
|
expect(isQuestionRequired(physicalHealthDescription, optionDAnswers)).toBe(true);
|
|
|
|
// 2. Medication Name and Reason
|
|
const medicationDescription: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "appearance_health.medication_name_and_reason_for_use",
|
|
title: "Medication Name and Reason for Use",
|
|
required: false,
|
|
baseRequired: false,
|
|
visibility: {
|
|
parent_question_id:
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis",
|
|
trigger_option_ids: [
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis.yes",
|
|
],
|
|
operator: "any_of",
|
|
conditions: [
|
|
{
|
|
parent_question_id:
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues",
|
|
trigger_option_ids: [
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues.yes",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
],
|
|
root_operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id:
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis",
|
|
trigger_option_ids: [
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis.yes",
|
|
],
|
|
operator: "any_of",
|
|
conditions: [
|
|
{
|
|
parent_question_id:
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues",
|
|
trigger_option_ids: [
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues.yes",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
],
|
|
root_operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// Both No -> hidden
|
|
const medNoAnswers = {
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis": {
|
|
value: "no",
|
|
option_id:
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis.no",
|
|
},
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues": {
|
|
value: "no",
|
|
option_id:
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues.no",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(medicationDescription, medNoAnswers)).toBe(false);
|
|
expect(isQuestionRequired(medicationDescription, medNoAnswers)).toBe(false);
|
|
|
|
// Mental health med Yes -> visible and required
|
|
const medMentalYesAnswers = {
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis": {
|
|
value: "no",
|
|
option_id:
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis.no",
|
|
},
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues": {
|
|
value: "yes",
|
|
option_id:
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues.yes",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(medicationDescription, medMentalYesAnswers)).toBe(true);
|
|
expect(isQuestionRequired(medicationDescription, medMentalYesAnswers)).toBe(true);
|
|
|
|
// Ongoing med Yes -> visible and required
|
|
const medOngoingYesAnswers = {
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis": {
|
|
value: "yes",
|
|
option_id:
|
|
"appearance_health.do_you_currently_take_any_medication_on_an_ongoing_basis.yes",
|
|
},
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues": {
|
|
value: "no",
|
|
option_id:
|
|
"appearance_health.are_you_currently_taking_medication_for_mental_health_related_issues.no",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(medicationDescription, medOngoingYesAnswers)).toBe(true);
|
|
expect(isQuestionRequired(medicationDescription, medOngoingYesAnswers)).toBe(true);
|
|
});
|
|
|
|
it("should hide job title, work location, and monthly income for student, unemployed, student & job seeking, and homemaker", () => {
|
|
const jobTitle: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "education_career.job_title",
|
|
title: "عنوان شغلی",
|
|
visibility: {
|
|
parent_question_id: "education_career.employment_status",
|
|
trigger_option_ids: [
|
|
"education_career.employment_status.full_time_employed",
|
|
"education_career.employment_status.part_time_employed",
|
|
"education_career.employment_status.self_employed_freelancer",
|
|
"education_career.employment_status.entrepreneur_business_owner",
|
|
"education_career.employment_status.working_student",
|
|
"education_career.employment_status.retired",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
const workLocation: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "education_career.work_location",
|
|
title: "محل فعالیت",
|
|
visibility: {
|
|
parent_question_id: "education_career.employment_status",
|
|
trigger_option_ids: [
|
|
"education_career.employment_status.full_time_employed",
|
|
"education_career.employment_status.part_time_employed",
|
|
"education_career.employment_status.self_employed_freelancer",
|
|
"education_career.employment_status.entrepreneur_business_owner",
|
|
"education_career.employment_status.working_student",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
const monthlyIncome: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "education_career.monthly_income",
|
|
title: "میزان درآمد ماهانه",
|
|
required: false,
|
|
visibility: {
|
|
parent_question_id: "education_career.employment_status",
|
|
trigger_option_ids: [
|
|
"education_career.employment_status.full_time_employed",
|
|
"education_career.employment_status.part_time_employed",
|
|
"education_career.employment_status.self_employed_freelancer",
|
|
"education_career.employment_status.entrepreneur_business_owner",
|
|
"education_career.employment_status.working_student",
|
|
"education_career.employment_status.retired",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id: "education_career.employment_status",
|
|
trigger_option_ids: [
|
|
"education_career.employment_status.full_time_employed",
|
|
"education_career.employment_status.part_time_employed",
|
|
"education_career.employment_status.self_employed_freelancer",
|
|
"education_career.employment_status.entrepreneur_business_owner",
|
|
"education_career.employment_status.working_student",
|
|
"education_career.employment_status.retired",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// Hidden cases: دانشجو, دانشجو و جویای کار, جویای کار / بیکار, خانهدار
|
|
const hiddenStatuses = [
|
|
"student",
|
|
"student_and_job_seeking",
|
|
"job_seeking_unemployed",
|
|
"homemaker",
|
|
];
|
|
|
|
for (const status of hiddenStatuses) {
|
|
const answers = {
|
|
"education_career.employment_status": {
|
|
value: status,
|
|
option_id: `education_career.employment_status.${status}`,
|
|
},
|
|
};
|
|
|
|
expect(isQuestionVisible(jobTitle, answers)).toBe(false);
|
|
expect(isQuestionVisible(workLocation, answers)).toBe(false);
|
|
expect(isQuestionVisible(monthlyIncome, answers)).toBe(false);
|
|
expect(isQuestionRequired(monthlyIncome, answers)).toBe(false);
|
|
}
|
|
|
|
// Visible case: Full time employed
|
|
const fullTimeAnswers = {
|
|
"education_career.employment_status": {
|
|
value: "full_time_employed",
|
|
option_id: "education_career.employment_status.full_time_employed",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(jobTitle, fullTimeAnswers)).toBe(true);
|
|
expect(isQuestionVisible(workLocation, fullTimeAnswers)).toBe(true);
|
|
expect(isQuestionVisible(monthlyIncome, fullTimeAnswers)).toBe(true);
|
|
expect(isQuestionRequired(monthlyIncome, fullTimeAnswers)).toBe(true);
|
|
|
|
// Visible case: Working student
|
|
const workingStudentAnswers = {
|
|
"education_career.employment_status": {
|
|
value: "working_student",
|
|
option_id: "education_career.employment_status.working_student",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(jobTitle, workingStudentAnswers)).toBe(true);
|
|
expect(isQuestionVisible(workLocation, workingStudentAnswers)).toBe(true);
|
|
expect(isQuestionVisible(monthlyIncome, workingStudentAnswers)).toBe(true);
|
|
expect(isQuestionRequired(monthlyIncome, workingStudentAnswers)).toBe(true);
|
|
|
|
// Retired case: Job title and monthly income visible, work location hidden
|
|
const retiredAnswers = {
|
|
"education_career.employment_status": {
|
|
value: "retired",
|
|
option_id: "education_career.employment_status.retired",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(jobTitle, retiredAnswers)).toBe(true);
|
|
expect(isQuestionVisible(workLocation, retiredAnswers)).toBe(false);
|
|
expect(isQuestionVisible(monthlyIncome, retiredAnswers)).toBe(true);
|
|
expect(isQuestionRequired(monthlyIncome, retiredAnswers)).toBe(true);
|
|
});
|
|
|
|
it("should show parents marital status only when both parents are alive (Option A) and hide for options B, C, D", () => {
|
|
const parentsMaritalStatus: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "family_background.parents_marital_status",
|
|
title: "وضعیت تأهل والدین",
|
|
required: false,
|
|
visibility: {
|
|
parent_question_id: "family_background.parents_survival_status",
|
|
trigger_option_ids: [
|
|
"family_background.parents_survival_status.both_parents_are_alive",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id: "family_background.parents_survival_status",
|
|
trigger_option_ids: [
|
|
"family_background.parents_survival_status.both_parents_are_alive",
|
|
],
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// Option A: Both parents are alive -> Visible & Required
|
|
const optionAAnswers = {
|
|
"family_background.parents_survival_status": {
|
|
value: "both_parents_are_alive",
|
|
option_id: "family_background.parents_survival_status.both_parents_are_alive",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(parentsMaritalStatus, optionAAnswers)).toBe(true);
|
|
expect(isQuestionRequired(parentsMaritalStatus, optionAAnswers)).toBe(true);
|
|
|
|
// Option B: Father has passed away -> Hidden & Not Required
|
|
const optionBAnswers = {
|
|
"family_background.parents_survival_status": {
|
|
value: "father_has_passed_away",
|
|
option_id: "family_background.parents_survival_status.father_has_passed_away",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(parentsMaritalStatus, optionBAnswers)).toBe(false);
|
|
expect(isQuestionRequired(parentsMaritalStatus, optionBAnswers)).toBe(false);
|
|
|
|
// Option C: Mother has passed away -> Hidden & Not Required
|
|
const optionCAnswers = {
|
|
"family_background.parents_survival_status": {
|
|
value: "mother_has_passed_away",
|
|
option_id: "family_background.parents_survival_status.mother_has_passed_away",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(parentsMaritalStatus, optionCAnswers)).toBe(false);
|
|
expect(isQuestionRequired(parentsMaritalStatus, optionCAnswers)).toBe(false);
|
|
|
|
// Option D: Both parents have passed away -> Hidden & Not Required
|
|
const optionDAnswers = {
|
|
"family_background.parents_survival_status": {
|
|
value: "both_parents_have_passed_away",
|
|
option_id: "family_background.parents_survival_status.both_parents_have_passed_away",
|
|
},
|
|
};
|
|
expect(isQuestionVisible(parentsMaritalStatus, optionDAnswers)).toBe(false);
|
|
expect(isQuestionRequired(parentsMaritalStatus, optionDAnswers)).toBe(false);
|
|
});
|
|
|
|
it("should show family responsibility follow-up questions (live with you, additional details) and make them required only when responsibility options are selected", () => {
|
|
const parentId = "family_background.do_you_currently_have_an_ongoing_financial_caregiving_or_guardianship_responsibility_for_a_family_member";
|
|
const triggerOptionIds = [
|
|
`${parentId}.i_am_responsible_for_caring_for_my_father`,
|
|
`${parentId}.i_am_responsible_for_caring_for_my_mother`,
|
|
`${parentId}.i_am_responsible_for_caring_for_both_parents`,
|
|
`${parentId}.i_am_responsible_for_caring_for_a_sibling_brother_sister`,
|
|
`${parentId}.i_am_the_legal_guardian_or_supervisor_of_a_family_member`,
|
|
`${parentId}.i_regularly_provide_financial_support_for_a_family_member_s_living_expenses`,
|
|
`${parentId}.i_have_other_circumstances_and_will_explain_in_the_description`,
|
|
`${parentId}.i_am_responsible_for_caring_for_my_parent_s_father_mother_or_both`,
|
|
];
|
|
|
|
const liveWithYou: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "family_background.do_the_supported_individual_s_live_with_you",
|
|
title: "آیا فرد یا افراد تحت حمایت با شما زندگی میکنند؟",
|
|
required: false,
|
|
visibility: {
|
|
parent_question_id: parentId,
|
|
trigger_option_ids: triggerOptionIds,
|
|
operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id: parentId,
|
|
trigger_option_ids: triggerOptionIds,
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
const additionalDetails: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "family_background.additional_details_about_family_responsibility",
|
|
title: "توضیحات تکمیلی درباره مسئولیت خانوادگی",
|
|
required: false,
|
|
visibility: {
|
|
parent_question_id: parentId,
|
|
trigger_option_ids: triggerOptionIds,
|
|
operator: "any_of",
|
|
},
|
|
requiredWhen: {
|
|
parent_question_id: parentId,
|
|
trigger_option_ids: triggerOptionIds,
|
|
operator: "any_of",
|
|
},
|
|
};
|
|
|
|
// Case 1: No ongoing responsibility selected -> Hidden & Not Required
|
|
const noRespAnswers = {
|
|
[parentId]: {
|
|
value: ["خیر، مسئولیت مستمری ندارم."],
|
|
option_id: [`${parentId}.no_i_do_not_have_any_ongoing_responsibility`],
|
|
},
|
|
};
|
|
expect(isQuestionVisible(liveWithYou, noRespAnswers)).toBe(false);
|
|
expect(isQuestionRequired(liveWithYou, noRespAnswers)).toBe(false);
|
|
expect(isQuestionVisible(additionalDetails, noRespAnswers)).toBe(false);
|
|
expect(isQuestionRequired(additionalDetails, noRespAnswers)).toBe(false);
|
|
|
|
// Case 2: Responsibility selected (e.g. Caring for father) -> Visible & Required
|
|
const fatherRespAnswers = {
|
|
[parentId]: {
|
|
value: ["مسئولیت مراقبت از پدر را بر عهده دارم."],
|
|
option_id: [`${parentId}.i_am_responsible_for_caring_for_my_father`],
|
|
},
|
|
};
|
|
expect(isQuestionVisible(liveWithYou, fatherRespAnswers)).toBe(true);
|
|
expect(isQuestionRequired(liveWithYou, fatherRespAnswers)).toBe(true);
|
|
expect(isQuestionVisible(additionalDetails, fatherRespAnswers)).toBe(true);
|
|
expect(isQuestionRequired(additionalDetails, fatherRespAnswers)).toBe(true);
|
|
|
|
// Case 3: Multiple responsibilities selected -> Visible & Required
|
|
const multiRespAnswers = {
|
|
[parentId]: {
|
|
value: ["مسئولیت مراقبت از پدر", "حمایت مالی"],
|
|
option_id: [
|
|
`${parentId}.i_am_responsible_for_caring_for_my_father`,
|
|
`${parentId}.i_regularly_provide_financial_support_for_a_family_member_s_living_expenses`,
|
|
],
|
|
},
|
|
};
|
|
expect(isQuestionVisible(liveWithYou, multiRespAnswers)).toBe(true);
|
|
expect(isQuestionRequired(liveWithYou, multiRespAnswers)).toBe(true);
|
|
expect(isQuestionVisible(additionalDetails, multiRespAnswers)).toBe(true);
|
|
expect(isQuestionRequired(additionalDetails, multiRespAnswers)).toBe(true);
|
|
});
|
|
|
|
it("should handle Section 6 marital history and children follow-up rules properly", () => {
|
|
const mStatusId = "marital_history.current_marital_status";
|
|
const previousTriggerIds = [
|
|
`${mStatusId}.failed_engagement_annulled_marriage_without_living_together`,
|
|
`${mStatusId}.failed_marriage_contract_annulled_engagement_without_starting_joint_life`,
|
|
`${mStatusId}.divorced_after_living_together`,
|
|
`${mStatusId}.widowed`,
|
|
];
|
|
const divorcedOrAnnulledIds = [
|
|
`${mStatusId}.failed_engagement_annulled_marriage_without_living_together`,
|
|
`${mStatusId}.failed_marriage_contract_annulled_engagement_without_starting_joint_life`,
|
|
`${mStatusId}.divorced_after_living_together`,
|
|
];
|
|
|
|
const cStatusId = "marital_history.children_and_guardianship_status";
|
|
const hasChildrenTriggerIds = [
|
|
`${cStatusId}.have_children_living_with_me`,
|
|
`${cStatusId}.have_children_not_living_with_me`,
|
|
];
|
|
|
|
const prevDuration: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "marital_history.previous_marriage_duration",
|
|
title: "مدت ازدواج یا عقد قبلی",
|
|
required: false,
|
|
visibility: { parent_question_id: mStatusId, trigger_option_ids: previousTriggerIds, operator: "any_of" },
|
|
requiredWhen: { parent_question_id: mStatusId, trigger_option_ids: previousTriggerIds, operator: "any_of" },
|
|
};
|
|
|
|
const reasonSeparation: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "marital_history.reason_for_separation",
|
|
title: "علت جدایی، در صورت وجود",
|
|
required: false,
|
|
visibility: { parent_question_id: mStatusId, trigger_option_ids: divorcedOrAnnulledIds, operator: "any_of" },
|
|
};
|
|
|
|
const childrenStatus: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "marital_history.children_and_guardianship_status",
|
|
title: "وضعیت فرزند و تکفل",
|
|
required: false,
|
|
visibility: { parent_question_id: mStatusId, trigger_option_ids: previousTriggerIds, operator: "any_of" },
|
|
requiredWhen: { parent_question_id: mStatusId, trigger_option_ids: previousTriggerIds, operator: "any_of" },
|
|
};
|
|
|
|
const numChildren: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "marital_history.number_of_children",
|
|
title: "تعداد فرزندان",
|
|
required: false,
|
|
visibility: { parent_question_id: cStatusId, trigger_option_ids: hasChildrenTriggerIds, operator: "any_of" },
|
|
requiredWhen: { parent_question_id: cStatusId, trigger_option_ids: hasChildrenTriggerIds, operator: "any_of" },
|
|
};
|
|
|
|
const custodyStatus: QuestionField = {
|
|
...dummyQuestion,
|
|
id: "marital_history.what_is_the_custody_status_of_your_child_ren",
|
|
title: "وضعیت حضانت فرزند یا فرزندان شما چگونه است؟",
|
|
required: false,
|
|
visibility: { parent_question_id: cStatusId, trigger_option_ids: hasChildrenTriggerIds, operator: "any_of" },
|
|
requiredWhen: { parent_question_id: cStatusId, trigger_option_ids: hasChildrenTriggerIds, operator: "any_of" },
|
|
};
|
|
|
|
// 1. Single: previous duration, reason for separation, and children status are all HIDDEN
|
|
const singleAns = {
|
|
[mStatusId]: {
|
|
value: "single_never_married",
|
|
option_id: `${mStatusId}.single_never_married`,
|
|
},
|
|
};
|
|
expect(isQuestionVisible(prevDuration, singleAns)).toBe(false);
|
|
expect(isQuestionVisible(reasonSeparation, singleAns)).toBe(false);
|
|
expect(isQuestionVisible(childrenStatus, singleAns)).toBe(false);
|
|
|
|
// 2. Divorced: duration, reason, and children status are all VISIBLE
|
|
const divorcedAns = {
|
|
[mStatusId]: {
|
|
value: "divorced_after_living_together",
|
|
option_id: `${mStatusId}.divorced_after_living_together`,
|
|
},
|
|
};
|
|
expect(isQuestionVisible(prevDuration, divorcedAns)).toBe(true);
|
|
expect(isQuestionRequired(prevDuration, divorcedAns)).toBe(true);
|
|
expect(isQuestionVisible(reasonSeparation, divorcedAns)).toBe(true);
|
|
expect(isQuestionVisible(childrenStatus, divorcedAns)).toBe(true);
|
|
expect(isQuestionRequired(childrenStatus, divorcedAns)).toBe(true);
|
|
|
|
// 3. Widowed: duration & children VISIBLE, reason for separation HIDDEN
|
|
const widowedAns = {
|
|
[mStatusId]: {
|
|
value: "widowed",
|
|
option_id: `${mStatusId}.widowed`,
|
|
},
|
|
};
|
|
expect(isQuestionVisible(prevDuration, widowedAns)).toBe(true);
|
|
expect(isQuestionRequired(prevDuration, widowedAns)).toBe(true);
|
|
expect(isQuestionVisible(reasonSeparation, widowedAns)).toBe(false);
|
|
expect(isQuestionVisible(childrenStatus, widowedAns)).toBe(true);
|
|
expect(isQuestionRequired(childrenStatus, widowedAns)).toBe(true);
|
|
|
|
// 4. Children follow-ups: when children exist -> VISIBLE & REQUIRED
|
|
const hasChildAns = {
|
|
[cStatusId]: {
|
|
value: "have_children_living_with_me",
|
|
option_id: `${cStatusId}.have_children_living_with_me`,
|
|
},
|
|
};
|
|
expect(isQuestionVisible(numChildren, hasChildAns)).toBe(true);
|
|
expect(isQuestionRequired(numChildren, hasChildAns)).toBe(true);
|
|
expect(isQuestionVisible(custodyStatus, hasChildAns)).toBe(true);
|
|
expect(isQuestionRequired(custodyStatus, hasChildAns)).toBe(true);
|
|
|
|
// 5. No children: child questions HIDDEN & NOT REQUIRED
|
|
const noChildAns = {
|
|
[cStatusId]: {
|
|
value: "no_children",
|
|
option_id: `${cStatusId}.no_children`,
|
|
},
|
|
};
|
|
expect(isQuestionVisible(numChildren, noChildAns)).toBe(false);
|
|
expect(isQuestionRequired(numChildren, noChildAns)).toBe(false);
|
|
expect(isQuestionVisible(custodyStatus, noChildAns)).toBe(false);
|
|
expect(isQuestionRequired(custodyStatus, noChildAns)).toBe(false);
|
|
});
|
|
});
|