diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/AsyncLayout.svelte b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/AsyncLayout.svelte new file mode 100644 index 0000000000..ac26e633ec --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/AsyncLayout.svelte @@ -0,0 +1,13 @@ + + +
Resolving a promise here: {await Promise.resolve('ok')}
+ + + {@render children?.()} + + {#snippet pending()} + loading... + {/snippet} + diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/DataLayout.svelte b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/DataLayout.svelte new file mode 100644 index 0000000000..8e2a0dc9cf --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/DataLayout.svelte @@ -0,0 +1,11 @@ + + +{@render children?.()} diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/Page.svelte b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/Page.svelte new file mode 100644 index 0000000000..62368b361d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/Page.svelte @@ -0,0 +1 @@ +
this is the child
diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/RootLayout.svelte b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/RootLayout.svelte new file mode 100644 index 0000000000..a49a739284 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/RootLayout.svelte @@ -0,0 +1,5 @@ + + +{@render children?.()} diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/_config.js b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/_config.js new file mode 100644 index 0000000000..14d2e0f04c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/_config.js @@ -0,0 +1,30 @@ +import { settled } from 'svelte'; +import { test } from '../../test'; + +// Regression test for https://github.com/sveltejs/kit/issues/17383 +export default test({ + mode: ['hydrate'], + skip_initial_flushSync: true, + + async test({ assert, target, component, mod, hydrate, logs }) { + const tree = mod.create_tree(); + const { data, child } = tree; + tree.data = {}; + tree.child = undefined; + component.tree = tree; + await Promise.resolve(); + + // Kit applies the loaded data to its existing root immediately before hydration. + // Do not flush these writes: the async boundary must encounter the pending batch. + tree.data = data; + tree.child = child; + hydrate(); + await settled(); + + assert.htmlEqual( + target.innerHTML, + '
Resolving a promise here: ok
this is the child
' + ); + assert.deepEqual(logs, ['root', 'child']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/main.svelte new file mode 100644 index 0000000000..a320f2469b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/main.svelte @@ -0,0 +1,94 @@ + + + + +{#snippet node(n, depth)} + {const Component = $derived(n.component)} + {const Error = $derived(n.error)} + {const data = $derived(n.data)} + + {#snippet failed(error)} + + {/snippet} + + + {#if n.child} + + {@render node(n.child, depth + 1)} + + {:else} + + {/if} + +{/snippet} + +{@render node(tree, 0)} diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/state.svelte.js b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/state.svelte.js new file mode 100644 index 0000000000..1c34cc0974 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydration-pre-mount-writes/state.svelte.js @@ -0,0 +1,21 @@ +export class RenderNode { + /** @type {any} */ + component; + + /** @type {any} */ + error; + + data = $state.raw({}); + + /** @type {RenderNode | undefined} */ + child = $state.raw(); + + /** + * @param {any} component + * @param {any} [error] + */ + constructor(component, error) { + this.component = component; + this.error = error; + } +}