mirror of https://github.com/sveltejs/svelte
parent
ba4d37a4b4
commit
7005aae212
@ -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>
|
||||
@ -0,0 +1,42 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons = `
|
||||
<button>fork</button>
|
||||
<button>x = 5</button>
|
||||
<button>commit</button>
|
||||
<button>shift</button>
|
||||
`;
|
||||
|
||||
// A fork writes `x`, then the real world writes `x` as well (with async work still pending).
|
||||
// The fork's write is overtaken and it has nothing left to commit — `commit()` must resolve
|
||||
// rather than throw `fork_discarded`, and the real world's value wins
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [fork, x5, commit, shift] = target.querySelectorAll('button');
|
||||
|
||||
fork.click(); // speculative: delay(10)
|
||||
await tick();
|
||||
x5.click(); // real: delay(5); the fork adopts x = 5 and re-runs: delay(5)
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
|
||||
|
||||
shift.click(); // the fork's obsolete delay(10)
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
|
||||
|
||||
shift.click(); // the real delay(5)
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>5</p>`);
|
||||
|
||||
shift.click(); // the fork's delay(5), rejected when the fork was cleaned up
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>5</p>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
|
||||
let x = $state(0);
|
||||
let f;
|
||||
let error = $state('');
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value === 0) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => { f = fork(() => { x = 10; }); }}>fork</button>
|
||||
<button onclick={() => (x = 5)}>x = 5</button>
|
||||
<button onclick={() => { f.commit().catch((e) => (error = e.message)); }}>commit</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
|
||||
<p>{await delay(x)} {error}</p>
|
||||
@ -0,0 +1,49 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons = `
|
||||
<button>A0</button>
|
||||
<button>A</button>
|
||||
<button>B</button>
|
||||
<button>resolve q</button>
|
||||
<button>resolve p</button>
|
||||
<button>resolve t</button>
|
||||
<button>resolve r</button>
|
||||
<button>init</button>
|
||||
`;
|
||||
|
||||
// Test ensure dependencies on earlier batches are also merged correctly
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const [A0, A, B, resolve_q, resolve_p, resolve_t, resolve_r, init] =
|
||||
target.querySelectorAll('button');
|
||||
|
||||
init.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>q0 r0 p0 t0 s0</p>`);
|
||||
|
||||
A0.click(); // q=1, r=1 -> slow(q=1), slow(r=1)
|
||||
await tick();
|
||||
A.click(); // q=2, p=1, s=1 -> slow(q=2), slow(p=1); depends on A0
|
||||
await tick();
|
||||
B.click(); // s=2, t=1 -> slow(t=1); depends on A
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>q0 r0 p0 t0 s0</p>`);
|
||||
|
||||
// A's runs resolve -> A merges into A0, which is still waiting on slow(r=1)
|
||||
resolve_q.click();
|
||||
resolve_p.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>q0 r0 p0 t0 s0</p>`);
|
||||
|
||||
// B's run resolves -> B must wait for A0
|
||||
resolve_t.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>q0 r0 p0 t0 s0</p>`);
|
||||
|
||||
// A0's run resolves -> everything commits at once
|
||||
resolve_r.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>q2 r1 p1 t1 s2</p>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
<script>
|
||||
let q = $state(0);
|
||||
let r = $state(0);
|
||||
let p = $state(0);
|
||||
let s = $state(0);
|
||||
let t = $state(0);
|
||||
|
||||
const resolvers = { q: [], r: [], p: [], t: [] };
|
||||
|
||||
function slow(kind, v) {
|
||||
return new Promise((resolve) => resolvers[kind].push(() => resolve(v)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => { q++; r++; }}>A0</button>
|
||||
<button onclick={() => { q++; p++; s++; }}>A</button>
|
||||
<button onclick={() => { s++; t++; }}>B</button>
|
||||
<button onclick={() => resolvers.q.pop()?.()}>resolve q</button>
|
||||
<button onclick={() => resolvers.p.pop()?.()}>resolve p</button>
|
||||
<button onclick={() => resolvers.t.pop()?.()}>resolve t</button>
|
||||
<button onclick={() => resolvers.r.shift()?.()}>resolve r</button>
|
||||
<button onclick={() => { for (const k in resolvers) resolvers[k].shift()?.(); }}>init</button>
|
||||
|
||||
<svelte:boundary>
|
||||
{#snippet pending()}loading{/snippet}
|
||||
<p>q{await slow('q', q)} r{await slow('r', r)} p{await slow('p', p)} t{await slow('t', t)} s{s}</p>
|
||||
</svelte:boundary>
|
||||
Loading…
Reference in new issue