diff --git a/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/_config.js b/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/_config.js new file mode 100644 index 0000000000..89d42b5b96 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/_config.js @@ -0,0 +1,37 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + await tick(); + const [x, y, shift] = target.querySelectorAll('button'); + + assert.deepEqual(logs, ['effect _ 0']); + + // write x — the batch is pending on its async expression + x.click(); + await tick(); + assert.deepEqual(logs, ['effect _ 0']); + + // the effect newly depends on `x` — it reads the held-back value (0) + // (at some point it read latest, but we decided against doing this) + y.click(); + await tick(); + assert.deepEqual(logs, ['effect _ 0', 'effect 0 1']); + + // the effect re-runs and no longer depends on `x` at all + y.click(); + await tick(); + assert.deepEqual(logs, ['effect _ 0', 'effect 0 1', 'effect _ 2']); + + // the pending batch settles and commits x = 1 — the effect no longer + // depends on `x`, so it should not re-run + shift.click(); + await tick(); + assert.deepEqual(logs, ['effect _ 0', 'effect 0 1', 'effect _ 2']); + assert.htmlEqual( + target.innerHTML, + '

1

' + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/main.svelte new file mode 100644 index 0000000000..4d9d616293 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-commit-stale-reader-dropped-dep/main.svelte @@ -0,0 +1,24 @@ + + +

{await delay(x)}

+ + + diff --git a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-3/_config.js b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-3/_config.js index c9e7513b22..868ae1f54f 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-3/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-3/_config.js @@ -2,7 +2,6 @@ import { tick } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971 async test({ assert, target }) { await tick(); const [a_b, a_c, b_d, shift, pop] = target.querySelectorAll('button'); @@ -63,12 +62,12 @@ export default test({ ` ); - pop.click(); // second b resolved, still pending: [b, a] + pop.click(); // second b resolved, still pending: [b, a] but b is now obsolete await tick(); assert.htmlEqual( target.innerHTML, ` - a 0 | b 0 | c 0 | d 0 + a 1 | b 2 | c 0 | d 1 @@ -79,18 +78,6 @@ export default test({ shift.click(); // first b resolved, first + last batch settled, still pending: [a] await tick(); - assert.htmlEqual( - target.innerHTML, - ` - a 1 | b 2 | c 0 | d 1 - - - - - - ` - ); - shift.click(); // all resolved await tick(); assert.htmlEqual( diff --git a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-4/_config.js b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-4/_config.js index 472a3ebcaf..fff23f68ef 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-4/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-4/_config.js @@ -2,7 +2,6 @@ import { tick } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971 async test({ assert, target }) { await tick(); const [a_b, a_c, b_d, shift, pop] = target.querySelectorAll('button'); @@ -63,12 +62,12 @@ export default test({ ` ); - pop.click(); // second b resolved, still pending: [b, a] + pop.click(); // second b resolved, still pending: [b, a] with b obsolete so can render some already await tick(); assert.htmlEqual( target.innerHTML, ` - a 0 | b 0 | c 0 | d 0 + a 1 | b 2 | c 0 | d 1 @@ -78,22 +77,6 @@ export default test({ ); pop.click(); // second a resolved, first a/b now obsolete - // TODO would be nice to show final result here already, right now it doesn't because - // we have no handle on the already resolved first a anymore - await tick(); - assert.htmlEqual( - target.innerHTML, - ` - a 0 | b 0 | c 0 | d 0 - - - - - - ` - ); - - shift.click(); // queue empty await tick(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js index 61360d8dc9..fd7bc40eed 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js @@ -2,7 +2,6 @@ import { tick } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, async test({ assert, target }) { await tick(); const [a_b_fork, a_c, b_d, shift, pop, commit] = target.querySelectorAll('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/_config.js b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/_config.js new file mode 100644 index 0000000000..c1acd5bce6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/_config.js @@ -0,0 +1,52 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [x, y, resolve] = target.querySelectorAll('button'); + + x.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

WORLD

+ ` + ); + + y.click(); + await tick(); + // the new branch reads `upper` — a derived of the source the pending batch + // wrote — as a new dependency. It renders with the pre-write value 'WORLD', + // as the pending batch's write is hidden from the batch that commits + assert.htmlEqual( + target.innerHTML, + ` + + + +

WORLD

+

WORLD

+ ` + ); + + resolve.click(); + await tick(); + // the pending batch discovers that the new branch depends on its write + // when it resumes, and commits it fully consistent + assert.htmlEqual( + target.innerHTML, + ` + + + +

UNIVERSE

+ universe +

UNIVERSE

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/main.svelte new file mode 100644 index 0000000000..aa95730425 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-5/main.svelte @@ -0,0 +1,29 @@ + + + + + + + + +

{upper}

+ +{#if x.x === 'universe'} + {await delay(x.x)} +{/if} + +{#if y > 0} +

{upper}

+{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-fork-4/_config.js b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-fork-4/_config.js index 6a6399a19e..a20f8c0ba5 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-fork-4/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-state-new-branch-fork-4/_config.js @@ -2,7 +2,6 @@ import { tick } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971 async test({ assert, target }) { const [x, y, resolve, commit] = target.querySelectorAll('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/_config.js b/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/_config.js new file mode 100644 index 0000000000..37c2f7e97c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/_config.js @@ -0,0 +1,30 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + async test({ assert, target }) { + await tick(); + const [update, show, resolve] = target.querySelectorAll('button'); + + update.click(); + await tick(); + + show.click(); + await tick(); + + // the template effect newly depends on `value`, which the pending batch + // has written — it reads the pre-write value and crashes + assert.htmlEqual( + target.innerHTML, + ` + + + +

crash

+ ` + ); + + resolve.click(); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/main.svelte new file mode 100644 index 0000000000..05db2f78dd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-read-new-dependency/main.svelte @@ -0,0 +1,22 @@ + + + + + + +{await wait(value)} + + +

{show ? value.x + value.x : ''}

+ {#snippet failed()} +

crash

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-29/_config.js b/packages/svelte/tests/runtime-runes/samples/error-boundary-29/_config.js new file mode 100644 index 0000000000..ef4e1203b1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-29/_config.js @@ -0,0 +1,14 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// A render effect in a branch that is created during traversal doesn't run right away (in async mode, +// it runs together with the other render effects of the batch), but its error is still caught by the boundary +export default test({ + mode: ['client'], + test({ assert, target }) { + const [show] = target.querySelectorAll('button'); + + flushSync(() => show.click()); + assert.htmlEqual(target.innerHTML, '

crash

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-29/main.svelte b/packages/svelte/tests/runtime-runes/samples/error-boundary-29/main.svelte new file mode 100644 index 0000000000..170bc308e3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-29/main.svelte @@ -0,0 +1,16 @@ + + + + +{#if show} + +

{value.x}

+ + {#snippet failed()} +

crash

+ {/snippet} +
+{/if}