diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e0ce53864..0a4d83558f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,47 +6,12 @@ on: permissions: contents: read # to fetch code (actions/checkout) jobs: - Setup: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: npm - - run: npm install - env: - SKIP_PREPARE: true - - run: npm run build - env: - PUBLISH: true - - name: Upload build assets - id: upload-artifact - uses: actions/upload-artifact@v3 - with: - name: build-assets - path: | - index.* - compiler.* - ssr.* - action/ - animate/ - easing/ - internal/ - motion/ - store/ - transition/ - types/ Tests: - needs: Setup runs-on: ${{ matrix.os }} timeout-minutes: 15 strategy: matrix: - node-version: [8, 10, 12, 14, 16, 18] + node-version: [14, 16, 18] os: [ubuntu-latest, windows-latest, macOS-latest] steps: - uses: actions/checkout@v3 @@ -54,24 +19,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: npm - - name: Download build assets - uses: actions/download-artifact@v3 - id: download-artifact - with: - name: build-assets - - name: Get Node version ${{ runner.os }} - run: echo "NODE_VERSION=`node --version`" >> $GITHUB_ENV - if: runner.os != 'Windows' - - name: Get Node version ${{ runner.os }} - run: | - chcp 65001 - echo ("NODE_VERSION=$(node --version)") >> $env:GITHUB_ENV - if: runner.os == 'Windows' - - run: npm install --save-dev puppeteer@13 - if: ${{ runner.os == 'Linux' && (!startsWith(env.NODE_VERSION, 'v8.') && !startsWith(env.NODE_VERSION, 'v10.')) }} - run: npm install - env: - SKIP_PREPARE: true - run: npm run test:integration env: CI: true diff --git a/CHANGELOG.md b/CHANGELOG.md index ede7feaf22..44b50c6951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,44 +1,80 @@ # Svelte changelog -## Unreleased - +## Unreleased (4.0) + +* Minimum supported Node version is now Node 14 + +## Unreleased (3.0) + +* Handle `width`/`height` attributes when spreading ([#6752](https://github.com/sveltejs/svelte/issues/6752)) +* Add support for resize observer bindings (`
`) ([#8022](https://github.com/sveltejs/svelte/pull/8022)) + +## 3.58.0 + +* Add `bind:innerText` for `contenteditable` elements ([#3311](https://github.com/sveltejs/svelte/issues/3311)) +* Add support for CSS `@container` queries ([#6969](https://github.com/sveltejs/svelte/issues/6969)) +* Respect `preserveComments` in DOM output ([#7182](https://github.com/sveltejs/svelte/pull/7182)) +* Allow use of `document` for `target` in typings ([#7554](https://github.com/sveltejs/svelte/pull/7554)) +* Add `a11y-interactive-supports-focus` warning ([#8392](https://github.com/sveltejs/svelte/pull/8392)) +* Fix equality check when updating dynamic text ([#5931](https://github.com/sveltejs/svelte/issues/5931)) +* Relax `a11y-no-noninteractive-element-to-interactive-role` warning ([#8402](https://github.com/sveltejs/svelte/pull/8402)) +* Properly handle microdata attributes ([#8413](https://github.com/sveltejs/svelte/issues/8413)) +* Prevent name collision when using computed destructuring variables ([#8417](https://github.com/sveltejs/svelte/issues/8417)) +* Fix escaping `', + 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
+
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + 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, + ` +
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + 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
+
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + 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, + ` +
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + 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 values as value (value)} +
  • + +
  • + {/each} +
+{/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 @@ + +
{}} /> +
{}} /> +
{}} /> +
{}} /> +