Repository: sveltejs/kit
Pull request #7205 (2022-10-10 13:29:23)

Update dependency @rollup/plugin-node-resolve to v15
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@rollup/plugin-node-resolve](https://togithub.com/rollup/plugins/tree/master/packages/node-resolve/#readme) ([source](https://togithub.com/rollup/plugins)) | [`^14.1.0` -> `^15.0.0`](https://renovatebot.com/diffs/npm/@rollup%2fplugin-node-resolve/14.1.0/15.0.0) | [![age](https://badges.renovateapi.com/packages/npm/@rollup%2fplugin-node-resolve/15.0.0/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/npm/@rollup%2fplugin-node-resolve/15.0.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/npm/@rollup%2fplugin-node-resolve/15.0.0/compatibility-slim/14.1.0)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/npm/@rollup%2fplugin-node-resolve/15.0.0/confidence-slim/14.1.0)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>rollup/plugins</summary>

### [`v15.0.0`](https://togithub.com/rollup/plugins/blob/HEAD/packages/node-resolve/CHANGELOG.md#v1500)

[Compare Source](https://togithub.com/rollup/plugins/compare/509d0310ff12f6dec78df59585b55b4f0209af9a...8f1aea320bb43c16afe52bc44ed357746c8f9711)

*2022-10-10*

##### Breaking Changes

-   fix: prepare for Rollup 3 [#&#8203;1288](https://togithub.com/rollup/plugins/pull/1288)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/sveltejs/kit).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzMi4yMjguMSIsInVwZGF0ZWRJblZlciI6IjMyLjIyOC4xIn0=-->



Patch:
diff --git a/.changeset/hot-shoes-bow.md b/.changeset/hot-shoes-bow.md
new file mode 100644
index 000000000..5a3a6794a
--- /dev/null
+++ b/.changeset/hot-shoes-bow.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Fix parsing content-type header for actions
diff --git a/.changeset/rotten-trees-brush.md b/.changeset/rotten-trees-brush.md
new file mode 100644
index 000000000..5265a930e
--- /dev/null
+++ b/.changeset/rotten-trees-brush.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] reset form in use:enhance after successful submit
diff --git a/.changeset/rude-berries-rush.md b/.changeset/rude-berries-rush.md
new file mode 100644
index 000000000..c0ef80487
--- /dev/null
+++ b/.changeset/rude-berries-rush.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/amp': patch
+---
+
+Amend boilerplate to match current recommendations
diff --git a/.changeset/sharp-lies-grin.md b/.changeset/sharp-lies-grin.md
new file mode 100644
index 000000000..a75c5f53b
--- /dev/null
+++ b/.changeset/sharp-lies-grin.md
@@ -0,0 +1,5 @@
+---
+"@sveltejs/adapter-netlify": patch
+---
+
+[fix] clear out build directory when running `adapter-netlify`
diff --git a/.changeset/tame-mugs-teach.md b/.changeset/tame-mugs-teach.md
new file mode 100644
index 000000000..ef7f5bf67
--- /dev/null
+++ b/.changeset/tame-mugs-teach.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] auto-update commented PageError
diff --git a/documentation/docs/06-form-actions.md b/documentation/docs/06-form-actions.md
index d87effa24..401e09f14 100644
--- a/documentation/docs/06-form-actions.md
+++ b/documentation/docs/06-form-actions.md
@@ -134,7 +134,7 @@ export const actions = {
 
 #### Validation errors
 
-If the request couldn't be processed because of invalid data, you can return validation errors — along with the previously submitted form values — back to the user so that they can try again. The `invalid` function lets you return an HTTP status code (typically 400, in the case of validation errors) along with the data:
+If the request couldn't be processed because of invalid data, you can return validation errors — along with the previously submitted form values — back to the user so that they can try again. The `invalid` function lets you return an HTTP status code (typically 400 or 422, in the case of validation errors) along with the data:
 
 ```diff
 // @errors: 2339 2304
@@ -366,4 +366,4 @@ const response = await fetch(this.action, {
 
 ### Alternatives
 
-Form actions are the preferred way to send data to the server, since they can be progressively enhanced, but you can also use [`+server.js`](/docs/routing#server) files to expose (for example) a JSON API.
\ No newline at end of file
+Form actions are the preferred way to send data to the server, since they can be progressively enhanced, but you can also use [`+server.js`](/docs/routing#server) files to expose (for example) a JSON API.
diff --git a/package.json b/package.json
index 95178beaa..93ffa12d1 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
 		"@changesets/cli": "^2.22.0",
 		"@rollup/plugin-commonjs": "^23.0.0",
 		"@rollup/plugin-json": "^4.1.0",
-		"@rollup/plugin-node-resolve": "^14.1.0",
+		"@rollup/plugin-node-resolve": "^15.0.0",
 		"@svitejs/changesets-changelog-github-compact": "^0.1.1",
 		"playwright": "^1.25.0",
 		"prettier": "^2.6.2",
diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js
index 6d77b17a7..ac1db56c8 100644
--- a/packages/adapter-netlify/index.js
+++ b/packages/adapter-netlify/index.js
@@ -45,6 +45,7 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
 			const publish = get_publish_directory(netlify_config, builder) || 'build';
 
 			// empty out existing build directories
+			builder.rimraf(publish);
 			builder.rimraf('.netlify/edge-functions');
 			builder.rimraf('.netlify/functions-internal');
 			builder.rimraf('.netlify/server');
diff --git a/packages/adapter-netlify/package.json b/packages/adapter-netlify/package.json
index 3f07cf186..0919e7e15 100644
--- a/packages/adapter-netlify/package.json
+++ b/packages/adapter-netlify/package.json
@@ -40,7 +40,7 @@
 		"@netlify/functions": "^1.0.0",
 		"@rollup/plugin-commonjs": "^23.0.0",
 		"@rollup/plugin-json": "^4.1.0",
-		"@rollup/plugin-node-resolve": "^14.1.0",
+		"@rollup/plugin-node-resolve": "^15.0.0",
 		"@sveltejs/kit": "workspace:*",
 		"@types/node": "^16.11.36",
 		"@types/set-cookie-parser": "^2.4.2",
diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json
index 5c665ad2b..5333ab85d 100644
--- a/packages/adapter-node/package.json
+++ b/packages/adapter-node/package.json
@@ -44,7 +44,7 @@
 	"dependencies": {
 		"@rollup/plugin-commonjs": "^23.0.0",
 		"@rollup/plugin-json": "^4.1.0",
-		"@rollup/plugin-node-resolve": "^14.1.0",
+		"@rollup/plugin-node-resolve": "^15.0.0",
 		"rollup": "^2.78.1"
 	}
 }
diff --git a/packages/amp/index.js b/packages/amp/index.js
index 5b54cb891..41fb0c55a 100644
--- a/packages/amp/index.js
+++ b/packages/amp/index.js
@@ -1,8 +1,8 @@
 // https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate/
 const boilerplate = `
-	<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
-	<link rel="preload" as="script" href="https://cdn.ampproject.org/v0.js">
+	<link rel="preload" as="script" href="https://cdn.ampproject.org/v0.js" />
 	<script async src="https://cdn.ampproject.org/v0.js"></script>
+	<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
 `;
 
 /** @param {string} html */
diff --git a/packages/kit/src/core/sync/sync.js b/packages/kit/src/core/sync/sync.js
index ce7c8dccf..b1ba0fbb5 100644
--- a/packages/kit/src/core/sync/sync.js
+++ b/packages/kit/src/core/sync/sync.js
@@ -18,9 +18,17 @@ export function init(config, mode) {
 	if (fs.existsSync('src/app.d.ts')) {
 		const content = fs.readFileSync('src/app.d.ts', 'utf-8');
 		if (content.includes('PageError')) {
-			throw new Error(
-				'App.PageError has been renamed to App.Error — please update your src/app.d.ts'
-			);
+			if (content.includes('// interface PageError')) {
+				fs.writeFileSync(
+					'src/app.d.ts',
+					content.replace(/\/\/ interface PageError/g, '// interface Error')
+				);
+				console.warn('App.PageError has been renamed to App.Error — we updated your src/app.d.ts');
+			} else {
+				throw new Error(
+					'App.PageError has been renamed to App.Error — please update your src/app.d.ts'
+				);
+			}
 		}
 	}
 
diff --git a/packages/kit/src/runtime/app/forms.js b/packages/kit/src/runtime/app/forms.js
index b77770b96..4a93d633d 100644
--- a/packages/kit/src/runtime/app/forms.js
+++ b/packages/kit/src/runtime/app/forms.js
@@ -25,6 +25,7 @@ export function enhance(form, submit = () => {}) {
 	 */
 	const fallback_callback = async ({ action, result }) => {
 		if (result.type === 'success') {
+			form.reset();
 			await invalidateAll();
 		}
 
diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js
index 6f08b62f1..8eb14c6da 100644
--- a/packages/kit/src/runtime/server/index.js
+++ b/packages/kit/src/runtime/server/index.js
@@ -3,6 +3,7 @@ import { render_page } from './page/index.js';
 import { render_response } from './page/render.js';
 import { respond_with_error } from './page/respond_with_error.js';
 import { coalesce_to_error } from '../../utils/error.js';
+import { is_form_content_type } from '../../utils/http.js';
 import { GENERIC_ERROR, handle_fatal_error } from './utils.js';
 import { decode_params, disable_search, normalize_path } from '../../utils/url.js';
 import { exec } from '../../utils/routing.js';
@@ -24,12 +25,10 @@ export async function respond(request, options, state) {
 	let url = new URL(request.url);
 
 	if (options.csrf.check_origin) {
-		const type = request.headers.get('content-type')?.split(';')[0];
-
 		const forbidden =
 			request.method === 'POST' &&
 			request.headers.get('origin') !== url.origin &&
-			(type === 'application/x-www-form-urlencoded' || type === 'multipart/form-data');
+			is_form_content_type(request);
 
 		if (forbidden) {
 			return new Response(`Cross-site ${request.method} form submissions are forbidden`, {
diff --git a/packages/kit/src/runtime/server/page/actions.js b/packages/kit/src/runtime/server/page/actions.js
index 6f9507e87..02c038d5e 100644
--- a/packages/kit/src/runtime/server/page/actions.js
+++ b/packages/kit/src/runtime/server/page/actions.js
@@ -1,6 +1,6 @@
 import { error, json } from '../../../exports/index.js';
 import { normalize_error } from '../../../utils/error.js';
-import { negotiate } from '../../../utils/http.js';
+import { is_form_content_type, negotiate } from '../../../utils/http.js';
 import { HttpError, Redirect, ValidationError } from '../../control.js';
 import { handle_error_and_jsonify } from '../utils.js';
 
@@ -180,9 +180,10 @@ export async function call_action(event, actions) {
 		throw new Error(`No action with name '${name}' found`);
 	}
 
-	const type = event.request.headers.get('content-type')?.split('; ')[0];
-	if (type !== 'application/x-www-form-urlencoded' && type !== 'multipart/form-data') {
-		throw new Error(`Actions expect form-encoded data (received ${type})`);
+	if (!is_form_content_type(event.request)) {
+		throw new Error(
+			`Actions expect form-encoded data (received ${event.request.headers.get('content-type')}`
+		);
 	}
 
 	return action(event);
diff --git a/packages/kit/src/utils/http.js b/packages/kit/src/utils/http.js
index 434a0f1f8..31721d10c 100644
--- a/packages/kit/src/utils/http.js
+++ b/packages/kit/src/utils/http.js
@@ -53,3 +53,20 @@ export function negotiate(accept, types) {
 
 	return accepted;
 }
+
+/**
+ * Returns `true` if the request contains a `content-type` header with the given type
+ * @param {Request} request
+ * @param  {...string} types
+ */
+export function is_content_type(request, ...types) {
+	const type = request.headers.get('content-type')?.split(';', 1)[0].trim() ?? '';
+	return types.includes(type);
+}
+
+/**
+ * @param {Request} request
+ */
+export function is_form_content_type(request) {
+	return is_content_type(request, 'application/x-www-form-urlencoded', 'multipart/form-data');
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 29568f41c..da031a842 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7,7 +7,7 @@ importers:
       '@changesets/cli': ^2.22.0
       '@rollup/plugin-commonjs': ^23.0.0
       '@rollup/plugin-json': ^4.1.0
-      '@rollup/plugin-node-resolve': ^14.1.0
+      '@rollup/plugin-node-resolve': ^15.0.0
       '@svitejs/changesets-changelog-github-compact': ^0.1.1
       playwright: ^1.25.0
       prettier: ^2.6.2
@@ -20,7 +20,7 @@ importers:
       '@changesets/cli': 2.23.0
       '@rollup/plugin-commonjs': 23.0.0_rollup@2.78.1
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
-      '@rollup/plugin-node-resolve': 14.1.0_rollup@2.78.1
+      '@rollup/plugin-node-resolve': 15.0.0_rollup@2.78.1
       '@svitejs/changesets-changelog-github-compact': 0.1.1
       playwright: 1.25.0
       prettier: 2.7.1
@@ -85,7 +85,7 @@ importers:
       '@netlify/functions': ^1.0.0
       '@rollup/plugin-commonjs': ^23.0.0
       '@rollup/plugin-json': ^4.1.0
-      '@rollup/plugin-node-resolve': ^14.1.0
+      '@rollup/plugin-node-resolve': ^15.0.0
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       '@types/set-cookie-parser': ^2.4.2
@@ -103,7 +103,7 @@ importers:
       '@netlify/functions': 1.0.0
       '@rollup/plugin-commonjs': 23.0.0_rollup@2.78.1
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
-      '@rollup/plugin-node-resolve': 14.1.0_rollup@2.78.1
+      '@rollup/plugin-node-resolve': 15.0.0_rollup@2.78.1
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
       '@types/set-cookie-parser': 2.4.2
@@ -116,7 +116,7 @@ importers:
     specifiers:
       '@rollup/plugin-commonjs': ^23.0.0
       '@rollup/plugin-json': ^4.1.0
-      '@rollup/plugin-node-resolve': ^14.1.0
+      '@rollup/plugin-node-resolve': ^15.0.0
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       c8: ^7.11.3
@@ -129,7 +129,7 @@ importers:
     dependencies:
       '@rollup/plugin-commonjs': 23.0.0_rollup@2.78.1
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
-      '@rollup/plugin-node-resolve': 14.1.0_rollup@2.78.1
+      '@rollup/plugin-node-resolve': 15.0.0_rollup@2.78.1
       rollup: 2.78.1
     devDependencies:
       '@sveltejs/kit': link:../kit
@@ -1102,16 +1102,19 @@ packages:
       '@rollup/pluginutils': 3.1.0_rollup@2.78.1
       rollup: 2.78.1
 
-  /@rollup/plugin-node-resolve/14.1.0_rollup@2.78.1:
-    resolution: {integrity: sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==}
-    engines: {node: '>= 10.0.0'}
+  /@rollup/plugin-node-resolve/15.0.0_rollup@2.78.1:
+    resolution: {integrity: sha512-iwJbzfTzlzDDQcGmkS7EkCKwe2kSkdBrjX87Fy/KrNjr6UNnLpod0t6X66e502LRe5JJCA4FFqrEscWPnZAkig==}
+    engines: {node: '>=14.0.0'}
     peerDependencies:
-      rollup: ^2.78.0
+      rollup: ^2.78.0||^3.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
     dependencies:
-      '@rollup/pluginutils': 3.1.0_rollup@2.78.1
-      '@types/resolve': 1.17.1
+      '@rollup/pluginutils': 4.2.1
+      '@types/resolve': 1.20.2
       deepmerge: 4.2.2
-      is-builtin-module: 3.1.0
+      is-builtin-module: 3.2.0
       is-module: 1.0.0
       resolve: 1.22.1
       rollup: 2.78.1
@@ -1229,6 +1232,7 @@ packages:
 
   /@types/node/18.0.0:
     resolution: {integrity: sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==}
+    dev: true
 
   /@types/normalize-package-data/2.4.1:
     resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@@ -1248,10 +1252,8 @@ packages:
     resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
     dev: true
 
-  /@types/resolve/1.17.1:
-    resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
-    dependencies:
-      '@types/node': 18.0.0
+  /@types/resolve/1.20.2:
+    resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
 
   /@types/sade/1.7.4:
     resolution: {integrity: sha512-6ys13kmtlY0aIOz4KtMdeBD9BHs6vSE3aRcj4vAZqXjypT2el8WZt6799CMjElVgh1cbOH/t3vrpQ4IpwytcPA==}
@@ -2617,8 +2619,8 @@ packages:
       has-tostringtag: 1.0.0
     dev: true
 
-  /is-builtin-module/3.1.0:
-    resolution: {integrity: sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==}
+  /is-builtin-module/3.2.0:
+    resolution: {integrity: sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==}
     engines: {node: '>=6'}
     dependencies:
       builtin-modules: 3.3.0


Test patch:
diff --git a/packages/kit/test/apps/basics/src/routes/actions/success-data/+page.svelte b/packages/kit/test/apps/basics/src/routes/actions/success-data/+page.svelte
index e3699100e..e784d2b20 100644
--- a/packages/kit/test/apps/basics/src/routes/actions/success-data/+page.svelte
+++ b/packages/kit/test/apps/basics/src/routes/actions/success-data/+page.svelte
@@ -2,10 +2,12 @@
 	/** @type {import('./$types').ActionData} */
 	export let form;
 
-	async function submit() {
+	async function submit({ submitter }) {
 		const res = await fetch(this.action, {
 			method: 'POST',
-			body: new FormData(this),
+			body: submitter.getAttribute('formenctype') === 'multipart/form-data'
+				? new FormData(this)
+				: new URLSearchParams({ username: this['username'].value }),
 			headers: {
 				accept: 'application/json'
 			}
@@ -19,5 +21,6 @@
 
 <form method="post" on:submit|preventDefault={submit}>
 	<input name="username" type="text" />
-	<button>Submit</button>
+	<button formenctype="multipart/form-data">Submit</button>
+	<button formenctype="application/x-www-form-urlencoded">Submit</button>
 </form>
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index 93816939b..e563c01ca 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -1773,7 +1773,7 @@ test.describe('Actions', () => {
 		}
 	});
 
-	test('Success data is returned', async ({ page }) => {
+	test('Success data as form-data is returned', async ({ page }) => {
 		await page.goto('/actions/success-data');
 
 		expect(await page.textContent('pre')).toBe(JSON.stringify(null));
@@ -1781,12 +1781,26 @@ test.describe('Actions', () => {
 		await page.type('input[name="username"]', 'foo');
 		await Promise.all([
 			page.waitForRequest((request) => request.url().includes('/actions/success-data')),
-			page.click('button')
+			page.click('button[formenctype="multipart/form-data"]')
 		]);
 
 		await expect(page.locator('pre')).toHaveText(JSON.stringify({ result: 'foo' }));
 	});
 
+	test('Success data as form-urlencoded is returned', async ({ page }) => {
+		await page.goto('/actions/success-data');
+
+		expect(await page.textContent('pre')).toBe(JSON.stringify(null));
+
+		await page.type('input[name="username"]', 'bar');
+		await Promise.all([
+			page.waitForRequest((request) => request.url().includes('/actions/success-data')),
+			page.click('button[formenctype="application/x-www-form-urlencoded"]')
+		]);
+
+		await expect(page.locator('pre')).toHaveText(JSON.stringify({ result: 'bar' }));
+	});
+
 	test('applyAction updates form prop', async ({ page, javaScriptEnabled }) => {
 		await page.goto('/actions/update-form');
 		expect(await page.textContent('pre')).toBe(JSON.stringify(null));
@@ -1859,6 +1873,7 @@ test.describe('Actions', () => {
 
 		await expect(page.locator('pre.formdata1')).toHaveText(JSON.stringify({ result: 'foo' }));
 		await expect(page.locator('pre.formdata2')).toHaveText(JSON.stringify({ result: 'foo' }));
+		await expect(page.locator('input[name=username]')).toHaveValue('');
 	});
 
 	test('use:enhance abort controller', async ({ page, javaScriptEnabled }) => {