ealush / vest

Vest ✅ Declarative validations framework

Home Page:https://vestjs.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dynamic fields

saharulit opened this issue · comments

I have a form where some fields are dynamically created, some of the dynamic fields are required and some are optional,
I couldn’t find a way to make vest support this use case, any suggestions?

Not knowing much about your specific use-case (maybe share a more detailed example?), but just from the overall description, it seems like you require something of that sort: A combination of each+optional

https://vestjs.dev/docs/writing_tests/advanced_test_features/dynamic_tests - allows you to iterate over a list of values to create dynamic tests
https://vestjs.dev/docs/writing_your_suite/optional_fields - allows you to set values as optional so they do not set the form as invalid when they are not filled out

I appreciate your quick response!

I will share with you more details -
My form library is Felete and my validator is Vest.
There are some fields in my form that are not consts and I'm getting them at runtime (I don't have the fields names)
It looks something like this:

[
{name: "address" , required: true},
{name: "building_number", required: false},
...
]

Is there a way to create a dynamic suite that gets data on the fly?

each(data.fields, field => {
    optional(field.name)
    test(
      field.name,
      'item price must be greater than 0',
      () => {
        enforce(field.price).isNumeric().greaterThan(0);
      },
    );
});

@ealush is this how you would write these validation tests? Combining each and optional this way doesn't seem to work (i.e., the fields aren't marked as optional).

@swithek I just ran a test with the exact scenario that you mentioned, and I can confirm it works correctly: https://codesandbox.io/s/react-forked-0bobdc?file=/src/suite.js

Type in Req_1 and Req_2, and you'll see that the submit button lights up, even though you did not fill out the optional field.

I believe that what you're experiencing is this:
You type in the optional field, and then remove its content. In this scenario, the field is indeed not valid any more.

It all boils down to what optional really means in your app's context, and what qualifies as optional-satisfying-test.

Let me explain:

If the field is empty, does that qualify for optional? Maybe. But what if the user typed inside the field and then removed its content - is that qualify as optional? Maybe in your app, the field is optional only if some other condition applies, for example - when another field has been filled...

As you see, optional can mean different things in different context. As I mentioned in a previous answer a couple of weeks back, Vest doesn't have a notion of your apps logic, or in other words - Vest has no knowledge of "what should happen now", it also doesn't make sense of your data, so marking a certain field as optional, doesn't mean Vest is going to check the data properties passed to it, because you may name them whatever you want.

Instead, a different approach is taken in Vest, assuming it isn't aware of your business logic.

Vest determines whether a field qualifies as optional by a certain rule: did it have any test runs?
Meaning, if a test of a certain field did indeed run, it will be regarded as required, because its tests were triggered.

  • or, in other words - Vest allows the Suite to be regarded as valid, if the fields marked as optional did not run at all.

Thank you for your quick reply @ealush! What you're saying makes complete sense, however, as specified in the docs, you can have custom rules that determine whether the field should be optional or not, is that correct? If that's the case, shouldn't having

optional({
    optional: !data["optional"],
});

be enough to cover all the empty value/undefined field cases, even when there are existing validation results from previous runs? This doesn't seem to work when each is used. Maybe I'm missing something?

Here's an example based on your example: https://codesandbox.io/s/react-forked-oy06l8?file=/src/suite.js

I will have to dig deeper to see why that specific case didn't work for you, but just to unblock you now - using a function should solve it for you.

optional({
  optional: () => !data.optional
});

https://codesandbox.io/s/react-forked-hpry5u?file=/src/suite.js