From 6836265e9d5410eb5a8cff8a86049369355da35e Mon Sep 17 00:00:00 2001 From: Vahn Gomes Date: Fri, 15 Mar 2024 21:20:07 -0400 Subject: [PATCH] Refactor requiredWhen validation logic --- __tests__/validator.test.ts | 68 +++++++++++++++++++++++++++++++++++++ src/index.ts | 40 +++++++++++++--------- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/__tests__/validator.test.ts b/__tests__/validator.test.ts index 13ab36e..814080f 100644 --- a/__tests__/validator.test.ts +++ b/__tests__/validator.test.ts @@ -182,6 +182,74 @@ describe("Validator - Required When Validation", () => { ); expect(validator.validate({ age: 18 })).resolves.toBe(false); }); + + it("should validate requiredWhen fields with multiple fields", () => { + const validator = new Validator( + { + name: { + type: "string", + requiredWhen: [ + { field: "age", value: 18 }, + { field: "age", value: 20 }, + ], + }, + age: { type: "number" }, + }, + { + name: { + type: "Name must be a string", + requiredWhen: "Name is required", + }, + age: { + type: "Age must be a number", + }, + } + ); + + expect(validator.validate({ name: "John Doe", age: 18 })).resolves.toBe( + true + ); + expect(validator.validate({ name: "John Doe", age: 20 })).resolves.toBe( + true + ); + expect(validator.validate({ age: 18 })).resolves.toBe(false); + }); + + it("should validate requiredWhen fields with multiple fields and values", () => { + const validator = new Validator( + { + name: { + type: "string", + requiredWhen: [ + { field: "age", value: [18, 20] }, + { field: "active", value: true }, + ], + }, + age: { type: "number" }, + active: { type: "boolean" }, + }, + { + name: { + type: "Name must be a string", + requiredWhen: "Name is required", + }, + age: { + type: "Age must be a number", + }, + active: { + type: "Active must be a boolean", + }, + } + ); + + expect( + validator.validate({ name: "John Doe", age: 18, active: true }) + ).resolves.toBe(true); + expect( + validator.validate({ name: "John Doe", age: 20, active: true }) + ).resolves.toBe(true); + expect(validator.validate({ age: 18, active: true })).resolves.toBe(false); + }); }); describe("Validator - Min/Max Validation", () => { diff --git a/src/index.ts b/src/index.ts index 965ae16..f38abf0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,7 +45,9 @@ interface Rule { /** * Field is required when another field matches a specific value. */ - requiredWhen?: { field: string; value: any | any[] }; + requiredWhen?: + | { field: string; value: any | any[] } + | Array<{ field: string; value: any | any[] }>; } /** @@ -265,27 +267,33 @@ class Validator { // Handle requiredWhen condition if (rule.requiredWhen) { - const conditionField = rule.requiredWhen.field; - const conditionValue = rule.requiredWhen.value; let conditionMet = false; - // Check if conditionValue is an array and if it includes the input value - if (Array.isArray(conditionValue)) { - conditionMet = conditionValue.includes(input[conditionField]); - } else { - // If conditionValue is not an array, proceed with the normal equality check - conditionMet = input[conditionField] === conditionValue; + // Convert single condition to array for unified processing + const conditions = Array.isArray(rule.requiredWhen) + ? rule.requiredWhen + : [rule.requiredWhen]; + + for (const condition of conditions) { + const conditionField = condition.field; + const conditionValue = condition.value; + const inputValue = input[conditionField]; + + // Check if the condition is met (supports value being an array) + if (Array.isArray(conditionValue)) { + conditionMet = conditionValue.includes(inputValue); + } else { + conditionMet = inputValue === conditionValue; + } + + if (conditionMet) break; // Stop checking further conditions if one is met } - // If the condition is met and the field is required but not present or empty + // If any condition is met and the field is required but not present or empty if (conditionMet && (value === "" || value === undefined)) { this.errors[key] = - this.messages[key].required ?? - `"${key}" is required when "${conditionField}" is set to ${ - Array.isArray(conditionValue) - ? conditionValue.join(" or ") - : conditionValue - }.`; + this.messages[key].requiredWhen ?? + `"${key}" is required based on the current conditions.`; isValid = false; continue; // Skip further checks for this field }