chore: More flaky test fixes (#15020)
authorElliott Johnson <elliott.johnson@vercel.com>
Wed, 3 Dec 2025 18:13:24 +0000 (11:13 -0700)
committerGitHub <noreply@github.com>
Wed, 3 Dec 2025 18:13:24 +0000 (11:13 -0700)
* fix fast-running test

* fix: form remote function test contention

packages/kit/test/apps/basics/src/routes/remote/form/[test_name]/+page.svelte [moved from packages/kit/test/apps/basics/src/routes/remote/form/+page.svelte with 63% similarity]
packages/kit/test/apps/basics/src/routes/remote/form/[test_name]/form.remote.ts [new file with mode: 0644]
packages/kit/test/apps/basics/src/routes/remote/form/form.remote.ts [deleted file]
packages/kit/test/apps/basics/src/routes/remote/form/imperative/+page.svelte
packages/kit/test/apps/basics/src/routes/routing/hashes/target/+page.svelte
packages/kit/test/apps/basics/test/cross-platform/test.js
packages/kit/test/apps/basics/test/test.js

similarity index 63%
rename from packages/kit/test/apps/basics/src/routes/remote/form/+page.svelte
rename to packages/kit/test/apps/basics/src/routes/remote/form/[test_name]/+page.svelte
index 33f931628aa1964b58f8c242dcef0eb3fbfc5607..9607ab161ce567f2bab4e107d42b33091925adf3 100644 (file)
@@ -6,10 +6,12 @@
                set_reverse_message
        } from './form.remote.js';
 
-       const message = get_message();
+       const { params } = $props();
 
-       const scoped = set_message.for('scoped');
-       const enhanced = set_message.for('enhanced');
+       const message = get_message(params.test_name);
+
+       const scoped = set_message.for(`scoped:${params.test_name}`);
+       const enhanced = set_message.for(`enhanced:${params.test_name}`);
 </script>
 
 <p>message.current: {message.current}</p>
        {/if}
 
        <input {...set_message.fields.message.as('text')} />
+       <input {...set_message.fields.test_name.as('hidden', params.test_name)} />
+       <!--
+        NOTE: there really probably should be a `set_reverse_message' test_name hidden field here, but it collides with the one above.
+        This kind of lines up with our discussions from earlier where we were talking about needing to include the RF hash in the field name.
+        If we do that and this test starts failing, all we'll need to do is add the hidden field back in.
+       -->
        <button>set message</button>
        <button {...set_reverse_message.buttonProps}>set reverse message</button>
 </form>
@@ -44,6 +52,7 @@
        {/if}
 
        <input {...scoped.fields.message.as('text')} />
+       <input {...scoped.fields.test_name.as('hidden', params.test_name)} />
        <button>set scoped message</button>
 </form>
 
@@ -56,7 +65,9 @@
 <form
        data-enhanced
        {...enhanced.enhance(async ({ data, submit }) => {
-               await submit().updates(get_message().withOverride(() => data.message + ' (override)'));
+               await submit().updates(
+                       get_message(params.test_name).withOverride(() => data.message + ' (override)')
+               );
        })}
 >
        {#if enhanced.fields.message.issues()}
@@ -64,6 +75,7 @@
        {/if}
 
        <input {...enhanced.fields.message.as('text')} />
+       <input {...enhanced.fields.test_name.as('hidden', params.test_name)} />
        <button><span>set enhanced message</span></button>
 </form>
 
@@ -75,4 +87,5 @@
 
 <form {...resolve_deferreds}>
        <button>resolve deferreds</button>
+       <input {...resolve_deferreds.fields.test_name.as('hidden', params.test_name)} />
 </form>
diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/[test_name]/form.remote.ts b/packages/kit/test/apps/basics/src/routes/remote/form/[test_name]/form.remote.ts
new file mode 100644 (file)
index 0000000..8a0d860
--- /dev/null
@@ -0,0 +1,71 @@
+import { form, getRequestEvent, query } from '$app/server';
+import { error, redirect } from '@sveltejs/kit';
+import * as v from 'valibot';
+
+const instances = new Map<
+       string,
+       { message: string; deferreds: Array<PromiseWithResolvers<void>> }
+>();
+
+export const get_message = query(v.string(), (test_name) => {
+       return instances.get(test_name)?.message || 'initial';
+});
+
+export const set_message = form(
+       v.object({
+               test_name: v.string(),
+               id: v.optional(v.string()),
+               message: v.picklist(
+                       ['hello', 'goodbye', 'unexpected error', 'expected error', 'redirect'],
+                       'message is invalid'
+               ),
+               uppercase: v.optional(v.string())
+       }),
+       async (data) => {
+               if (data.message === 'unexpected error') {
+                       throw new Error('oops');
+               }
+
+               if (data.message === 'expected error') {
+                       error(500, 'oops');
+               }
+
+               if (data.message === 'redirect') {
+                       redirect(303, '/remote');
+               }
+
+               const instance = instances.get(data.test_name) ?? { message: 'initial', deferreds: [] };
+               instances.set(data.test_name, instance);
+
+               instance.message = data.uppercase === 'true' ? data.message.toUpperCase() : data.message;
+
+               if (getRequestEvent().isRemoteRequest) {
+                       const deferred = Promise.withResolvers<void>();
+                       instance.deferreds.push(deferred);
+                       await deferred.promise;
+               }
+
+               return instance.message + (data.id ? ` (from: ${data.id})` : '');
+       }
+);
+
+export const set_reverse_message = form(
+       v.object({ test_name: v.string(), message: v.string() }),
+       (data) => {
+               const instance = instances.get(data.test_name) ?? { message: 'initial', deferreds: [] };
+               instances.set(data.test_name, instance);
+               instance.message = data.message.split('').reverse().join('');
+               return instance.message;
+       }
+);
+
+export const resolve_deferreds = form(v.object({ test_name: v.string() }), async (data) => {
+       const instance = instances.get(data.test_name);
+       if (!instance) return;
+
+       const { deferreds } = instance;
+       for (const deferred of deferreds) {
+               deferred.resolve();
+       }
+       deferreds.length = 0;
+});
diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/form.remote.ts b/packages/kit/test/apps/basics/src/routes/remote/form/form.remote.ts
deleted file mode 100644 (file)
index 83a29f0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-import { form, getRequestEvent, query } from '$app/server';
-import { error, redirect } from '@sveltejs/kit';
-import * as v from 'valibot';
-
-let message = 'initial';
-const deferreds = [];
-
-export const get_message = query(() => {
-       return message;
-});
-
-export const set_message = form(
-       v.object({
-               id: v.optional(v.string()),
-               message: v.picklist(
-                       ['hello', 'goodbye', 'unexpected error', 'expected error', 'redirect'],
-                       'message is invalid'
-               ),
-               uppercase: v.optional(v.string())
-       }),
-       async (data) => {
-               if (data.message === 'unexpected error') {
-                       throw new Error('oops');
-               }
-
-               if (data.message === 'expected error') {
-                       error(500, 'oops');
-               }
-
-               if (data.message === 'redirect') {
-                       redirect(303, '/remote');
-               }
-
-               message = data.uppercase === 'true' ? data.message.toUpperCase() : data.message;
-
-               if (getRequestEvent().isRemoteRequest) {
-                       const deferred = Promise.withResolvers();
-                       deferreds.push(deferred);
-                       await deferred.promise;
-               }
-
-               return message + (data.id ? ` (from: ${data.id})` : '');
-       }
-);
-
-export const set_reverse_message = form(v.object({ message: v.string() }), (data) => {
-       message = data.message.split('').reverse().join('');
-       return message;
-});
-
-export const resolve_deferreds = form(async () => {
-       for (const deferred of deferreds) {
-               deferred.resolve();
-       }
-       deferreds.length = 0;
-});
index c21e4d146af3e91e9847ad8934afc8d4f63bb485..14e4a86ed75cb3802c20206cf3be2512043ff9df 100644 (file)
@@ -1,8 +1,9 @@
 <script lang="ts">
-       import { set_message } from '../form.remote.js';
+       import { set_message } from '../[test_name]/form.remote.js';
        import * as v from 'valibot';
 
        const schema = v.object({
+               test_name: v.string(),
                message: v.picklist(
                        ['hello', 'goodbye', 'unexpected error', 'expected error', 'redirect'],
                        'message is invalid'
@@ -14,6 +15,7 @@
        <label>
                <span>Message</span>
                <input {...set_message.fields.message.as('text')} />
+               <input {...set_message.fields.test_name.as('hidden', 'imperative')} />
        </label>
 
        <p id="issue">
index 245993b8223945c114ddccc9f5a62cebd2f7cd80..d59c3cb2a25c6b101fd2a6879759d411cc785d18 100644 (file)
@@ -3,8 +3,8 @@
        <li><a href="#p2">second paragraph</a></li>
 </ol>
 
-<p id="p1">paragraph 1</p>
-<p id="p2">paragraph 2</p>
+<p tabindex="-1" id="p1">paragraph 1</p>
+<p tabindex="-1" id="p2">paragraph 2</p>
 
 <li><button>next focus element</button></li>
 
index d9bd0a9293480bbf1f7b6e3a1b199ce7479f40fb..c0e73da6df6c728cfdbf09a2e0d6bddbc9b197ca 100644 (file)
@@ -787,8 +787,8 @@ test.describe('Routing', () => {
        test('focus works if page load has hash', async ({ page, browserName }) => {
                await page.goto('/routing/hashes/target#p2');
 
+               await page.waitForSelector('#p2:focus');
                await page.keyboard.press(browserName === 'webkit' ? 'Alt+Tab' : 'Tab');
-
                await page.waitForSelector('button:focus');
        });
 
index f464265b9a31dc2ebf04d38f3228f86e3ffc1113..554a4d8ba59dfed6339dbc29aafe5a671281e848 100644 (file)
@@ -1659,7 +1659,7 @@ test.describe('remote functions', () => {
        });
 
        test('form works', async ({ page, javaScriptEnabled }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/basic');
 
                if (javaScriptEnabled) {
                        // TODO remove the `if` — once async SSR lands these assertions should always succeed
@@ -1682,7 +1682,7 @@ test.describe('remote functions', () => {
                }
 
                await expect(page.getByText('set_message.result')).toHaveText('set_message.result: hello');
-               await expect(page.locator('[data-unscoped] input')).toHaveValue('');
+               await expect(page.locator('[data-unscoped] input[name="message"]')).toHaveValue('');
        });
 
        test('form submitters work', async ({ page }) => {
@@ -1694,7 +1694,7 @@ test.describe('remote functions', () => {
        });
 
        test('form updates inputs live', async ({ page, javaScriptEnabled }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/live-update');
 
                await page.fill('input', 'hello');
 
@@ -1716,7 +1716,7 @@ test.describe('remote functions', () => {
        });
 
        test('form reports validation issues', async ({ page }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/validation-issues');
 
                await page.fill('input', 'invalid');
                await page.getByText('set message').click();
@@ -1725,7 +1725,7 @@ test.describe('remote functions', () => {
        });
 
        test('form handles unexpected error', async ({ page }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/unexpected-error');
 
                await page.fill('input', 'unexpected error');
                await page.getByText('set message').click();
@@ -1736,7 +1736,7 @@ test.describe('remote functions', () => {
        });
 
        test('form handles expected error', async ({ page }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/expected-error');
 
                await page.fill('input', 'expected error');
                await page.getByText('set message').click();
@@ -1745,7 +1745,7 @@ test.describe('remote functions', () => {
        });
 
        test('form redirects', async ({ page }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/redirect');
 
                await page.fill('input', 'redirect');
                await page.getByText('set message').click();
@@ -1754,7 +1754,7 @@ test.describe('remote functions', () => {
        });
 
        test('form.buttonProps works', async ({ page, javaScriptEnabled }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/button-props');
 
                await page.fill('[data-unscoped] input', 'backwards');
                await page.getByText('set reverse message').click();
@@ -1772,7 +1772,7 @@ test.describe('remote functions', () => {
        });
 
        test('form scoping with for(...) works', async ({ page, javaScriptEnabled }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/form-scoped');
 
                await page.fill('[data-scoped] input', 'hello');
                await page.getByText('set scoped message').click();
@@ -1786,12 +1786,14 @@ test.describe('remote functions', () => {
                        await expect(page.getByText('await get_message():')).toHaveText('await get_message(): hello');
                }
 
-               await expect(page.getByText('scoped.result')).toHaveText('scoped.result: hello (from: scoped)');
-               await expect(page.locator('[data-scoped] input')).toHaveValue('');
+               await expect(page.getByText('scoped.result')).toHaveText(
+                       'scoped.result: hello (from: scoped:form-scoped)'
+               );
+               await expect(page.locator('[data-scoped] input[name="message"]')).toHaveValue('');
        });
 
        test('form enhance(...) works', async ({ page, javaScriptEnabled }) => {
-               await page.goto('/remote/form');
+               await page.goto('/remote/form/enhanced');
 
                await page.fill('[data-enhanced] input', 'hello');
 
@@ -1808,13 +1810,13 @@ test.describe('remote functions', () => {
                        await expect(page.getByText('await get_message():')).toHaveText('await get_message(): hello');
 
                        // enhanced submission should not clear the input; the developer must do that at the appropriate time
-                       await expect(page.locator('[data-enhanced] input')).toHaveValue('hello');
+                       await expect(page.locator('[data-enhanced] input[name="message"]')).toHaveValue('hello');
                } else {
-                       await expect(page.locator('[data-enhanced] input')).toHaveValue('');
+                       await expect(page.locator('[data-enhanced] input[name="message"]')).toHaveValue('');
                }
 
                await expect(page.getByText('enhanced.result')).toHaveText(
-                       'enhanced.result: hello (from: enhanced)'
+                       'enhanced.result: hello (from: enhanced:enhanced)'
                );
        });