mirror of https://github.com/sveltejs/svelte
parent
6d3317f972
commit
06f7ec0e8a
@ -0,0 +1,39 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons =
|
||||
'<button>s</button><button>u</button><button>d</button><button>resolve a</button><button>resolve b</button><button>resolve c</button>';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target, logs }) {
|
||||
await tick();
|
||||
const [s, u, d, resolve_a, resolve_b, resolve_c] = target.querySelectorAll('button');
|
||||
|
||||
// batch A: `d` becomes 10, but is not evaluated yet (the `<span>` is deferred)
|
||||
s.click();
|
||||
await tick();
|
||||
|
||||
// batch B
|
||||
u.click();
|
||||
await tick();
|
||||
|
||||
// batch C overrides `d` while A and B are pending. This must not mark `d` as
|
||||
// clean, because the other batches haven't seen its new value (10) yet
|
||||
d.click();
|
||||
await tick();
|
||||
|
||||
// B sees A's change (but not C's), so `d` is 10 in its world
|
||||
resolve_b.click();
|
||||
await tick();
|
||||
assert.equal(logs[0], 'probe 10');
|
||||
|
||||
resolve_a.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>1</p><p>0</p><span>10</span><i>10</i>`);
|
||||
|
||||
resolve_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>1</p><p>1</p><span>99</span><i>99</i>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,42 @@
|
||||
<script>
|
||||
let s = $state(0);
|
||||
let u = $state(0);
|
||||
let w = $state(0);
|
||||
let show = $state(true);
|
||||
let d = $derived(s * 10);
|
||||
|
||||
const pending = new Map();
|
||||
|
||||
function delay(name, value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => pending.set(name, () => resolve(value)));
|
||||
}
|
||||
|
||||
function probe(value) {
|
||||
console.log(`probe ${value}`);
|
||||
return value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => s++}>s</button>
|
||||
<button onclick={() => u++}>u</button>
|
||||
<button
|
||||
onclick={() => {
|
||||
d = 99;
|
||||
w++;
|
||||
}}>d</button
|
||||
>
|
||||
<button onclick={() => pending.get('a')?.()}>resolve a</button>
|
||||
<button onclick={() => pending.get('b')?.()}>resolve b</button>
|
||||
<button onclick={() => pending.get('c')?.()}>resolve c</button>
|
||||
|
||||
<p>{await delay('a', s)}</p>
|
||||
<p>{await delay('c', w)}</p>
|
||||
<!-- inside a branch, so that B's traversal doesn't reach (and stash) the effect reading `d` -->
|
||||
{#if show}
|
||||
<span>{d}</span>
|
||||
{/if}
|
||||
|
||||
{#if await delay('b', u)}
|
||||
<i>{await probe(d)}</i>
|
||||
{/if}
|
||||
@ -0,0 +1,28 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons = `
|
||||
<button>update</button>
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
`;
|
||||
|
||||
// Same as `async-state-read-new-dependency`, but the branch is selected by an eager expression
|
||||
// Earlier we said the reader inside it must still see the latest value of `value` rather than `undefined`,
|
||||
// but that decision was adjusted, so this test now verifies the updated behavior.
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [update, show, resolve] = target.querySelectorAll('button');
|
||||
|
||||
update.click(); // pending batch writes `value`
|
||||
await tick();
|
||||
|
||||
show.click(); // eager flush creates the branch, which reads `value` for the first time and crashes
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>crash</p>`);
|
||||
|
||||
resolve.click();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
let value = $state();
|
||||
let show = $state(false);
|
||||
const deferred = Promise.withResolvers();
|
||||
|
||||
function wait(value) {
|
||||
return value === undefined ? '' : deferred.promise;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (value = { x: 1 })}>update</button>
|
||||
<button onclick={() => (show = true)}>show</button>
|
||||
<button onclick={() => deferred.resolve('')}>resolve</button>
|
||||
|
||||
{await wait(value)}
|
||||
|
||||
{#if $state.eager(show)}
|
||||
<svelte:boundary>
|
||||
<p>{value.x}</p>
|
||||
{#snippet failed()}
|
||||
<p>crash</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
{/if}
|
||||
@ -0,0 +1,22 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons = `<button>preload</button><button>other</button><button>commit</button>`;
|
||||
|
||||
// If a fork is auto-discarded it should not throw on user-commit.
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
const [preload, other, commit] = target.querySelectorAll('button');
|
||||
|
||||
preload.click();
|
||||
await tick();
|
||||
other.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>true 1</p>`);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>true 1</p>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
|
||||
let open = $state(true);
|
||||
let other = $state(0);
|
||||
let pending;
|
||||
let error = $state('');
|
||||
</script>
|
||||
|
||||
<button onclick={() => { pending ??= fork(() => { open = true; }); }}>preload</button>
|
||||
<button onclick={() => other++}>other</button>
|
||||
<button onclick={() => { pending.commit().catch((e) => (error = e.message)); pending = null; }}>commit</button>
|
||||
|
||||
<p>{open} {other} {error}</p>
|
||||
Loading…
Reference in new issue