From 1b964dce938573ef7063d658fac0ca60a37d8900 Mon Sep 17 00:00:00 2001 From: Billy Le Date: Thu, 8 Aug 2024 23:05:10 +0800 Subject: [PATCH] fix/actions-default-values: set default values from zod if FormData key is not present --- .changeset/nervous-garlics-beam.md | 5 ++ .../src/actions/runtime/virtual/server.ts | 15 ++++++ .../units/actions/form-data-to-object.test.js | 48 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 .changeset/nervous-garlics-beam.md diff --git a/.changeset/nervous-garlics-beam.md b/.changeset/nervous-garlics-beam.md new file mode 100644 index 0000000000000..6ba4b66ff95d3 --- /dev/null +++ b/.changeset/nervous-garlics-beam.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Set action input default values from zod if FormData key is not present diff --git a/packages/astro/src/actions/runtime/virtual/server.ts b/packages/astro/src/actions/runtime/virtual/server.ts index a711f10326fc1..2d3f2409abfc6 100644 --- a/packages/astro/src/actions/runtime/virtual/server.ts +++ b/packages/astro/src/actions/runtime/virtual/server.ts @@ -137,6 +137,21 @@ export function formDataToObject( while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable) { validator = validator._def.innerType; } + + // use zod default value when key is undefined + // else continue to get correct zod class + if(validator instanceof z.ZodDefault) { + if(!formData.has(key)) { + obj[key] = validator._def.defaultValue(); + continue; + } + + while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable) { + validator = validator._def.innerType; + } + } + + if (validator instanceof z.ZodBoolean) { obj[key] = formData.has(key); } else if (validator instanceof z.ZodArray) { diff --git a/packages/astro/test/units/actions/form-data-to-object.test.js b/packages/astro/test/units/actions/form-data-to-object.test.js index 6cce8f3d7df44..2728c31d0f38e 100644 --- a/packages/astro/test/units/actions/form-data-to-object.test.js +++ b/packages/astro/test/units/actions/form-data-to-object.test.js @@ -91,6 +91,37 @@ describe('formDataToObject', () => { assert.equal(res.age, null); }); + it('should handle zod default values', () => { + const formData = new FormData(); + + const input = z.object({ + name: z.string().default("test"), + email: z.string().default('test@test.test'), + favoriteNumbers: z.array(z.number()).default([1,2]) + }); + + const res = formDataToObject(formData, input); + assert.equal(res.name, 'test'); + assert.equal(res.email, 'test@test.test'); + assert.deepEqual(res.favoriteNumbers, [1, 2]); + }) + + it('should handle zod chaining of optional, default, and nullish values', () => { + const formData = new FormData(); + formData.set('email', 'test@test.test') + + const input = z.object({ + name: z.string().default("test").optional(), + email: z.string().optional().nullish(), + favoriteNumbers: z.array(z.number()).default([1,2]).nullish().optional() + }); + + const res = formDataToObject(formData, input); + assert.equal(res.name, 'test'); + assert.equal(res.email, 'test@test.test'); + assert.deepEqual(res.favoriteNumbers, [1, 2]) + }) + it('should handle File objects', () => { const formData = new FormData(); formData.set('file', new File([''], 'test.txt')); @@ -135,4 +166,21 @@ describe('formDataToObject', () => { assert.ok(Array.isArray(res.age), 'age is not an array'); assert.deepEqual(res.age.sort(), [25, 30, 35]); }); + + it('should handle an array of File objects', () => { + const formData = new FormData(); + const file1 = new File([''], 'test1.txt'); + const file2 = new File([''], 'test2.txt') + formData.append('files', file1); + formData.append('files', file2); + + const input = z.object({ + files: z.array(z.instanceof(File)) + }); + + const res = formDataToObject(formData, input); + + assert.equal(res.files instanceof Array, true); + assert.deepEqual(res.files, [file1, file2]) + }); });