airjp73 / rvf

Easy form validation and state management for React and Remix
https://rvf-js.io
MIT License
839 stars 66 forks source link

[Bug]: zod-form-data won't validate all fields at once when using safeParse #358

Open thdk opened 7 months ago

thdk commented 7 months ago

Which packages are impacted?

What version of these packages are you using?

"zod": "^3.22.4",
"zod-form-data": "^2.0.2"

Please provide a link to a minimal reproduction of the issue.

https://stackblitz.com/edit/vitest-dev-vitest-jswqx2?file=test%2Fbasic.test.ts

Steps to Reproduce the Bug or Issue

  import { describe, expect, test } from 'vitest';
  import { z } from 'zod';
  import { zfd } from 'zod-form-data';

  test('multiple fields should get validated at once', (v) => {
    const Schema = zfd.formData(
      z.object({
        field1: zfd.text(),
        field2: zfd.text(),
      })
    );

    const data = new FormData();
    data.append('field1', '');
    data.append('field2', '');

    const result = Schema.safeParse(data);

    expect(result.success).toBe(false);

    if (result.success) {
      throw new Error('Expected failure but got success');
    } else {
      const errors = result.error.flatten() as z.inferFlattenedErrors<
        typeof Schema
      >;

      // Both fields should have been validated but aren't
      expect.soft(errors.fieldErrors.field1).toEqual(['Required']);
      expect.soft(errors.fieldErrors.field2).toEqual(['Required']);
    }
  });

Expected behavior

When multiple fields are invalid, and the form data is parsed using z.safeParse then the result object should have an error property that contains the error information for both fields.

The actual result is that only the first field is validated. Next, when the first issue is solved by the user and resubmits the form, the error for the next field is shown.

Screenshots or Videos

No response

Platform

Additional context

No response

airjp73 commented 7 months ago

Thank you for the thorough reproduction! Definitely a weird bug. Interestingly, if you use safeParseAsync instead, that fixes it (code)? Hopefully that's a reasonable workaround for now as I'm not sure when I'll have time to investigate.

thdk commented 7 months ago

I was already using the validator from withZod as workaround which also worked.

const validator = withZod(schema);
const result = await validator.validate(data);

After your message I had a look into the source code of withZod which seems very similar to how I was using it myself except for the use of safeParseAsync instead of safeParse indeed. I'll revert my code and use safeParseAsync instead of my withZod workaround.

I have one issue left for which I will create a separate issue.