diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/_config.js b/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/_config.js index 29d374deec..51b37781d7 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/_config.js @@ -6,24 +6,12 @@ import { test } from '../../test'; // before destroy_effects walks pending keys. export default test({ mode: ['client'], - async test({ assert, target }) { await tick(); - assert.htmlEqual( - target.innerHTML, - ` - - - -

A0/B0

-
12
- ` - ); - - const [startA, startB, settleB] = target.querySelectorAll('button'); + const [startA, startB, settleB, settleA] = target.querySelectorAll('button'); - // Batch A: add key 9, then block forever on gate A. + // Batch A: add key 9, then blocks on gate A. startA.click(); await tick(); @@ -32,17 +20,32 @@ export default test({ await tick(); // Settle B first so B commits while A is still pending. - // Without the fix this throws reading `.e` of undefined and leaves a/b stuck. + // Should not take the fast path in each block to clear state.items prematurely. settleB.click(); await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + + + +

A0/B0

+
12
+ ` + ); + // Settle A so empty array of B can be committed + settleA.click(); + await tick(); assert.htmlEqual( target.innerHTML, ` -

A0/B1

+ +

A1/B1

` ); diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/main.svelte index 68c3937c25..84786d1dff 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-each-controlled-empty-pending/main.svelte @@ -4,12 +4,13 @@ let tickA = $state(0); let tickB = $state(0); - // Two independent sources so the batches touch disjoint source sets - // and are not merged. - const items = $derived(extraKey === null ? base : [...base, extraKey]); + // Two independent sources so the batches touch disjoint source sets and are not merged. + const items = $derived(base.length ? extraKey === null ? base : [...base, extraKey] : []); /** @type {((value: string) => void) | undefined} */ let resolveB; + /** @type {((value: string) => void) | undefined} */ + let resolveA; /** * @param {string} name @@ -20,6 +21,7 @@ ? Promise.resolve(`${name}0`) : new Promise((r) => { if (name === 'B') resolveB = r; + else resolveA = r; }); const a = $derived(await gate('A', tickA)); @@ -38,11 +40,15 @@ function settleB() { resolveB?.('B1'); } + function settleA() { + resolveA?.('A1'); + } +

{a}/{b}