Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nested suites #1141

Open
codrin-iftimie opened this issue Mar 13, 2024 · 2 comments
Open

Support for nested suites #1141

codrin-iftimie opened this issue Mar 13, 2024 · 2 comments

Comments

@codrin-iftimie
Copy link

I'm researching libraries that can be used to replace my in-house form validator library. I'm using generators at the moment.
Most of the requirements this library checks them. Kudos for that.
But, one of the common requirements is the ability to nest validators to ensure good code reusability.
Let's take this as an example

const itemSuite = create(() => {
  test('field1', 'Field1 is invalid' () => {
    //
  })
})

const mainSuite = create((items) => {
  test('items', 'One or more item is invalid' () => {
    ensure(data.items).matchesArrayOfSuite(itemSuite)
  })

  test('innerItem', 'This inner item is not valid', () => {
    ensure(data.innerItem).matchesSuite(itemSuite)
  })
})

In some cases, I'd like to use the itemSuite to validate an item object on a "details" page where there are independent CRUD operations for each item.
In other cases, I have a wizard where we allow the user to add these items as part of a bigger payload (see mainSuite).
I know that matchesArrayOfSuite nor matchesSuite is not part of the current enforce API. Is there any plan to support something similar to this that would allow nesting suites?
Expectations would be to see a general error on items and innerItem if the object is not valid, but also have mainSuite to inherit the details from itemSuite to show them to their respective fields.

@codrin-iftimie
Copy link
Author

Seems that the following is producing the right result

const itemSuite = create("itemSuite", (item, path) => {
  test(`${path}.name`, "Name is required", () => {
    enforce(item.name).isNotEmpty();
  });
});

const mainSuite = create("mainSuite", (data, field) => {
  only(field);

  test("a", "A != B", () => {
    enforce(data.a).equals(data.b);
  });

  itemSuite(data.innerItem, "innerItem");

  each(data.items, (item) => {
    itemSuite(item, `items.${item.guid}`);
  });
});

const result = mainSuite(
  {
    a: "a",
    b: "b",
    items: [
      { name: "", guid: 1 },
      { name: "", guid: 2 },
      { name: "test", guid: 3 },
    ],
    innerItem: {
      name: "",
    },
  },
  ["items.1.name", "innerItem.name"]
); // result.errorCount = 2

Would you advise devs to use this library this way?

@ealush
Copy link
Owner

ealush commented Mar 22, 2024

Hey @codrin-iftimie, sorry for responding late. I have been traveling.

Yes, your approach should work as expected, and most operations should work correctly when nesting suites this way.

only, omitWhen, and skipWhen, include should work with no problem. Querying and outputting these results should work as well.

By the way, this will work just the same if you simply use a function for your nested suite, and do not create an entire suite for that. Meaning, simply the callback of your sub suite is sufficient for this. It will be a little easier on performance.

In the future, I might add a few more features around the approach that you selected (creating two suites), but for now, these two approaches are identical in terms of functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants