element
+ const inner_div = window.document.createElement('div');
+ div.insertBefore(inner_div, null);
+ event = new window.InputEvent('input');
+ await div.dispatchEvent(event);
+ assert.equal(div.textContent, 'a');
+
+ text = window.document.createTextNode('b');
+ inner_div.insertBefore(text, null);
+ event = new window.InputEvent('input');
+ await div.dispatchEvent(event);
+ assert.equal(div.textContent, 'ab');
+ }
+};
diff --git a/test/runtime/samples/component-event-handler-contenteditable/main.svelte b/test/runtime-puppeteer/samples/component-event-handler-contenteditable/main.svelte
similarity index 100%
rename from test/runtime/samples/component-event-handler-contenteditable/main.svelte
rename to test/runtime-puppeteer/samples/component-event-handler-contenteditable/main.svelte
diff --git a/test/runtime-puppeteer/samples/inline-style-directive-precedence/_config.js b/test/runtime-puppeteer/samples/inline-style-directive-precedence/_config.js
new file mode 100644
index 0000000000..a684f3e0d7
--- /dev/null
+++ b/test/runtime-puppeteer/samples/inline-style-directive-precedence/_config.js
@@ -0,0 +1,24 @@
+export default {
+ html: `
+
+ `,
+
+ test({ assert, target, window, component }) {
+ const p = target.querySelector('p');
+ const styles = window.getComputedStyle(p);
+ assert.equal(styles.color, 'rgb(255, 0, 0)');
+ assert.equal(styles.fontSize, '32px');
+ assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)');
+ assert.equal(styles.borderColor, 'rgb(0, 128, 0)');
+
+ component.foo = 'font-size: 50px; color: green;'; // Update style attribute
+ {
+ const p = target.querySelector('p');
+ const styles = window.getComputedStyle(p);
+ assert.equal(styles.color, 'rgb(255, 0, 0)');
+ assert.equal(styles.fontSize, '32px');
+ assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)');
+ assert.equal(styles.borderColor, 'rgb(0, 128, 0)');
+ }
+ }
+};
diff --git a/test/runtime-puppeteer/samples/inline-style-directive-precedence/main.svelte b/test/runtime-puppeteer/samples/inline-style-directive-precedence/main.svelte
new file mode 100644
index 0000000000..3e8b721a42
--- /dev/null
+++ b/test/runtime-puppeteer/samples/inline-style-directive-precedence/main.svelte
@@ -0,0 +1,15 @@
+
+
+
diff --git a/test/runtime/samples/action-document/_config.js b/test/runtime/samples/action-document/_config.js
new file mode 100644
index 0000000000..d33cdb3fa4
--- /dev/null
+++ b/test/runtime/samples/action-document/_config.js
@@ -0,0 +1,14 @@
+export default {
+ html: '
',
+
+ async test({ assert, target, window }) {
+ const visibility = new window.Event('visibilitychange');
+
+ await window.document.dispatchEvent(visibility);
+ assert.htmlEqual(target.innerHTML, `
+
+ `);
+ }
+};
diff --git a/test/runtime/samples/action-document/main.svelte b/test/runtime/samples/action-document/main.svelte
new file mode 100644
index 0000000000..eec4b3fecd
--- /dev/null
+++ b/test/runtime/samples/action-document/main.svelte
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/test/runtime/samples/attribute-boolean-hidden/_config.js b/test/runtime/samples/attribute-boolean-hidden/_config.js
new file mode 100644
index 0000000000..cb38feb93d
--- /dev/null
+++ b/test/runtime/samples/attribute-boolean-hidden/_config.js
@@ -0,0 +1,10 @@
+export default {
+ props: {
+ hidden: true
+ },
+ html: '
',
+ test({ assert, component, target }) {
+ component.hidden = false;
+ assert.htmlEqual(target.innerHTML, '
');
+ }
+};
diff --git a/test/runtime/samples/attribute-boolean-hidden/main.svelte b/test/runtime/samples/attribute-boolean-hidden/main.svelte
new file mode 100644
index 0000000000..f8d7a26910
--- /dev/null
+++ b/test/runtime/samples/attribute-boolean-hidden/main.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/test/runtime/samples/attribute-boolean-itemscope/_config.js b/test/runtime/samples/attribute-boolean-itemscope/_config.js
deleted file mode 100644
index b5b21cfc47..0000000000
--- a/test/runtime/samples/attribute-boolean-itemscope/_config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-export default {
- props: {
- itemscope: true
- },
- test({ assert, target, component }) {
- const div = target.querySelector('div');
- assert.ok(div.itemscope);
- component.itemscope = false;
- assert.ok(!div.itemscope);
- }
-};
diff --git a/test/runtime/samples/attribute-boolean-itemscope/main.svelte b/test/runtime/samples/attribute-boolean-itemscope/main.svelte
deleted file mode 100644
index 83265a983c..0000000000
--- a/test/runtime/samples/attribute-boolean-itemscope/main.svelte
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/test/runtime/samples/attribute-escape/_config.js b/test/runtime/samples/attribute-escape/_config.js
new file mode 100644
index 0000000000..25313f01dc
--- /dev/null
+++ b/test/runtime/samples/attribute-escape/_config.js
@@ -0,0 +1,4 @@
+export default {
+ html: '
',
+ ssrHtml: '
'
+};
diff --git a/test/runtime/samples/attribute-escape/main.svelte b/test/runtime/samples/attribute-escape/main.svelte
new file mode 100644
index 0000000000..1b1fdf62a0
--- /dev/null
+++ b/test/runtime/samples/attribute-escape/main.svelte
@@ -0,0 +1 @@
+
`} />
diff --git a/test/runtime/samples/attribute-microdata/_config.js b/test/runtime/samples/attribute-microdata/_config.js
new file mode 100644
index 0000000000..8c6a7765ea
--- /dev/null
+++ b/test/runtime/samples/attribute-microdata/_config.js
@@ -0,0 +1,25 @@
+// There is no relationship between the attribute and the dom node with regards to microdata attributes https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata
+export default {
+ html: `
+
Game - REQUIRES
+
OS
+
+
+
RATING:
+ 4.6 (
+ 8864 ratings )
+
+
+
+
+ Price: $1.00
+
+
+ `
+};
diff --git a/test/runtime/samples/attribute-microdata/main.svelte b/test/runtime/samples/attribute-microdata/main.svelte
new file mode 100644
index 0000000000..f03a6943d9
--- /dev/null
+++ b/test/runtime/samples/attribute-microdata/main.svelte
@@ -0,0 +1,31 @@
+
+
+
Game - REQUIRES
+
OS
+
+
+
+ RATING:
+ 4.6 (
+ 8864 ratings )
+
+
+
+
+
+ Price: $1.00
+
+
diff --git a/test/runtime/samples/await-then-destruct-computed-props/_config.js b/test/runtime/samples/await-then-destruct-computed-props/_config.js
new file mode 100644
index 0000000000..6d147535e3
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-computed-props/_config.js
@@ -0,0 +1,32 @@
+export default {
+ async test({ assert, component, target }) {
+ await Promise.resolve();
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
propA: 3
+
propB: 7
+
num: 3
+
rest: {"prop3":{"prop9":9,"prop10":10}}
+
propZ: 5
+
propY: 6
+
rest: {"propX":7,"propW":8}
+ `
+ );
+
+ await (component.object = Promise.resolve({ prop1: 'one', prop2: 'two', prop3: { prop7: 'seven' }, prop4: { prop10: 'ten' }}));
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
propA: seven
+
propB: ten
+
num: 5
+
rest: {"prop1":"one","prop2":"two"}
+
propZ: 5
+
propY: 6
+
rest: {"propX":7,"propW":8}
+ `
+ );
+ }
+};
diff --git a/test/runtime/samples/await-then-destruct-computed-props/main.svelte b/test/runtime/samples/await-then-destruct-computed-props/main.svelte
new file mode 100644
index 0000000000..71756d6cf3
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-computed-props/main.svelte
@@ -0,0 +1,23 @@
+
+
+{#await object then { [`prop${num++}`]: { [`prop${num + 3}`]: propA }, [`prop${num++}`]: { [`prop${num + 5}`]: propB }, ...rest }}
+
propA: {propA}
+
propB: {propB}
+
num: {num}
+
rest: {JSON.stringify(rest)}
+{/await}
+
+{#await objectReject then value}
+ resolved
+{:catch { [`${prop}Z`]: propZ, [`${prop}Y`]: propY, ...rest }}
+
propZ: {propZ}
+
propY: {propY}
+
rest: {JSON.stringify(rest)}
+{/await}
+
diff --git a/test/runtime/samples/await-then-destruct-number-props/_config.js b/test/runtime/samples/await-then-destruct-number-props/_config.js
new file mode 100644
index 0000000000..6ef5e978d1
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-number-props/_config.js
@@ -0,0 +1,63 @@
+export default {
+ props: {
+ thePromise: new Promise(_ => {})
+ },
+
+ html: `
+ loading...
+ `,
+
+ async test({ assert, component, target }) {
+ await (component.thePromise = Promise.resolve([10, 11, 12, 13, 14, 15]));
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
[1] 11
+
[3] 13
+
[4] 14
+ `
+ );
+
+ await (component.thePromise = Promise.resolve({ 1: 21, 3: 23, 4: 24 }));
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
[1] 21
+
[3] 23
+
[4] 24
+ `
+ );
+
+ try {
+ await (component.thePromise = Promise.reject([30, 31, 32, 33, 34, 35]));
+ } catch (e) {
+ // do nothing
+ }
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
[0] 30
+
[2] 32
+
[5] 35
+ `
+ );
+
+ try {
+ await (component.thePromise = Promise.reject({ 0: 40, 2: 42, 5: 45 }));
+ } catch (e) {
+ // do nothing
+ }
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
[0] 40
+
[2] 42
+
[5] 45
+ `
+ );
+ }
+};
diff --git a/test/runtime/samples/await-then-destruct-number-props/main.svelte b/test/runtime/samples/await-then-destruct-number-props/main.svelte
new file mode 100644
index 0000000000..aaeee9b353
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-number-props/main.svelte
@@ -0,0 +1,15 @@
+
+
+{#await thePromise}
+ loading...
+{:then { 1: a, 3: b, 4: c }}
+
[1] {a}
+
[3] {b}
+
[4] {c}
+{:catch { 0: d, 2: e, 5: f }}
+
[0] {d}
+
[2] {e}
+
[5] {f}
+{/await}
diff --git a/test/runtime/samples/await-then-destruct-string-props/_config.js b/test/runtime/samples/await-then-destruct-string-props/_config.js
new file mode 100644
index 0000000000..6517f6bf20
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-string-props/_config.js
@@ -0,0 +1,17 @@
+export default {
+ async test({ assert, target }) {
+ await Promise.resolve();
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
prop-1: 1
+
prop4: 4
+
rest: {"prop2":2,"prop-3":3}
+
prop-7: 7
+
prop6: 6
+
rest: {"prop-5":5,"prop8":8}
+ `
+ );
+ }
+};
diff --git a/test/runtime/samples/await-then-destruct-string-props/main.svelte b/test/runtime/samples/await-then-destruct-string-props/main.svelte
new file mode 100644
index 0000000000..608b1161f5
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-string-props/main.svelte
@@ -0,0 +1,19 @@
+
+
+{#await object then { 'prop-1': prop1, 'prop4': fourthProp, ...rest }}
+
prop-1: {prop1}
+
prop4: {fourthProp}
+
rest: {JSON.stringify(rest)}
+{/await}
+
+{#await objectReject then value}
+ resolved
+{:catch { 'prop-7': prop7, 'prop6': sixthProp, ...rest }}
+
prop-7: {prop7}
+
prop6: {sixthProp}
+
rest: {JSON.stringify(rest)}
+{/await}
+
diff --git a/test/runtime/samples/binding-contenteditable-innertext/_config.js b/test/runtime/samples/binding-contenteditable-innertext/_config.js
new file mode 100644
index 0000000000..36e762ac24
--- /dev/null
+++ b/test/runtime/samples/binding-contenteditable-innertext/_config.js
@@ -0,0 +1,25 @@
+export default {
+ props: {
+ name: 'world'
+ },
+
+ ssrHtml: `
+
world
+
hello world
+ `,
+
+ async test({ assert, component, target, window }) {
+ // JSDom doesn't support innerText yet, so the test is not ideal
+ // https://github.com/jsdom/jsdom/issues/1245
+ const el = target.querySelector('editor');
+ assert.equal(el.innerText, 'world');
+
+ const event = new window.Event('input');
+ el.innerText = 'everybody';
+ await el.dispatchEvent(event);
+ assert.equal(component.name, 'everybody');
+
+ component.name = 'goodbye';
+ assert.equal(el.innerText, 'goodbye');
+ }
+};
diff --git a/test/runtime/samples/binding-contenteditable-innertext/main.svelte b/test/runtime/samples/binding-contenteditable-innertext/main.svelte
new file mode 100644
index 0000000000..d65350d1a8
--- /dev/null
+++ b/test/runtime/samples/binding-contenteditable-innertext/main.svelte
@@ -0,0 +1,6 @@
+
+
+
+
hello {name}
diff --git a/test/runtime/samples/binding-input-group-each-10/_config.js b/test/runtime/samples/binding-input-group-each-10/_config.js
new file mode 100644
index 0000000000..edfc508f05
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-10/_config.js
@@ -0,0 +1,52 @@
+// https://github.com/sveltejs/svelte/issues/7633
+export default {
+ async test({ assert, target, component, window }) {
+ let inputs = target.querySelectorAll('input');
+
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+
+ component.moveDown(0);
+ component.moveDown(1);
+ await Promise.resolve();
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
+ b
+
+
+ c
+
+
+ a
+
+ `
+ );
+
+ // after shifting order, should still keep the correct radio checked
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, false);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, true);
+
+ (component.current = 'b');
+ await Promise.resolve();
+
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+
+ component.moveDown(1);
+ await Promise.resolve();
+
+ // after shifting order, should still keep the correct radio checked
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-each-10/main.svelte b/test/runtime/samples/binding-input-group-each-10/main.svelte
new file mode 100644
index 0000000000..7c81cada9a
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-10/main.svelte
@@ -0,0 +1,36 @@
+
+
+{#each list as item (item.name)}
+
+ {item.name}
+ {#if true}
+
+ {/if}
+
+{/each}
+
diff --git a/test/runtime/samples/binding-input-group-each-11/_config.js b/test/runtime/samples/binding-input-group-each-11/_config.js
new file mode 100644
index 0000000000..a90993861a
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-11/_config.js
@@ -0,0 +1,88 @@
+// https://github.com/sveltejs/svelte/issues/6112
+export default {
+ async test({ assert, target, component, window }) {
+ let inputs = target.querySelectorAll('input');
+
+ const check = (set) => {
+ for (let i = 0; i < inputs.length; i++) {
+ assert.equal(inputs[i].checked, set.has(i));
+ }
+ };
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
1
+
+
+ `
+ );
+
+ check(new Set([0, 2, 5, 6]));
+
+ const event = new window.Event('change');
+
+ // dom to value
+ inputs[3].checked = true;
+ await inputs[3].dispatchEvent(event);
+
+ check(new Set([0, 3, 5, 6]));
+ assert.equal(component.pipelineOperations[1].operation.args[1].value, 'd');
+
+ // remove item
+ component.pipelineOperations = component.pipelineOperations.slice(1);
+ await Promise.resolve();
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
+
+ `
+ );
+
+ inputs = target.querySelectorAll('input');
+ check(new Set([0, 3, 5, 6]));
+
+ inputs[2].checked = true;
+ await inputs[2].dispatchEvent(event);
+
+ check(new Set([0, 2, 5, 6]));
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-each-11/main.svelte b/test/runtime/samples/binding-input-group-each-11/main.svelte
new file mode 100644
index 0000000000..7c759b5bb4
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-11/main.svelte
@@ -0,0 +1,60 @@
+
+
+{#each pipelineOperations as { operation, id } (id)}
+
+ {id}
+ {#each operation.args as arg}
+
+ {#each arg.options as { value }}
+
+ {/each}
+
+ {/each}
+
+{/each}
diff --git a/test/runtime/samples/binding-input-group-each-12/_config.js b/test/runtime/samples/binding-input-group-each-12/_config.js
new file mode 100644
index 0000000000..a3d6c92879
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-12/_config.js
@@ -0,0 +1,89 @@
+// https://github.com/sveltejs/svelte/issues/6112
+export default {
+ async test({ assert, target, component, window }) {
+ let inputs = target.querySelectorAll('input');
+
+ const check = (set) => {
+ for (let i = 0; i < inputs.length; i++) {
+ assert.equal(inputs[i].checked, set.has(i));
+ }
+ };
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
1
+
+
+ `
+ );
+
+ check(new Set([0, 2]));
+
+ const event = new window.Event('change');
+
+ // dom to value
+ inputs[3].checked = true;
+ await inputs[3].dispatchEvent(event);
+
+ check(new Set([0, 2, 3]));
+ assert.deepEqual(component.pipelineOperations[1].operation.args[1].value, ['c', 'd']);
+
+ // remove item
+ component.pipelineOperations = component.pipelineOperations.slice(1);
+ await Promise.resolve();
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
+
+ `
+ );
+
+ inputs = target.querySelectorAll('input');
+ check(new Set([0, 2, 3]));
+
+ inputs[5].checked = true;
+ await inputs[5].dispatchEvent(event);
+
+ check(new Set([0, 2, 3, 5]));
+ assert.deepEqual(component.pipelineOperations[1].operation.args[0].value, ['b']);
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-each-12/main.svelte b/test/runtime/samples/binding-input-group-each-12/main.svelte
new file mode 100644
index 0000000000..289353778a
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-12/main.svelte
@@ -0,0 +1,60 @@
+
+
+{#each pipelineOperations as { operation, id } (id)}
+
+ {id}
+ {#each operation.args as arg}
+
+ {#each arg.options as { value }}
+
+ {/each}
+
+ {/each}
+
+{/each}
diff --git a/test/runtime/samples/binding-input-group-each-13/_config.js b/test/runtime/samples/binding-input-group-each-13/_config.js
new file mode 100644
index 0000000000..affb94b8fb
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-13/_config.js
@@ -0,0 +1,30 @@
+export default {
+ async test({ assert, target, window }) {
+ const [input1, input2] = target.querySelectorAll('input[type=text]');
+ const radio = target.querySelector('input[type=radio]');
+
+ assert.equal(radio.checked, false);
+
+ const event = new window.Event('input');
+
+ input1.value = 'world';
+ await input1.dispatchEvent(event);
+ assert.equal(radio.checked, true);
+
+ input2.value = 'foo';
+ await input2.dispatchEvent(event);
+ assert.equal(radio.checked, false);
+
+ input1.value = 'foo';
+ await input1.dispatchEvent(event);
+ assert.equal(radio.checked, true);
+
+ input1.value = 'bar';
+ await input1.dispatchEvent(event);
+ assert.equal(radio.checked, false);
+
+ input2.value = 'bar';
+ await input2.dispatchEvent(event);
+ assert.equal(radio.checked, true);
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-each-13/main.svelte b/test/runtime/samples/binding-input-group-each-13/main.svelte
new file mode 100644
index 0000000000..592be2ae9d
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-13/main.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/test/runtime/samples/binding-input-group-each-8/_config.js b/test/runtime/samples/binding-input-group-each-8/_config.js
new file mode 100644
index 0000000000..b17b801a83
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-8/_config.js
@@ -0,0 +1,78 @@
+// https://github.com/sveltejs/svelte/issues/7884
+export default {
+ async test({ assert, target, component, window }) {
+ let inputs = target.querySelectorAll('input');
+
+ assert.htmlEqual(target.innerHTML, `
+
{"foo":[],"bar":[]}
+
foo
+
+
bar
+
+ `);
+
+ const event = new window.Event('change');
+
+ inputs[0].checked = true;
+ await inputs[0].dispatchEvent(event);
+ inputs[2].checked = true;
+ await inputs[2].dispatchEvent(event);
+ inputs[3].checked = true;
+ await inputs[3].dispatchEvent(event);
+
+ assert.htmlEqual(target.innerHTML, `
+
{"foo":[1,3],"bar":[1]}
+
foo
+
+
bar
+
+ `);
+
+ await component.update();
+
+ assert.htmlEqual(target.innerHTML, `
+
{"foo":[1,3],"bar":[1],"qux":[]}
+
qux
+
+ `);
+
+ inputs = target.querySelectorAll('input');
+ inputs[0].checked = true;
+ await inputs[0].dispatchEvent(event);
+
+ assert.htmlEqual(target.innerHTML, `
+
{"foo":[1,3],"bar":[1],"qux":[4]}
+
qux
+
+ `);
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+ }
+};
+
+
diff --git a/test/runtime/samples/binding-input-group-each-8/main.svelte b/test/runtime/samples/binding-input-group-each-8/main.svelte
new file mode 100644
index 0000000000..a6c5bccac0
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-8/main.svelte
@@ -0,0 +1,36 @@
+
+
+
+ {JSON.stringify(object)}
+
+
+{#each keys as key (key)}
+
{key}
+
+{/each}
diff --git a/test/runtime/samples/binding-input-group-each-9/_config.js b/test/runtime/samples/binding-input-group-each-9/_config.js
new file mode 100644
index 0000000000..e2b48a83d7
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-9/_config.js
@@ -0,0 +1,49 @@
+// https://github.com/sveltejs/svelte/issues/7633
+export default {
+ async test({ assert, target, component, window }) {
+ let inputs = target.querySelectorAll('input');
+
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+
+ await component.moveDown(0);
+ await component.moveDown(1);
+
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
+ b
+
+
+ c
+
+
+ a
+
+ `
+ );
+
+ // after shifting order, should still keep the correct radio checked
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, false);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, true);
+
+ await (component.current = 'b');
+
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+
+ await component.moveDown(1);
+
+ // after shifting order, should still keep the correct radio checked
+ inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].checked, true);
+ assert.equal(inputs[1].checked, false);
+ assert.equal(inputs[2].checked, false);
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-each-9/main.svelte b/test/runtime/samples/binding-input-group-each-9/main.svelte
new file mode 100644
index 0000000000..ee89123a9a
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-each-9/main.svelte
@@ -0,0 +1,36 @@
+
+
+{#each list as item}
+
+ {item.name}
+ {#if true}
+
+ {/if}
+
+{/each}
+
diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js b/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js
new file mode 100644
index 0000000000..bdc4da2d57
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js
@@ -0,0 +1,40 @@
+export default {
+ async test({ assert, target, component, window }) {
+ const button = target.querySelector('button');
+ const clickEvent = new window.Event('click');
+ const changeEvent = new window.Event('change');
+
+ const [input1, input2] = target.querySelectorAll('input[type="checkbox"]');
+ function validate_inputs(v1, v2) {
+ assert.equal(input1.checked, v1);
+ assert.equal(input2.checked, v2);
+ }
+
+ assert.deepEqual(component.test, []);
+ validate_inputs(false, false);
+
+ component.test = ['a', 'b'];
+ validate_inputs(true, true);
+
+ input1.checked = false;
+ await input1.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, ['b']);
+
+ input2.checked = false;
+ await input2.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, []);
+
+ input1.checked = true;
+ input2.checked = true;
+ await input1.dispatchEvent(changeEvent);
+ await input2.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, ['b', 'a']);
+
+ await button.dispatchEvent(clickEvent);
+ assert.deepEqual(component.test, ['b', 'a']); // should it be ['a'] only? valid arguments for both outcomes
+
+ input1.checked = false;
+ await input1.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, []);
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte b/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte
new file mode 100644
index 0000000000..71955b6b81
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte
@@ -0,0 +1,14 @@
+
+
+
+
+
+{#if !hidden}
+
+{/if}
+
diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js b/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js
new file mode 100644
index 0000000000..a8d5a7137f
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js
@@ -0,0 +1,34 @@
+export default {
+ async test({ assert, target, component, window }) {
+ const button = target.querySelector('button');
+ const clickEvent = new window.Event('click');
+ const changeEvent = new window.Event('change');
+
+ const [input1, input2] = target.querySelectorAll('input[type="radio"]');
+ function validate_inputs(v1, v2) {
+ assert.equal(input1.checked, v1);
+ assert.equal(input2.checked, v2);
+ }
+
+ component.test = 'a';
+ validate_inputs(true, false);
+
+ component.test = 'b';
+ validate_inputs(false, true);
+
+ input1.checked = true;
+ await input1.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, 'a');
+
+ input2.checked = true;
+ await input2.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, 'b');
+
+ await button.dispatchEvent(clickEvent);
+ assert.deepEqual(component.test, 'b'); // should it be undefined? valid arguments for both outcomes
+
+ input1.checked = true;
+ await input1.dispatchEvent(changeEvent);
+ assert.deepEqual(component.test, 'a');
+ }
+};
diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte b/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte
new file mode 100644
index 0000000000..9add22cacc
--- /dev/null
+++ b/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte
@@ -0,0 +1,14 @@
+
+
+
+
+
+{#if !hidden}
+
+{/if}
+
diff --git a/test/runtime/samples/binding-select-initial-value-undefined-2/_config.js b/test/runtime/samples/binding-select-initial-value-undefined-2/_config.js
new file mode 100644
index 0000000000..f7c91809bd
--- /dev/null
+++ b/test/runtime/samples/binding-select-initial-value-undefined-2/_config.js
@@ -0,0 +1,25 @@
+export default {
+ skip_if_ssr: true, // TODO would be nice to fix this in SSR as well
+
+ html: `
+
selected: b
+
+
+
+
selected: b
+ `,
+
+ test({ assert, component, target }) {
+ assert.equal(component.selected, 'b');
+ const select = target.querySelector('select');
+ const options = [...target.querySelectorAll('option')];
+
+ // option with selected attribute should be selected
+ assert.equal(select.value, 'b');
+ assert.ok(options[1].selected);
+ }
+};
diff --git a/test/runtime/samples/binding-select-initial-value-undefined-2/main.svelte b/test/runtime/samples/binding-select-initial-value-undefined-2/main.svelte
new file mode 100644
index 0000000000..0640a9ce27
--- /dev/null
+++ b/test/runtime/samples/binding-select-initial-value-undefined-2/main.svelte
@@ -0,0 +1,13 @@
+
+
+
selected: {selected}
+
+
+
+
selected: {selected}
\ No newline at end of file
diff --git a/test/runtime/samples/component-event-handler-contenteditable/_config.js b/test/runtime/samples/component-event-handler-contenteditable/_config.js
deleted file mode 100644
index 1628e22d01..0000000000
--- a/test/runtime/samples/component-event-handler-contenteditable/_config.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export default {
- html: `
-
- `,
-
- async test({ assert, target, window }) {
- const div = target.querySelector('div');
- const text = window.document.createTextNode('a');
- div.insertBefore(text, null);
- const event = new window.InputEvent('input');
- await div.dispatchEvent(event);
-
- assert.equal(div.textContent, 'a');
- }
-};
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js b/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js
new file mode 100644
index 0000000000..9ec4a3e3e6
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js
@@ -0,0 +1,20 @@
+export default {
+ html: `
+
4, 12, 60
+ `,
+
+ async test({ component, target, assert }) {
+ component.permutation = [2, 3, 1];
+ await (component.promise1 = Promise.resolve({length: 1, width: 2, height: 3}));
+ try {
+ await (component.promise2 = Promise.reject({length: 97, width: 98, height: 99}));
+ } catch (e) {
+ // nothing
+ }
+
+ assert.htmlEqual(target.innerHTML, `
+
2, 11, 2
+
9506, 28811, 98
+ `);
+ }
+};
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte b/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte
new file mode 100644
index 0000000000..285fc44348
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte
@@ -0,0 +1,27 @@
+
+
+{#await promise1 then { length, width, height }}
+ {@const { [0]: a, [1]: b, [2]: c } = permutation}
+ {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
+
{first}, {second}, {third}
+{/await}
+
+{#await promise2 catch { [`leng${th}`]: l, [`wid${th}`]: w, height: h }}
+ {@const [a, b, c] = permutation}
+ {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(l, w, h) }
+
{first}, {second}, {third}
+{/await}
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-computed-props/_config.js b/test/runtime/samples/const-tag-await-then-destructuring-computed-props/_config.js
new file mode 100644
index 0000000000..9ec4a3e3e6
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-computed-props/_config.js
@@ -0,0 +1,20 @@
+export default {
+ html: `
+
4, 12, 60
+ `,
+
+ async test({ component, target, assert }) {
+ component.permutation = [2, 3, 1];
+ await (component.promise1 = Promise.resolve({length: 1, width: 2, height: 3}));
+ try {
+ await (component.promise2 = Promise.reject({length: 97, width: 98, height: 99}));
+ } catch (e) {
+ // nothing
+ }
+
+ assert.htmlEqual(target.innerHTML, `
+
2, 11, 2
+
9506, 28811, 98
+ `);
+ }
+};
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-computed-props/main.svelte b/test/runtime/samples/const-tag-await-then-destructuring-computed-props/main.svelte
new file mode 100644
index 0000000000..fbc54e4d0b
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-computed-props/main.svelte
@@ -0,0 +1,25 @@
+
+
+{#await promise1 then { length, width, height }}
+ {@const [a, b, c] = permutation}
+ {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
+
{first}, {second}, {third}
+{/await}
+
+{#await promise2 catch { length, width, height }}
+ {@const [a, b, c] = permutation}
+ {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
+
{first}, {second}, {third}
+{/await}
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-literals/_config.js b/test/runtime/samples/const-tag-await-then-destructuring-literals/_config.js
new file mode 100644
index 0000000000..cb40e7c456
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-literals/_config.js
@@ -0,0 +1,19 @@
+export default {
+ html: '
12 120 70, 30+4=34
',
+ async test({ component, target, assert }) {
+ component.promise1 = Promise.resolve({width: 5, height: 6});
+ component.promise2 = Promise.reject({width: 6, height: 7});
+
+ await Promise.resolve();
+ assert.htmlEqual(target.innerHTML, `
+
30 300 110, 50+6=56
+
42 420 130, 60+7=67
+ `);
+
+ component.constant = 20;
+ assert.htmlEqual(target.innerHTML, `
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ `);
+ }
+};
diff --git a/test/runtime/samples/const-tag-await-then-destructuring-literals/main.svelte b/test/runtime/samples/const-tag-await-then-destructuring-literals/main.svelte
new file mode 100644
index 0000000000..0875820e4a
--- /dev/null
+++ b/test/runtime/samples/const-tag-await-then-destructuring-literals/main.svelte
@@ -0,0 +1,23 @@
+
+
+{#await promise1 then { width, height }}
+ {@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)}
+ {@const perimeter = (width + height) * constant}
+ {@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]}
+
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await}
+
+{#await promise2 catch { width, height }}
+ {@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)}
+ {@const perimeter = (width + height) * constant}
+ {@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]}
+
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await}
diff --git a/test/runtime/samples/const-tag-each-destructure-computed-in-computed/_config.js b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/_config.js
new file mode 100644
index 0000000000..c299f19da6
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/_config.js
@@ -0,0 +1,15 @@
+export default {
+ html: `
+
+
+
+ `,
+
+ async test({ component, target, assert }) {
+ component.boxes = [{ length: 10, width: 20, height: 30 }];
+
+ assert.htmlEqual(target.innerHTML,
+ '
'
+ );
+ }
+};
diff --git a/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte
new file mode 100644
index 0000000000..26dc5557ed
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte
@@ -0,0 +1,44 @@
+
+
+{#each boxes as { [`leng${th}`]: length, [`wid${th}`]: width, height }}
+ {@const {
+ [`two${dimension}`]: areas,
+ [`three${dimension}`]: {
+ volume
+ }
+ } = calculate(length, width, height)}
+ {@const {
+ i = 1,
+ [`bottom${area}`]: bottom,
+ [`side${area}${i++}`]: sideone,
+ [`side${area}${i++}`]: sidetwo
+ } = areas}
+
+{/each}
diff --git a/test/runtime/samples/const-tag-each-destructure-computed-props/_config.js b/test/runtime/samples/const-tag-each-destructure-computed-props/_config.js
new file mode 100644
index 0000000000..c299f19da6
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-computed-props/_config.js
@@ -0,0 +1,15 @@
+export default {
+ html: `
+
+
+
+ `,
+
+ async test({ component, target, assert }) {
+ component.boxes = [{ length: 10, width: 20, height: 30 }];
+
+ assert.htmlEqual(target.innerHTML,
+ '
'
+ );
+ }
+};
diff --git a/test/runtime/samples/const-tag-each-destructure-computed-props/main.svelte b/test/runtime/samples/const-tag-each-destructure-computed-props/main.svelte
new file mode 100644
index 0000000000..c8c7e1977a
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-computed-props/main.svelte
@@ -0,0 +1,42 @@
+
+
+{#each boxes as { length, width, height }}
+ {@const {
+ [`two${dimension}`]: {
+ i = 1,
+ [`bottom${area}`]: bottom,
+ [`side${area}${i++}`]: sideone,
+ [`side${area}${i++}`]: sidetwo
+ },
+ [`three${dimension}`]: {
+ volume
+ }
+ } = calculate(length, width, height)}
+
+{/each}
diff --git a/test/runtime/samples/const-tag-each-destructure-literals/_config.js b/test/runtime/samples/const-tag-each-destructure-literals/_config.js
new file mode 100644
index 0000000000..00f8b31540
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-literals/_config.js
@@ -0,0 +1,30 @@
+export default {
+ html: `
+
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `,
+ async test({ component, target, assert }) {
+ component.constant = 20;
+
+ assert.htmlEqual(target.innerHTML, `
+
12 240 140, 60+4=64
+
35 700 240, 100+7=107
+
48 960 280, 120+8=128
+ `);
+
+ component.boxes = [
+ {width: 3, height: 4},
+ {width: 4, height: 5},
+ {width: 5, height: 6},
+ {width: 6, height: 7}
+ ];
+
+ assert.htmlEqual(target.innerHTML, `
+
12 240 140, 60+4=64
+
20 400 180, 80+5=85
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ `);
+ }
+};
diff --git a/test/runtime/samples/const-tag-each-destructure-literals/main.svelte b/test/runtime/samples/const-tag-each-destructure-literals/main.svelte
new file mode 100644
index 0000000000..b0fc221ec9
--- /dev/null
+++ b/test/runtime/samples/const-tag-each-destructure-literals/main.svelte
@@ -0,0 +1,19 @@
+
+
+{#each boxes as { width, height }}
+ {@const { 'the-area': area, 'the-volume': volume } = calculate(width, height, constant)}
+ {@const perimeter = (width + height) * constant}
+ {@const { 2: sum, 0: _width, 1: _height } = [width * constant, height, width * constant + height]}
+
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/each}
diff --git a/test/runtime/samples/each-block-destructured-array-as-object/_config.js b/test/runtime/samples/each-block-destructured-array-as-object/_config.js
new file mode 100644
index 0000000000..ff341ce033
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-array-as-object/_config.js
@@ -0,0 +1,22 @@
+export default {
+ props: {
+ array: [
+ [1, 2, 3, 4, 5],
+ [6, 7, 8],
+ [9, 10, 11, 12]
+ ]
+ },
+
+ html: `
+
First: 1, Third: 3, Length: 5
+
First: 6, Third: 8, Length: 3
+
First: 9, Third: 11, Length: 4
+ `,
+
+ test({ assert, component, target }) {
+ component.array = [[12, 13]];
+ assert.htmlEqual( target.innerHTML, `
+
First: 12, Third: undefined, Length: 2
+ `);
+ }
+};
diff --git a/test/runtime/samples/each-block-destructured-array-as-object/main.svelte b/test/runtime/samples/each-block-destructured-array-as-object/main.svelte
new file mode 100644
index 0000000000..cff735555b
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-array-as-object/main.svelte
@@ -0,0 +1,7 @@
+
+
+{#each array as { 0: first, '2': third, "length": length }}
+
First: {first}, Third: {third}, Length: {length}
+{/each}
diff --git a/test/runtime/samples/each-block-destructured-array-computed-props/_config.js b/test/runtime/samples/each-block-destructured-array-computed-props/_config.js
new file mode 100644
index 0000000000..e400e2f280
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-array-computed-props/_config.js
@@ -0,0 +1,24 @@
+export default {
+ props: {
+ array: [
+ [1, 2, 3, 4, 5],
+ [6, 7, 8],
+ [9, 10, 11, 12],
+ [13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
+ ]
+ },
+
+ html: `
+
First: 1, Half: 3, Last: 5, Length: 5
+
First: 6, Half: 7, Last: 8, Length: 3
+
First: 9, Half: 11, Last: 12, Length: 4
+
First: 13, Half: 18, Last: 22, Length: 10
+ `,
+
+ test({ assert, component, target }) {
+ component.array = [[23, 24, 25, 26, 27, 28, 29]];
+ assert.htmlEqual( target.innerHTML, `
+
First: 23, Half: 26, Last: 29, Length: 7
+ `);
+ }
+};
diff --git a/test/runtime/samples/each-block-destructured-array-computed-props/main.svelte b/test/runtime/samples/each-block-destructured-array-computed-props/main.svelte
new file mode 100644
index 0000000000..00a9a99a89
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-array-computed-props/main.svelte
@@ -0,0 +1,7 @@
+
+
+{#each array as { 0: first, length, [length - 1]: last, [Math.floor(length / 2)]: half }}
+
First: {first}, Half: {half}, Last: {last}, Length: {length}
+{/each}
diff --git a/test/runtime/samples/each-block-destructured-object-computed-props/_config.js b/test/runtime/samples/each-block-destructured-object-computed-props/_config.js
new file mode 100644
index 0000000000..7e98fab913
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-computed-props/_config.js
@@ -0,0 +1,26 @@
+export default {
+ props: {
+ firstString: 'cats',
+ secondString: 'dogs',
+ objectsArray: [
+ { dogs: 'woof', cats: 'meow', stac: 'stack', DOGS: 'WOOF' },
+ { dogs: 'A German sheppard', cats: 'A tailless cat', stac: 'A jenga tower', DOGS: 'A GERMAN SHEPPARD' },
+ { dogs: 'dogs', cats: 'cats', stac: 'stac', DOGS: 'DOGS' }
+ ]
+ },
+
+ html: `
+
cats: meow
+
dogs: woof
+
stac: stack
+
DOGS: WOOF
+
cats: A tailless cat
+
dogs: A German sheppard
+
stac: A jenga tower
+
DOGS: A GERMAN SHEPPARD
+
cats: cats
+
dogs: dogs
+
stac: stac
+
DOGS: DOGS
+ `
+};
diff --git a/test/runtime/samples/each-block-destructured-object-computed-props/main.svelte b/test/runtime/samples/each-block-destructured-object-computed-props/main.svelte
new file mode 100644
index 0000000000..9c2ae29617
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-computed-props/main.svelte
@@ -0,0 +1,12 @@
+
+
+{#each objectsArray as { [firstString]: firstProp, [secondString]: secondProp, [firstString.split('').reverse().join('')]: reverseFirst, [secondString.toUpperCase()]: upperSecond } }
+
{firstString}: {firstProp}
+
{secondString}: {secondProp}
+
{firstString.split('').reverse().join('')}: {reverseFirst}
+
{secondString.toUpperCase()}: {upperSecond}
+{/each}
diff --git a/test/runtime/samples/each-block-destructured-object-literal-props/_config.js b/test/runtime/samples/each-block-destructured-object-literal-props/_config.js
new file mode 100644
index 0000000000..0b29c28cd9
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-literal-props/_config.js
@@ -0,0 +1,22 @@
+export default {
+ props: {
+ objectsArray: [
+ { 'foo-bar': 'FooBar', 0: 'zero', prop: 'prop' },
+ { 'foo-bar': 'foobar', 0: 'null', prop: 'a prop' },
+ { 'foo-bar': 'FOO BAR', 0: 'nada', prop: 'the prop' }
+ ]
+ },
+
+ html: `
+
FooBar: prop zero
+
foobar: a prop null
+
FOO BAR: the prop nada
+ `,
+
+ test({ assert, component, target }) {
+ component.objectsArray = [{ 'foo-bar': 'Fool Ball', 0: 'nil', prop: 'one prop' }];
+ assert.htmlEqual( target.innerHTML, `
+
Fool Ball: one prop nil
+ `);
+ }
+};
diff --git a/test/runtime/samples/each-block-destructured-object-literal-props/main.svelte b/test/runtime/samples/each-block-destructured-object-literal-props/main.svelte
new file mode 100644
index 0000000000..08826e80e9
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-literal-props/main.svelte
@@ -0,0 +1,7 @@
+
+
+{#each objectsArray as { 0: prop0, "foo-bar": propFooBar, prop: varProp } }
+
{propFooBar}: {varProp} {prop0}
+{/each}
diff --git a/test/runtime/samples/each-block-destructured-object-literal-rest/_config.js b/test/runtime/samples/each-block-destructured-object-literal-rest/_config.js
new file mode 100644
index 0000000000..b2f29e28f5
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-literal-rest/_config.js
@@ -0,0 +1,22 @@
+export default {
+ props: {
+ objectsArray: [
+ { quote: 'q1', 'wrong-quote': 'wq1', 16: '16', class: 'class' },
+ { quote: 'q2', 'wrong-quote': 'wq2', 16: 'sixteen', class: 'glass' },
+ { quote: 'q3', 'wrong-quote': 'wq3', 16: 'seize', class: 'mass' }
+ ]
+ },
+
+ html: `
+
Quote: q1, Wrong Quote: wq1, 16: 16
+
Quote: q2, Wrong Quote: wq2, 16: sixteen
+
Quote: q3, Wrong Quote: wq3, 16: seize
+ `,
+
+ test({ assert, component, target }) {
+ component.objectsArray = [{ quote: 'new-quote', 'wrong-quote': 'wq4', 16: 'ten+six', role: 'role' }];
+ assert.htmlEqual(target.innerHTML, `
+
Quote: new-quote, Wrong Quote: wq4, 16: ten+six
+ `);
+ }
+};
diff --git a/test/runtime/samples/each-block-destructured-object-literal-rest/main.svelte b/test/runtime/samples/each-block-destructured-object-literal-rest/main.svelte
new file mode 100644
index 0000000000..943b3b7940
--- /dev/null
+++ b/test/runtime/samples/each-block-destructured-object-literal-rest/main.svelte
@@ -0,0 +1,7 @@
+
+
+{#each objectsArray as { "quote": quotedProp, "wrong-quote": wrongQuote, 16: sixteen, ...props } }
+
Quote: {quotedProp}, Wrong Quote: {wrongQuote}, 16: {sixteen}
+{/each}
diff --git a/test/runtime/samples/html-entities-inside-component-slot/Component.svelte b/test/runtime/samples/html-entities-inside-component-slot/Component.svelte
new file mode 100644
index 0000000000..8063609738
--- /dev/null
+++ b/test/runtime/samples/html-entities-inside-component-slot/Component.svelte
@@ -0,0 +1,3 @@
+
+
+
diff --git a/test/runtime/samples/html-entities-inside-component-slot/_config.js b/test/runtime/samples/html-entities-inside-component-slot/_config.js
new file mode 100644
index 0000000000..33777a4919
--- /dev/null
+++ b/test/runtime/samples/html-entities-inside-component-slot/_config.js
@@ -0,0 +1,11 @@
+export default {
+ html: `
+
+
+
+
+
+
+
+ `
+};
diff --git a/test/runtime/samples/html-entities-inside-component-slot/main.svelte b/test/runtime/samples/html-entities-inside-component-slot/main.svelte
new file mode 100644
index 0000000000..8baecfedcc
--- /dev/null
+++ b/test/runtime/samples/html-entities-inside-component-slot/main.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+ {@html " "}
+
diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js
index f5780daf80..f2ab49b511 100644
--- a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js
+++ b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js
@@ -5,7 +5,6 @@ export default {
test({ assert, target, window }) {
const p = target.querySelector('p');
-
const styles = window.getComputedStyle(p);
assert.equal(styles.color, 'red');
assert.equal(styles.height, '40px');
diff --git a/test/runtime/samples/reactive-statement-indirect/_config.js b/test/runtime/samples/reactive-statement-indirect/_config.js
new file mode 100644
index 0000000000..9265ded073
--- /dev/null
+++ b/test/runtime/samples/reactive-statement-indirect/_config.js
@@ -0,0 +1,14 @@
+export default {
+ html: `
+
2
+
+ `,
+ async test({ assert, target }) {
+ await target.querySelector('button').dispatchEvent(new window.MouseEvent('click'));
+
+ assert.htmlEqual(target.innerHTML, `
+
4
+
+ `);
+ }
+};
diff --git a/test/runtime/samples/reactive-statement-indirect/main.svelte b/test/runtime/samples/reactive-statement-indirect/main.svelte
new file mode 100644
index 0000000000..ab75c19127
--- /dev/null
+++ b/test/runtime/samples/reactive-statement-indirect/main.svelte
@@ -0,0 +1,11 @@
+
+
+
{indirect_double}
+
diff --git a/test/runtime/samples/reactive-values-text-node/_config.js b/test/runtime/samples/reactive-values-text-node/_config.js
new file mode 100644
index 0000000000..fb859285dd
--- /dev/null
+++ b/test/runtime/samples/reactive-values-text-node/_config.js
@@ -0,0 +1,9 @@
+export default {
+ html:'
same text
',
+ async test({ assert, target }) {
+ await new Promise(f => setTimeout(f, 10));
+ assert.htmlEqual(target.innerHTML, `
+
same text text
+ `);
+ }
+};
diff --git a/test/runtime/samples/reactive-values-text-node/main.svelte b/test/runtime/samples/reactive-values-text-node/main.svelte
new file mode 100644
index 0000000000..0982622b1a
--- /dev/null
+++ b/test/runtime/samples/reactive-values-text-node/main.svelte
@@ -0,0 +1,8 @@
+
+
+
{text} text
diff --git a/test/runtime/samples/spread-width-height-attributes/_config.js b/test/runtime/samples/spread-width-height-attributes/_config.js
new file mode 100644
index 0000000000..cf2dc7efde
--- /dev/null
+++ b/test/runtime/samples/spread-width-height-attributes/_config.js
@@ -0,0 +1,4 @@
+export default {
+ // https://github.com/sveltejs/svelte/issues/6752
+ html: '
![]()
'
+};
diff --git a/test/runtime/samples/spread-width-height-attributes/main.svelte b/test/runtime/samples/spread-width-height-attributes/main.svelte
new file mode 100644
index 0000000000..b91b008457
--- /dev/null
+++ b/test/runtime/samples/spread-width-height-attributes/main.svelte
@@ -0,0 +1 @@
+
![]()
diff --git a/test/runtime/samples/transition-js-deferred-option-direction/_config.js b/test/runtime/samples/transition-js-deferred-option-direction/_config.js
index 2bf448d9c7..71adc5539f 100644
--- a/test/runtime/samples/transition-js-deferred-option-direction/_config.js
+++ b/test/runtime/samples/transition-js-deferred-option-direction/_config.js
@@ -4,16 +4,19 @@ export default {
const div_in = target.querySelector('#in');
const div_out = target.querySelector('#out');
- const div_both = target.querySelector('#both');
+ const div_bothin = target.querySelector('#both-in');
+ const div_bothout = target.querySelector('#both-out');
- assert.equal(div_in.initial, 'in');
- assert.equal(div_out.initial, 'out');
- assert.equal(div_both.initial, 'both');
+ assert.equal(div_in.directions, 'in,in');
+ assert.equal(div_out.directions, 'out');
+ assert.equal(div_bothin.directions, 'both');
+ assert.equal(div_bothout.directions, 'both');
return Promise.resolve().then(() => {
- assert.equal(div_in.later, 'in');
- assert.equal(div_out.later, 'out');
- assert.equal(div_both.later, 'both');
+ assert.equal(div_in.directions, 'in,in');
+ assert.equal(div_out.directions, 'out,out');
+ assert.equal(div_bothin.directions, 'both,in');
+ assert.equal(div_bothout.directions, 'both,out');
});
}
};
diff --git a/test/runtime/samples/transition-js-deferred-option-direction/main.svelte b/test/runtime/samples/transition-js-deferred-option-direction/main.svelte
index 9ac816ce75..76bca2b5e2 100644
--- a/test/runtime/samples/transition-js-deferred-option-direction/main.svelte
+++ b/test/runtime/samples/transition-js-deferred-option-direction/main.svelte
@@ -2,10 +2,10 @@
export let visible;
function foo(node, _params, options) {
- node.initial = options.direction;
+ node.directions = options.direction;
return (opts) => {
- node.later = opts.direction;
+ node.directions += "," + opts.direction;
return {
duration: 10
@@ -15,10 +15,11 @@
{#if visible}
-
-
+
+
{/if}
{#if !visible}
-
+
+
{/if}
diff --git a/test/sourcemaps/samples/compile-option-dev/test.js b/test/sourcemaps/samples/compile-option-dev/test.js
index f169ab8832..eec81fc93e 100644
--- a/test/sourcemaps/samples/compile-option-dev/test.js
+++ b/test/sourcemaps/samples/compile-option-dev/test.js
@@ -18,10 +18,13 @@ export async function test({ assert, css, js }) {
// TODO make util fn + move to test index.js
const sourcefile = 'input.svelte';
[
- // TODO how to get line + column numbers?
+ // TODO: get line and col num from input.svelte rather than hardcoding here
[css, '--keep-me', 13, 2],
- [css, '--done-replace-once', 6, 5],
- [css, '--done-replace-twice', 9, 5]
+ // TODO: these should be 7, 2 and 10, 2
+ // we use locate_1 which means lines are 1-indexed and cols are 0-indexed
+ // each tab is 1 col
+ [css, '--done-replace-once', 6, 4],
+ [css, '--done-replace-twice', 9, 4]
]
.forEach(([where, content, line, column]) => {
assert.deepEqual(
diff --git a/test/store/index.ts b/test/store/index.ts
index 7e8bdb2f64..920cabdc39 100644
--- a/test/store/index.ts
+++ b/test/store/index.ts
@@ -407,6 +407,25 @@ describe('store', () => {
const d = derived(fake_observable, _ => _);
assert.equal(get(d), 42);
});
+
+ it('doesn\'t restart when unsubscribed from another store with a shared ancestor', () => {
+ const a = writable(true);
+ let b_started = false;
+ const b = derived(a, (_, __) => {
+ b_started = true;
+ return () => {
+ assert.equal(b_started, true);
+ b_started = false;
+ };
+ });
+ const c = derived(a, ($a, set) => {
+ if ($a) return b.subscribe(set);
+ });
+
+ c.subscribe(() => { });
+ a.set(false);
+ assert.equal(b_started, false);
+ });
});
describe('get', () => {
diff --git a/test/utils/index.ts b/test/utils/index.ts
index a8aed9387a..37ba63b1c7 100644
--- a/test/utils/index.ts
+++ b/test/utils/index.ts
@@ -1,5 +1,6 @@
import * as assert from 'assert';
import { trim_start, trim_end } from '../../src/compiler/utils/trim';
+import { split_css_unit } from '../../src/runtime/internal/utils';
describe('utils', () => {
describe('trim', () => {
@@ -13,4 +14,17 @@ describe('utils', () => {
assert.equal(value, ' \r\n\t svelte content');
});
});
+
+ describe('split_css_unit', () => {
+ it('should use px as default', () => {
+ assert.deepEqual(split_css_unit(10), [10, 'px']);
+ assert.deepEqual(split_css_unit('10'), [10, 'px']);
+ });
+
+ it('should split the css notation into value and unit', () => {
+ assert.deepEqual(split_css_unit('-50%'), [-50, '%']);
+ assert.deepEqual(split_css_unit('0.1rem'), [0.1, 'rem']);
+ assert.deepEqual(split_css_unit('.1rem'), [0.1, 'rem']);
+ });
+ });
});
diff --git a/test/validator/samples/a11y-contenteditable-element-without-child/errors.json b/test/validator/samples/a11y-contenteditable-element-without-child/errors.json
index b4bd522c40..2d803d755a 100644
--- a/test/validator/samples/a11y-contenteditable-element-without-child/errors.json
+++ b/test/validator/samples/a11y-contenteditable-element-without-child/errors.json
@@ -1,7 +1,7 @@
[
{
"code": "missing-contenteditable-attribute",
- "message": "'contenteditable' attribute is required for textContent and innerHTML two-way bindings",
+ "message": "'contenteditable' attribute is required for textContent, innerHTML and innerText two-way bindings",
"start": {
"line": 6,
"column": 3
diff --git a/test/validator/samples/a11y-interactive-supports-focus/input.svelte b/test/validator/samples/a11y-interactive-supports-focus/input.svelte
new file mode 100644
index 0000000000..9caa9ccfaf
--- /dev/null
+++ b/test/validator/samples/a11y-interactive-supports-focus/input.svelte
@@ -0,0 +1,32 @@
+
+
{}} />
+
{}} />
+
{}} />
+
{}} />
+