mirror of https://github.com/sveltejs/svelte
commit
2145510951
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: prevent hydration error on async `{@html ...}`
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: defer batch resolution until earlier intersecting batches have committed
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: properly invoke `iterator.return()` during reactivity loss check
|
||||
@ -0,0 +1,7 @@
|
||||
<h1>Hello</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
color: var(--color);
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,7 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
hmr: true
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
import Component from "./Component.svelte";
|
||||
</script>
|
||||
|
||||
<Component --color="red" />
|
||||
@ -0,0 +1,10 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['hydrate'],
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `<div><div><p>first test</p></div> other test</div>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
function firstTest() {
|
||||
return Promise.resolve('<p>first test</p>');
|
||||
}
|
||||
|
||||
function otherTest() {
|
||||
return Promise.resolve('other test');
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div>{@html await firstTest()}</div>
|
||||
{await otherTest()}
|
||||
</div>
|
||||
@ -0,0 +1,107 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a_b, a_c, b_d, shift, pop] = target.querySelectorAll('button');
|
||||
|
||||
a_b.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 1 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 2 | b 1 | c 1 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 2 | b 2 | c 1 | d 1
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {await delay(a)} | b {await delay(b)} | c {c} | d {d}
|
||||
<button onclick={() => {a++;b++;}}>
|
||||
a and b
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,82 @@
|
||||
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');
|
||||
|
||||
a_b.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click(); // second b resolved, blocked on first batch because a still pending
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
pop.click(); // second a resolved, first a/b now obsolete; empty queue
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 2 | b 2 | c 1 | d 1
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {await delay(a)} | b {await delay(b)} | c {c} | d {d}
|
||||
<button onclick={() => {a++;b++;}}>
|
||||
a and b
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,108 @@
|
||||
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');
|
||||
|
||||
a_b.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // first a resolved, still pending: [b, a, b]
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click(); // second b resolved, still pending: [b, a]
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
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
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // all resolved
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 2 | b 2 | c 1 | d 1
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {await delay(a)} | b {await delay(b)} | c {c} | d {d}
|
||||
<button onclick={() => {a++;b++;}}>
|
||||
a and b
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,110 @@
|
||||
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');
|
||||
|
||||
a_b.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // first a resolved, still pending: [b, a, b]
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click(); // second b resolved, still pending: [b, a]
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
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
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // queue empty
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 2 | b 2 | c 1 | d 1
|
||||
<button>a and b</button>
|
||||
<button>a and c</button>
|
||||
<button>b and d</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {await delay(a)} | b {await delay(b)} | c {c} | d {d}
|
||||
<button onclick={() => {a++;b++;}}>
|
||||
a and b
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,118 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a, c, shift, pop] = target.querySelectorAll('button');
|
||||
|
||||
a.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
// how it's on main
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 1 | d 1
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 2 | c 1 | d 3
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
// how it's on https://github.com/sveltejs/svelte/pull/17971
|
||||
// shift.click();
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 0 | b 0 | c 0 | d 0
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
|
||||
// shift.click();
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 1 | b 2 | c 0 | d 2
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
|
||||
// shift.click();
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 1 | b 2 | c 1 | d 3
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $derived(await delay(a * 2));
|
||||
let c = $state(0);
|
||||
let d = $derived(await delay(b + c));
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {a} | b {b} | c {c} | d {d}
|
||||
<button onclick={() => {a++;}}>
|
||||
a++
|
||||
</button>
|
||||
<button onclick={() => {c++;}}>
|
||||
c++
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,76 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a, c, shift, pop] = target.querySelectorAll('button');
|
||||
|
||||
a.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
// Although the second batch is eventually connected to the first one, we can't see that
|
||||
// at this point yet and so the second one flushes right away.
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 1 | d 1
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 1 | d 1
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 2 | c 1 | d 3
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $derived(await delay(a * 2));
|
||||
let c = $state(0);
|
||||
let d = $derived(await delay(b + c));
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {a} | b {b} | c {c} | d {d}
|
||||
<button onclick={() => {a++;}}>
|
||||
a++
|
||||
</button>
|
||||
<button onclick={() => {c++;}}>
|
||||
c++
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,129 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a, c, shift, pop] = target.querySelectorAll('button');
|
||||
|
||||
a.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // schedules second step of first batch and schedules rerun of second batch
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 0 | b 0 | c 0 | d 0
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
// how it's on main
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 2 | c 0 | d 2
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // obsolete second batch promise (already rejected)
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 2 | c 0 | d 2
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click(); // first batch resolves
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
a 1 | b 2 | c 1 | d 3
|
||||
<button>a++</button>
|
||||
<button>c++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
`
|
||||
);
|
||||
|
||||
// how it's on https://github.com/sveltejs/svelte/pull/17971
|
||||
// pop.click(); // second batch resolves but knows it needs to wait on first batch
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 0 | b 0 | c 0 | d 0
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
|
||||
// shift.click(); // obsolete second batch promise (already rejected)
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 0 | b 0 | c 0 | d 0
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
|
||||
// shift.click(); // first batch resolves, with it second can now resolve as well
|
||||
// await tick();
|
||||
// assert.htmlEqual(
|
||||
// target.innerHTML,
|
||||
// `
|
||||
// a 1 | b 2 | c 1 | d 3
|
||||
// <button>a++</button>
|
||||
// <button>c++</button>
|
||||
// <button>shift</button>
|
||||
// <button>pop</button>
|
||||
// `
|
||||
// );
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
let a = $state(0);
|
||||
let b = $derived(await delay(a * 2));
|
||||
let c = $state(0);
|
||||
let d = $derived(await delay(b + c));
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
a {a} | b {b} | c {c} | d {d}
|
||||
<button onclick={() => {a++;}}>
|
||||
a++
|
||||
</button>
|
||||
<button onclick={() => {c++;}}>
|
||||
c++
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
@ -0,0 +1,34 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a_b_fork, a_c, shift, pop, commit] = target.querySelectorAll('button');
|
||||
const [p] = target.querySelectorAll('p');
|
||||
|
||||
a_b_fork.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0');
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0');
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 0 | c 1');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 0 | c 1');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 0 | c 1');
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>a {await delay(a)} | b {await delay(b)} | c {c}</p>
|
||||
|
||||
<button onclick={() => {f = fork(() => {a++;b++;});}}>
|
||||
a and b (fork)
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit fork</button>
|
||||
@ -0,0 +1,42 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [a_b_fork, a_c, b_d, shift, pop, commit] = target.querySelectorAll('button');
|
||||
const [p] = target.querySelectorAll('p');
|
||||
|
||||
a_b_fork.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 1 | c 0 | d 1');
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>a {await delay(a)} | b {await delay(b)} | c {c} | d {d}</p>
|
||||
|
||||
<button onclick={() => {f = fork(() => {a++;b++;});}}>
|
||||
a and b (fork)
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit fork</button>
|
||||
@ -0,0 +1,43 @@
|
||||
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');
|
||||
const [p] = target.querySelectorAll('p');
|
||||
|
||||
a_b_fork.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
a_c.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
b_d.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 0 | c 1 | d 0');
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
|
||||
let a = $state(0);
|
||||
let b = $state(0);
|
||||
let c = $state(0);
|
||||
let d = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (!value) return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>a {await delay(a)} | b {await delay(b)} | c {c} | d {d}</p>
|
||||
|
||||
<button onclick={() => {f = fork(() => {a++;b++;});}}>
|
||||
a and b (fork)
|
||||
</button>
|
||||
<button onclick={() => {a++;c++;}}>
|
||||
a and c
|
||||
</button>
|
||||
<button onclick={() => {b++;d++;}}>
|
||||
b and d
|
||||
</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit fork</button>
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
console.log(x);
|
||||
$effect(() => console.log('$effect: '+ x))
|
||||
</script>
|
||||
|
||||
{x}
|
||||
@ -0,0 +1,38 @@
|
||||
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, logs }) {
|
||||
const [x, y, resolve] = target.querySelectorAll('button');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
` // if this shows world world - that would also be ok
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.deepEqual(logs, ['universe', 'universe', '$effect: universe', '$effect: universe']);
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,28 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let deferred = [];
|
||||
|
||||
function delay(s) {
|
||||
const d = Promise.withResolvers();
|
||||
deferred.push(() => d.resolve(s))
|
||||
return d.promise;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => x = 'universe'}>x</button>
|
||||
|
||||
<button onclick={() => y++}>y++</button>
|
||||
|
||||
<button onclick={() => deferred.shift()()}>resolve</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
{#if y > 0}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,49 @@
|
||||
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] = target.querySelectorAll('button');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<hr>
|
||||
` // if this shows world world "world" world world world "world" - then this would also be ok
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let deferred = [];
|
||||
|
||||
function delay(s) {
|
||||
const d = Promise.withResolvers();
|
||||
deferred.push(() => d.resolve(s))
|
||||
return d.promise;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => x = 'universe'}>x</button>
|
||||
|
||||
<button onclick={() => y++}>y++</button>
|
||||
|
||||
<button onclick={() => deferred.shift()()}>resolve</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,61 @@
|
||||
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] = target.querySelectorAll('button');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<hr>
|
||||
` // if this shows world world "world" world world world "world" - then this would also be ok
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,34 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (x = 'universe')}>x</button>
|
||||
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.pop()?.()}>resolve</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,171 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
skip: true, // TODO more combinations pass on https://github.com/sveltejs/svelte/pull/17971
|
||||
timeout: 20_000,
|
||||
async test({ assert, target }) {
|
||||
const [x, fork_x, y, fork_y, shift, pop, commit_x, commit_y, reset] =
|
||||
target.querySelectorAll('button');
|
||||
|
||||
const initial = `
|
||||
<button>x</button>
|
||||
<button>x (fork)</button>
|
||||
<button>y++</button>
|
||||
<button>y++ (fork)</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit x</button>
|
||||
<button>commit y</button>
|
||||
<button>reset</button>
|
||||
<hr>
|
||||
`;
|
||||
|
||||
const final = `
|
||||
<button>x</button>
|
||||
<button>x (fork)</button>
|
||||
<button>y++</button>
|
||||
<button>y++ (fork)</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit x</button>
|
||||
<button>commit y</button>
|
||||
<button>reset</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`;
|
||||
|
||||
/** @param {HTMLElement} button */
|
||||
async function click(button) {
|
||||
button.click();
|
||||
await tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate all permutations of an array.
|
||||
* @param {HTMLElement[]} actions
|
||||
* @returns {HTMLElement[][]}
|
||||
*/
|
||||
function permutations(actions) {
|
||||
if (actions.length <= 1) return [actions];
|
||||
|
||||
/** @type {HTMLElement[][]} */
|
||||
const result = [];
|
||||
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
const head = actions[i];
|
||||
const rest = actions.slice(0, i).concat(actions.slice(i + 1));
|
||||
for (const tail of permutations(rest)) {
|
||||
result.push([head, ...tail]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep only valid orders where fork commits happen after their fork action.
|
||||
* @param {HTMLElement[]} order
|
||||
*/
|
||||
function is_valid_order(order) {
|
||||
const x_fork_index = order.indexOf(fork_x);
|
||||
const commit_x_index = order.indexOf(commit_x);
|
||||
if (commit_x_index !== -1 && (x_fork_index === -1 || commit_x_index < x_fork_index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const y_fork_index = order.indexOf(fork_y);
|
||||
const commit_y_index = order.indexOf(commit_y);
|
||||
if (commit_y_index !== -1 && (y_fork_index === -1 || commit_y_index < y_fork_index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Four control scenarios:
|
||||
* - x direct, y direct
|
||||
* - x direct, y via fork+commit
|
||||
* - x via fork+commit, y direct
|
||||
* - x via fork+commit, y via fork+commit
|
||||
*/
|
||||
const control_scenarios = [
|
||||
[x, y],
|
||||
[x, fork_y, commit_y],
|
||||
[fork_x, commit_x, y],
|
||||
[fork_x, commit_x, fork_y, commit_y]
|
||||
];
|
||||
|
||||
const control_orders = control_scenarios.flatMap((scenario) =>
|
||||
permutations(scenario).filter(is_valid_order)
|
||||
);
|
||||
|
||||
/**
|
||||
* All shift/pop combinations for draining async work.
|
||||
* We click three times because this scenario can queue up to 3 deferred resolutions.
|
||||
*/
|
||||
const resolve_orders = [
|
||||
[shift, shift, shift],
|
||||
[shift, pop, pop],
|
||||
[pop, shift, shift],
|
||||
[pop, pop, pop]
|
||||
];
|
||||
|
||||
for (const controls of control_orders) {
|
||||
for (const resolves of resolve_orders) {
|
||||
for (const action of controls) {
|
||||
await click(action);
|
||||
}
|
||||
|
||||
for (const action of resolves) {
|
||||
await click(action);
|
||||
}
|
||||
|
||||
const failure_msg = `Failed for: ${controls
|
||||
.map((btn) => btn.textContent)
|
||||
.concat(...resolves.map((btn) => btn.textContent))
|
||||
.join(', ')}`;
|
||||
assert.htmlEqual(target.innerHTML, final, failure_msg);
|
||||
|
||||
await click(reset);
|
||||
assert.htmlEqual(target.innerHTML, initial, failure_msg);
|
||||
}
|
||||
}
|
||||
|
||||
const other_scenarios = [
|
||||
[x, shift, y, shift, shift],
|
||||
[x, shift, y, pop, pop],
|
||||
[fork_x, shift, y, shift, commit_x, shift],
|
||||
[fork_x, shift, y, pop, commit_x, pop],
|
||||
[y, shift, x, shift, shift],
|
||||
[y, shift, x, pop, pop],
|
||||
[fork_y, shift, x, shift, commit_y, shift],
|
||||
[fork_y, shift, x, pop, commit_y, pop]
|
||||
];
|
||||
|
||||
for (const scenario of other_scenarios) {
|
||||
for (const action of scenario) {
|
||||
await click(action);
|
||||
}
|
||||
|
||||
const failure_msg = `Failed for: ${scenario.map((btn) => btn.textContent).join(', ')}`;
|
||||
assert.htmlEqual(target.innerHTML, final, failure_msg);
|
||||
|
||||
await click(reset);
|
||||
assert.htmlEqual(target.innerHTML, initial, failure_msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,41 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let fx;
|
||||
let fy;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (x = 'universe')}>x</button>
|
||||
<button onclick={() => (fx = fork(() => {x = 'universe';}))}>x (fork)</button>
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => (fy = fork(() => {y++;}))}>y++ (fork)</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => fx.commit()}>commit x</button>
|
||||
<button onclick={() => fy.commit()}>commit y</button>
|
||||
<button onclick={() => {x = 'world'; y = 0;}}>reset</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,90 @@
|
||||
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, shift, pop, commit] = target.querySelectorAll('button');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,36 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (f = fork(() => {x = 'universe';}))}>x</button>
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,71 @@
|
||||
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, shift, pop, commit] = target.querySelectorAll('button');
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
shift.click();
|
||||
await tick();
|
||||
shift.click();
|
||||
await tick();
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,36 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (f = fork(() => {x = 'universe';}))}>x</button>
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,70 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const [x, y, shift, pop, commit] = target.querySelectorAll('button');
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
pop.click();
|
||||
await tick();
|
||||
pop.click();
|
||||
await tick();
|
||||
pop.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>shift</button>
|
||||
<button>pop</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,36 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (f = fork(() => {x = 'universe';}))}>x</button>
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
<button onclick={() => deferred.pop()?.()}>pop</button>
|
||||
<button onclick={() => f.commit()}>commit</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,76 @@
|
||||
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');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
world
|
||||
"world"
|
||||
world
|
||||
world
|
||||
world
|
||||
"world"
|
||||
`
|
||||
);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
world
|
||||
"world"
|
||||
world
|
||||
world
|
||||
world
|
||||
"world"
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,32 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (f = fork(() => {x = 'universe';}))}>x</button>
|
||||
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.pop()?.()}>resolve</button>
|
||||
<button onclick={() => f.commit()}>commit</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
let { x } = $props();
|
||||
</script>
|
||||
|
||||
<!-- checks direct source, indirect derived, block effect, async effect -->
|
||||
{x}
|
||||
{JSON.stringify(x)}
|
||||
{#if x === 'universe'}universe{:else}world{/if}
|
||||
{#if JSON.stringify(x) === '"universe"'}universe{:else}world{/if}
|
||||
{await Promise.resolve(x)}
|
||||
{await Promise.resolve(JSON.stringify(x))}
|
||||
@ -0,0 +1,85 @@
|
||||
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');
|
||||
|
||||
x.click();
|
||||
await tick();
|
||||
|
||||
y.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
commit.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
<hr>
|
||||
world
|
||||
"world"
|
||||
world
|
||||
world
|
||||
world
|
||||
"world"
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>x</button>
|
||||
<button>y++</button>
|
||||
<button>resolve</button>
|
||||
<button>commit</button>
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
<hr>
|
||||
universe
|
||||
"universe"
|
||||
universe
|
||||
universe
|
||||
universe
|
||||
"universe"
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,36 @@
|
||||
<script>
|
||||
import { fork } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let x = $state('world');
|
||||
let y = $state(0);
|
||||
let f;
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(value) {
|
||||
if (value !== 'universe') return value;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
|
||||
function delay2(value) {
|
||||
return new Promise((resolve) => deferred.push(() => resolve(value)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (f = fork(() => {x = 'universe';}))}>x</button>
|
||||
|
||||
<button onclick={() => y++}>y++</button>
|
||||
<button onclick={() => deferred.pop()?.()}>resolve</button>
|
||||
<button onclick={() => f.commit()}>commit</button>
|
||||
|
||||
{#if x === 'universe'}
|
||||
{await delay(x)}
|
||||
<Child {x} />
|
||||
{/if}
|
||||
|
||||
<hr>
|
||||
|
||||
{#if y > 0}
|
||||
<Child x={await delay2(x)} />
|
||||
{/if}
|
||||
@ -0,0 +1,3 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({ compileOptions: { experimental: { async: true } } });
|
||||
@ -0,0 +1,26 @@
|
||||
import 'svelte/internal/disclose-version';
|
||||
import 'svelte/internal/flags/async';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default function Async_top_level_group_sync_run($$anchor) {
|
||||
var a,
|
||||
// these should be grouped into one, having an async tick inbetween
|
||||
// would change how the code runs and could introduce subtle timing bugs
|
||||
b,
|
||||
c;
|
||||
|
||||
var $$promises = $.run([
|
||||
async () => a = await Promise.resolve(1),
|
||||
() => {
|
||||
b = a + 1;
|
||||
c = b + 1;
|
||||
}
|
||||
]);
|
||||
|
||||
$.next();
|
||||
|
||||
var text = $.text();
|
||||
|
||||
$.template_effect(() => $.set_text(text, c), void 0, void 0, [$$promises[1]]);
|
||||
$.append($$anchor, text);
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import 'svelte/internal/flags/async';
|
||||
import * as $ from 'svelte/internal/server';
|
||||
|
||||
export default function Async_top_level_group_sync_run($$renderer) {
|
||||
var a,
|
||||
// these should be grouped into one, having an async tick inbetween
|
||||
// would change how the code runs and could introduce subtle timing bugs
|
||||
b,
|
||||
c;
|
||||
|
||||
var $$promises = $$renderer.run([
|
||||
async () => a = await Promise.resolve(1),
|
||||
() => {
|
||||
b = a + 1;
|
||||
c = b + 1;
|
||||
}
|
||||
]);
|
||||
|
||||
$$renderer.push(`<!---->`);
|
||||
$$renderer.async([$$promises[1]], ($$renderer) => $$renderer.push(() => $.escape(c)));
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
let a = await Promise.resolve(1);
|
||||
// these should be grouped into one, having an async tick inbetween
|
||||
// would change how the code runs and could introduce subtle timing bugs
|
||||
let b = a + 1;
|
||||
let c = b + 1;
|
||||
</script>
|
||||
|
||||
{c}
|
||||
@ -0,0 +1,22 @@
|
||||
import {
|
||||
type TweenOptions,
|
||||
type SpringOptions,
|
||||
type SpringUpdateOptions,
|
||||
type Updater
|
||||
} from 'svelte/motion';
|
||||
|
||||
let tweenOptions: TweenOptions<number> = {
|
||||
delay: 100,
|
||||
duration: 400
|
||||
};
|
||||
|
||||
let springOptions: SpringOptions = {
|
||||
stiffness: 0.1,
|
||||
damping: 0.5
|
||||
};
|
||||
|
||||
let springUpdateOptions: SpringUpdateOptions = {
|
||||
instant: true
|
||||
};
|
||||
|
||||
let updater: Updater<number> = (target, value) => target + value;
|
||||
Loading…
Reference in new issue