diff --git a/.changeset/large-dodos-bathe.md b/.changeset/large-dodos-bathe.md new file mode 100644 index 00000000000..eff5711fc5d --- /dev/null +++ b/.changeset/large-dodos-bathe.md @@ -0,0 +1,5 @@ +--- +"@remix-run/node": patch +--- + +- Upgrade to [`@remix-run/web-fetch@4.3.5`](https://github.com/remix-run/web-std-io/releases/tag/%40remix-run%2Fweb-fetch%404.3.5). Submitted empty file inputs are now correctly parsed out as empty `File` instances instead of being surfaced as an empty string via `request.formData()` diff --git a/integration/form-test.ts b/integration/form-test.ts index 9c0e5391a8f..7df40ad60af 100644 --- a/integration/form-test.ts +++ b/integration/form-test.ts @@ -392,6 +392,39 @@ test.describe("Forms", () => { } `, + "app/routes/empty-file-upload.jsx": js` + import { json } from "@remix-run/server-runtime"; + import { Form, useActionData } from "@remix-run/react"; + + export async function action({ request }) { + let formData = await request.formData(); + return json({ + text: formData.get('text'), + file: { + name: formData.get('file').name, + size: formData.get('file').size, + }, + fileMultiple: formData.getAll('fileMultiple').map(f => ({ + name: f.name, + size: f.size, + })), + }) + } + + export default function() { + const actionData = useActionData(); + return ( +
+ + + + + {actionData ?

{JSON.stringify(actionData)}

: null} +
+ ) + } + `, + // Generic route for outputting url-encoded form data (either from the request body or search params) // // TODO: refactor other tests to use this @@ -1065,6 +1098,19 @@ test.describe("Forms", () => { ); }); + test("empty file inputs resolve to File objects on the server", async ({ + page, + }) => { + let app = new PlaywrightFixture(appFixture, page); + + await app.goto("/empty-file-upload"); + await app.clickSubmitButton("/empty-file-upload"); + await page.waitForSelector("#action-data"); + expect((await app.getElement("#action-data")).text()).toContain( + '{"text":"","file":{"name":"","size":0},"fileMultiple":[{"name":"","size":0}]}' + ); + }); + test("pathless layout routes are ignored in form actions", async ({ page, }) => { diff --git a/packages/remix-node/package.json b/packages/remix-node/package.json index 3c6f4b275db..887ec4b2641 100644 --- a/packages/remix-node/package.json +++ b/packages/remix-node/package.json @@ -18,7 +18,7 @@ ], "dependencies": { "@remix-run/server-runtime": "1.18.1", - "@remix-run/web-fetch": "^4.3.4", + "@remix-run/web-fetch": "^4.3.5", "@remix-run/web-file": "^3.0.2", "@remix-run/web-stream": "^1.0.3", "@web3-storage/multipart-parser": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 99296618282..18759e070c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2602,10 +2602,10 @@ "@remix-run/web-stream" "^1.0.0" web-encoding "1.1.5" -"@remix-run/web-fetch@^4.3.4": - version "4.3.4" - resolved "https://registry.npmjs.org/@remix-run/web-fetch/-/web-fetch-4.3.4.tgz#6149582fa2199b8e2a35d4e653ba05772bd0e675" - integrity sha512-AUM1XBa4hcgeNt2CD86OlB5aDLlqdMl0uJ+89R8dPGx07I5BwMXnbopCaPAkvSBIoHeT/IoLWIuZrLi7RvXS+Q== +"@remix-run/web-fetch@^4.3.5": + version "4.3.5" + resolved "https://registry.npmjs.org/@remix-run/web-fetch/-/web-fetch-4.3.5.tgz#10e23082477e56ff496e4f02899a0389cdd249c9" + integrity sha512-cLLeNLvLRyFRhJLulzS98bb07kJ+ENkGaqUkBisdG4FNEoZF6tXtrTGLWJNJa1nAP/wFkMKEDxIP77LgAPyeow== dependencies: "@remix-run/web-blob" "^3.0.4" "@remix-run/web-form-data" "^3.0.3"