From f0746170558a9c268c2368527379420929edc9ae Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Sun, 30 Jun 2024 10:06:37 +0200 Subject: [PATCH] test: add many tests for dependent fields --- .gitignore | 1 + docs/blog/posts/NextRelease.md | 2 + src/core/input/dependentFields.test.ts | 116 ++++++++++++++++++++++++- src/core/input/dependentFields.ts | 4 - 4 files changed, 117 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 58babce5..9e66c925 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ meta.json site/ docs/index.md docs/changelog.md +coverage diff --git a/docs/blog/posts/NextRelease.md b/docs/blog/posts/NextRelease.md index a2bfd5fe..a8d07676 100644 --- a/docs/blog/posts/NextRelease.md +++ b/docs/blog/posts/NextRelease.md @@ -31,6 +31,8 @@ Form in preview mode with the condition met with the condition not met ![condition not met]() +This first iteration is purely visual: just because a field is hidden it does not mean that, if it has a value, is not going to be included in the result. If you fill a field, and then do something that makes it hidden, the value will still be included in the result. I think in practice most people just needs a way to start with several fields hidden, and then show them based on the value of other fields, so I think this is a good first approach. + The wording of the feature is not final, I'm not very satisfied with the current wording, so I'm open to suggestions. I hope you like it, that it does not introduce too many inconveniences and that it is useful to you. diff --git a/src/core/input/dependentFields.test.ts b/src/core/input/dependentFields.test.ts index d99765d0..b18675a2 100644 --- a/src/core/input/dependentFields.test.ts +++ b/src/core/input/dependentFields.test.ts @@ -1,12 +1,124 @@ import { input } from "@core"; +import * as v from "valibot"; import { FieldDefinition } from "../formDefinition"; +import * as deps from "./dependentFields"; +import { ConditionSchema } from "./dependentFields"; describe("dependentFields", () => { it("should return a list of conditions available for the input type: 'text'", () => { const field: FieldDefinition["input"] = { type: "text", }; - const result = input.availableConditionsForInput(field); - expect(result).toEqual(["isSet", "startsWith", "contains"]); + const types = input.availableConditionsForInput(field); + types.forEach((type) => { + const value = { type, dependencyName: "test-field", value: "test" }; + const parsed = v.safeParse(ConditionSchema, value); + expect(parsed.success).toBe(true); + }); + expect.assertions(types.length); + }); + it("should return true if the value is set", () => { + const condition: input.Condition = { + type: "isSet", + dependencyName: "test-field", + }; + expect(deps.valueMeetsCondition(condition, "test")).toBe(true); + expect(deps.valueMeetsCondition(condition, 0)).toBe(true); + expect(deps.valueMeetsCondition(condition, true)).toBe(true); + expect(deps.valueMeetsCondition(condition, false)).toBe(true); + }); + it("should return false if the value is not set", () => { + const condition: input.Condition = { + type: "isSet", + dependencyName: "test-field", + }; + expect(deps.valueMeetsCondition(condition, "")).toBe(false); + }); + it("should handle the boolean condition", () => { + const condition: input.Condition = { + type: "boolean", + value: true, + dependencyName: "test-field", + }; + expect(deps.valueMeetsCondition(condition, true)).toBe(true); + expect(deps.valueMeetsCondition(condition, false)).toBe(false); + }); + it('should handle the isSet conditions for "null" and "undefined"', () => { + const condition: input.Condition = { + type: "isSet", + dependencyName: "test-field", + }; + expect(deps.valueMeetsCondition(condition, null)).toBe(false); + expect(deps.valueMeetsCondition(condition, undefined)).toBe(false); + expect(deps.valueMeetsCondition(condition, "")).toBe(false); + }); + it("should properly handle all string conditions that are true", () => { + const conditions: [input.Condition, string][] = [ + [{ type: "startsWith", dependencyName: "test-field", value: "test" }, "test starts"], + [{ type: "endsWith", dependencyName: "test-field", value: "test" }, "ends with test"], + [{ type: "isExactly", dependencyName: "test-field", value: "test" }, "test"], + [ + { type: "contains", dependencyName: "test-field", value: "test" }, + "contains test somewhere", + ], + ]; + conditions.forEach(([condition, value]) => { + expect(deps.valueMeetsCondition(condition, value)).toBe(true); + }); + expect.assertions(conditions.length); + }); + it("should properly handle all string conditions that are false", () => { + const conditions: [input.Condition, unknown][] = [ + [{ type: "startsWith", dependencyName: "test-field", value: "test" }, "not test"], + [{ type: "startsWith", dependencyName: "test-field", value: "test" }, null], + [ + { type: "endsWith", dependencyName: "test-field", value: "test" }, + "not test at the end", + ], + [ + { type: "isExactly", dependencyName: "test-field", value: "test" }, + "not exactly test", + ], + [ + { type: "contains", dependencyName: "test-field", value: "test" }, + "does not contain tst", + ], + ]; + conditions.forEach(([condition, value]) => { + expect(deps.valueMeetsCondition(condition, value)).toBe(false); + }); + expect.assertions(conditions.length); + }); + it("should properly handle all number conditions that are true", () => { + const conditions: [input.Condition, unknown][] = [ + [{ type: "above", dependencyName: "test", value: 5 }, 6], + [{ type: "aboveOrEqual", dependencyName: "test", value: 5 }, 5], + [{ type: "aboveOrEqual", dependencyName: "test", value: 5 }, 8], + [{ type: "below", dependencyName: "test", value: 5 }, 4], + [{ type: "below", dependencyName: "test", value: 5 }, -4], + [{ type: "belowOrEqual", dependencyName: "test", value: 5 }, 5], + [{ type: "belowOrEqual", dependencyName: "test", value: 5 }, 2], + [{ type: "exactly", dependencyName: "test", value: 5 }, 5], + ]; + conditions.forEach(([condition, value]) => { + expect(deps.valueMeetsCondition(condition, value)).toBe(true); + }); + expect.assertions(conditions.length); + }); + it("should properly handle all number conditions that are false", () => { + const conditions: [input.Condition, unknown][] = [ + [{ type: "above", dependencyName: "test", value: 5 }, 4], + [{ type: "aboveOrEqual", dependencyName: "test", value: 5 }, 4], + [{ type: "below", dependencyName: "test", value: 5 }, 6], + [{ type: "belowOrEqual", dependencyName: "test", value: 5 }, 6], + [{ type: "exactly", dependencyName: "test", value: 5 }, 4], + [{ type: "exactly", dependencyName: "test", value: 5 }, null], + [{ type: "exactly", dependencyName: "test", value: 5 }, undefined], + [{ type: "exactly", dependencyName: "test", value: 5 }, {}], + ]; + conditions.forEach(([condition, value]) => { + expect(deps.valueMeetsCondition(condition, value)).toBe(false); + }); + expect.assertions(conditions.length); }); }); diff --git a/src/core/input/dependentFields.ts b/src/core/input/dependentFields.ts index 10f85194..62bc6156 100644 --- a/src/core/input/dependentFields.ts +++ b/src/core/input/dependentFields.ts @@ -109,12 +109,8 @@ function processNumberCondition( } export function valueMeetsCondition(condition: Condition, value: unknown): boolean { - if (value === null || value === undefined) { - return false; - } switch (condition.type) { case "isSet": - console.log({ ...condition, value }); return processIsSet(condition, value); case "startsWith": case "contains":