diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 457ddb3bab..9a50cae9ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,10 @@ jobs: - uses: actions/setup-node@v1 - run: 'npm i && npm run lint' Unit: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b53d2b4b..9f5ae90395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,15 @@ ## Unreleased +* Update `` to `undefined` ([#3569](https://github.com/sveltejs/svelte/issues/3569)) +* Fix setting ` ``` + +> The `value` attribute of an `input` element or its children `option` elements must not be set with spread attributes when using `bind:group` or `bind:checked`. Svelte needs to be able to see the element's `value` directly in the markup in these cases so that it can link it to the bound variable. + --- ### Text expressions diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index 56c58634b7..460c393e7e 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -287,7 +287,9 @@ The second argument to `readable` is the same as the second argument to `writabl ```js import { readable } from 'svelte/store'; -const time = readable(new Date(), set => { +const time = readable(null, set => { + set(new Date()); + const interval = setInterval(() => { set(new Date()); }, 1000); @@ -521,7 +523,7 @@ $: $size = big ? 100 : 10; ### `svelte/transition` -The `svelte/transition` module exports six functions: `fade`, `fly`, `slide`, `scale`, `draw` and `crossfade`. They are for use with Svelte [`transitions`](docs#transition_fn). +The `svelte/transition` module exports seven functions: `fade`, `blur`, `fly`, `slide`, `scale`, `draw` and `crossfade`. They are for use with Svelte [`transitions`](docs#transition_fn). #### `fade` diff --git a/site/content/faq/300-is-svelte-dev-down.md b/site/content/faq/300-is-svelte-dev-down.md deleted file mode 100644 index a7ce9984b7..0000000000 --- a/site/content/faq/300-is-svelte-dev-down.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -question: Is svelte.dev down? ---- - -Probably not, but it's possible. If you can't seem to access any `.dev` sites, check out [this SuperUser question and answer](https://superuser.com/q/1413402). \ No newline at end of file diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index 2f199709c8..bcb07280b0 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -60,7 +60,7 @@ export default class Binding extends Node { scope.dependencies_for_name.get(name).forEach(name => { const variable = component.var_lookup.get(name); if (variable) { - variable[this.expression.node.type === 'MemberExpression' ? 'mutated' : 'reassigned'] = true; + variable.mutated = true; } }); } else { diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index b29b4d4afd..b77cf61112 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -299,7 +299,7 @@ export default class Block { ${this.chunks.mount} }`; } else { - properties.mount = x`function #mount(#target, #anchor, #remount) { + properties.mount = x`function #mount(#target, #anchor) { ${this.chunks.mount} }`; } @@ -452,6 +452,9 @@ export default class Block { render_listeners(chunk: string = '') { if (this.event_listeners.length > 0) { + this.add_variable({ type: 'Identifier', name: '#mounted' }); + this.chunks.destroy.push(b`#mounted = false`); + const dispose: Identifier = { type: 'Identifier', name: `#dispose${chunk}` @@ -462,8 +465,10 @@ export default class Block { if (this.event_listeners.length === 1) { this.chunks.mount.push( b` - if (#remount) ${dispose}(); - ${dispose} = ${this.event_listeners[0]}; + if (!#mounted) { + ${dispose} = ${this.event_listeners[0]}; + #mounted = true; + } ` ); @@ -472,10 +477,12 @@ export default class Block { ); } else { this.chunks.mount.push(b` - if (#remount) @run_all(${dispose}); - ${dispose} = [ - ${this.event_listeners} - ]; + if (!#mounted) { + ${dispose} = [ + ${this.event_listeners} + ]; + #mounted = true; + } `); this.chunks.destroy.push( diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 85f252f57e..ca941b7be9 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -102,25 +102,12 @@ export default class AttributeWrapper { } else if (is_select_value_attribute) { // annoying special case const is_multiple_select = element.node.get_static_attribute_value('multiple'); - const i = block.get_unique_name('i'); - const option = block.get_unique_name('option'); - - const if_statement = is_multiple_select - ? b` - ${option}.selected = ~${last}.indexOf(${option}.__value);` - : b` - if (${option}.__value === ${last}) { - ${option}.selected = true; - ${{ type: 'BreakStatement' }}; - }`; // TODO the BreakStatement is gross, but it's unsyntactic otherwise... - - updater = b` - for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) { - var ${option} = ${element.var}.options[${i}]; - - ${if_statement} - } - `; + + if (is_multiple_select) { + updater = b`@select_options(${element.var}, ${last});`; + } else { + updater = b`@select_option(${element.var}, ${last});`; + } block.chunks.mount.push(b` ${last} = ${value}; diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index ac5732eae7..6222eb04a4 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -87,7 +87,7 @@ export default class BindingWrapper { const update_conditions: any[] = this.needs_lock ? [x`!${lock}`] : []; const mount_conditions: any[] = []; - const dependency_array = [...this.node.expression.dependencies]; + const dependency_array = Array.from(this.get_dependencies()); if (dependency_array.length > 0) { update_conditions.push(block.renderer.dirty(dependency_array)); diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index a50e02e76a..83bc8be94e 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -705,10 +705,27 @@ export default class ElementWrapper extends Wrapper { ); block.chunks.update.push(b` - ${fn}(${this.var}, @get_spread_update(${levels}, [ + ${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [ ${updates} ])); `); + + // handle edge cases for elements + if (this.node.name === 'select') { + const dependencies = new Set(); + for (const attr of this.attributes) { + for (const dep of attr.node.dependencies) { + dependencies.add(dep); + } + } + + block.chunks.mount.push(b` + if (${data}.multiple) @select_options(${this.var}, ${data}.value); + `); + block.chunks.update.push(b` + if (${block.renderer.dirty(Array.from(dependencies))} && ${data}.multiple) @select_options(${this.var}, ${data}.value); + `); + } } add_transitions( diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 55ed031381..268875acaf 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -172,10 +172,7 @@ export default class SlotWrapper extends Wrapper { const slot_update = b` if (${slot}.p && ${renderer.dirty(dynamic_dependencies)}) { - ${slot}.p( - @get_slot_context(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn}), - @get_slot_changes(${slot_definition}, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}) - ); + @update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}, ${get_slot_context_fn}); } `; const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b` diff --git a/src/runtime/internal/keyed_each.ts b/src/runtime/internal/keyed_each.ts index 6b56010d46..b397335c87 100644 --- a/src/runtime/internal/keyed_each.ts +++ b/src/runtime/internal/keyed_each.ts @@ -56,7 +56,7 @@ export function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list function insert(block) { transition_in(block, 1); - block.m(node, next, lookup.has(block.key)); + block.m(node, next); lookup.set(block.key, block); next = block.first; n--; diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 487116b655..d752c9de9d 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -103,6 +103,14 @@ export function get_slot_changes(definition, $$scope, dirty, fn) { return $$scope.dirty; } +export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { + const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); + if (slot_changes) { + const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); + slot.p(slot_context, slot_changes); + } +} + export function exclude_internal_props(props) { const result = {}; for (const k in props) if (k[0] !== '$') result[k] = props[k]; diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index aa2941f404..cac2f61b44 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -14,6 +14,7 @@ import { function create_fragment(ctx) { let button; let foo_action; + let mounted; let dispose; return { @@ -21,10 +22,13 @@ function create_fragment(ctx) { button = element("button"); button.textContent = "foo"; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, button, anchor); - if (remount) dispose(); - dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1])); + + if (!mounted) { + dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1])); + mounted = true; + } }, p(ctx, [dirty]) { if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]); @@ -33,6 +37,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(button); + mounted = false; dispose(); } }; diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index 1b3f5cc945..d52960bddd 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -14,6 +14,7 @@ import { function create_fragment(ctx) { let a; let link_action; + let mounted; let dispose; return { @@ -22,16 +23,20 @@ function create_fragment(ctx) { a.textContent = "Test"; attr(a, "href", "#"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, a, anchor); - if (remount) dispose(); - dispose = action_destroyer(link_action = link.call(null, a)); + + if (!mounted) { + dispose = action_destroyer(link_action = link.call(null, a)); + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(a); + mounted = false; dispose(); } }; diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js index fa955e4fd5..887195bce1 100644 --- a/test/js/samples/bind-online/expected.js +++ b/test/js/samples/bind-online/expected.js @@ -10,23 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let mounted; let dispose; add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { c: noop, - m(target, anchor, remount) { - if (remount) run_all(dispose); - - dispose = [ - listen(window, "online", /*onlinestatuschanged*/ ctx[1]), - listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) - ]; + m(target, anchor) { + if (!mounted) { + dispose = [ + listen(window, "online", /*onlinestatuschanged*/ ctx[1]), + listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) + ]; + + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index 77b68f1b27..f600157c65 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -12,6 +12,7 @@ import { function create_fragment(ctx) { let details; + let mounted; let dispose; return { @@ -21,11 +22,14 @@ function create_fragment(ctx) { details.innerHTML = `summarycontent `; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, details, anchor); details.open = /*open*/ ctx[0]; - if (remount) dispose(); - dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*open*/ 1) { @@ -36,6 +40,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(details); + mounted = false; dispose(); } }; diff --git a/test/js/samples/bindings-readonly-order/expected.js b/test/js/samples/bindings-readonly-order/expected.js index 00e8a5bf00..0e845c65b8 100644 --- a/test/js/samples/bindings-readonly-order/expected.js +++ b/test/js/samples/bindings-readonly-order/expected.js @@ -17,6 +17,7 @@ function create_fragment(ctx) { let input0; let t; let input1; + let mounted; let dispose; return { @@ -27,16 +28,19 @@ function create_fragment(ctx) { attr(input0, "type", "file"); attr(input1, "type", "file"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input0, anchor); insert(target, t, anchor); insert(target, input1, anchor); - if (remount) run_all(dispose); - dispose = [ - listen(input0, "change", /*input0_change_handler*/ ctx[1]), - listen(input1, "change", /*input1_change_handler*/ ctx[2]) - ]; + if (!mounted) { + dispose = [ + listen(input0, "change", /*input0_change_handler*/ ctx[1]), + listen(input1, "change", /*input1_change_handler*/ ctx[2]) + ]; + + mounted = true; + } }, p: noop, i: noop, @@ -45,6 +49,7 @@ function create_fragment(ctx) { if (detaching) detach(input0); if (detaching) detach(t); if (detaching) detach(input1); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/capture-inject-dev-only/expected.js b/test/js/samples/capture-inject-dev-only/expected.js index 3e355e1491..a87693dd9e 100644 --- a/test/js/samples/capture-inject-dev-only/expected.js +++ b/test/js/samples/capture-inject-dev-only/expected.js @@ -20,6 +20,7 @@ function create_fragment(ctx) { let t0; let t1; let input; + let mounted; let dispose; return { @@ -29,14 +30,17 @@ function create_fragment(ctx) { t1 = space(); input = element("input"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, p, anchor); append(p, t0); insert(target, t1, anchor); insert(target, input, anchor); set_input_value(input, /*foo*/ ctx[0]); - if (remount) dispose(); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]); @@ -51,6 +55,7 @@ function create_fragment(ctx) { if (detaching) detach(p); if (detaching) detach(t1); if (detaching) detach(input); + mounted = false; dispose(); } }; diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index c032a0636d..8a27ab6b24 100644 --- a/test/js/samples/component-static-var/expected.js +++ b/test/js/samples/component-static-var/expected.js @@ -24,6 +24,7 @@ function create_fragment(ctx) { let t1; let input; let current; + let mounted; let dispose; const foo = new Foo({ props: { x: y } }); const bar = new Bar({ props: { x: /*z*/ ctx[0] } }); @@ -36,7 +37,7 @@ function create_fragment(ctx) { t1 = space(); input = element("input"); }, - m(target, anchor, remount) { + m(target, anchor) { mount_component(foo, target, anchor); insert(target, t0, anchor); mount_component(bar, target, anchor); @@ -44,8 +45,11 @@ function create_fragment(ctx) { insert(target, input, anchor); set_input_value(input, /*z*/ ctx[0]); current = true; - if (remount) dispose(); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { const bar_changes = {}; @@ -73,6 +77,7 @@ function create_fragment(ctx) { destroy_component(bar, detaching); if (detaching) detach(t1); if (detaching) detach(input); + mounted = false; dispose(); } }; diff --git a/test/js/samples/component-store-reassign-invalidate/expected.js b/test/js/samples/component-store-reassign-invalidate/expected.js index b33047d8f3..0cf555bf0d 100644 --- a/test/js/samples/component-store-reassign-invalidate/expected.js +++ b/test/js/samples/component-store-reassign-invalidate/expected.js @@ -22,6 +22,7 @@ function create_fragment(ctx) { let t0; let t1; let button; + let mounted; let dispose; return { @@ -32,13 +33,16 @@ function create_fragment(ctx) { button = element("button"); button.textContent = "reset"; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, h1, anchor); append(h1, t0); insert(target, t1, anchor); insert(target, button, anchor); - if (remount) dispose(); - dispose = listen(button, "click", /*click_handler*/ ctx[2]); + + if (!mounted) { + dispose = listen(button, "click", /*click_handler*/ ctx[2]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]); @@ -49,6 +53,7 @@ function create_fragment(ctx) { if (detaching) detach(h1); if (detaching) detach(t1); if (detaching) detach(button); + mounted = false; dispose(); } }; diff --git a/test/js/samples/dont-invalidate-this/expected.js b/test/js/samples/dont-invalidate-this/expected.js index ba9e7152d7..0b155373a1 100644 --- a/test/js/samples/dont-invalidate-this/expected.js +++ b/test/js/samples/dont-invalidate-this/expected.js @@ -12,22 +12,27 @@ import { function create_fragment(ctx) { let input; + let mounted; let dispose; return { c() { input = element("input"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input, anchor); - if (remount) dispose(); - dispose = listen(input, "input", make_uppercase); + + if (!mounted) { + dispose = listen(input, "input", make_uppercase); + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(input); + mounted = false; dispose(); } }; diff --git a/test/js/samples/event-handler-dynamic/expected.js b/test/js/samples/event-handler-dynamic/expected.js index d8f5710023..dacdfe15ac 100644 --- a/test/js/samples/event-handler-dynamic/expected.js +++ b/test/js/samples/event-handler-dynamic/expected.js @@ -26,6 +26,7 @@ function create_fragment(ctx) { let t4; let t5; let button2; + let mounted; let dispose; return { @@ -43,7 +44,7 @@ function create_fragment(ctx) { button2 = element("button"); button2.textContent = "click"; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, p0, anchor); append(p0, button0); append(p0, t1); @@ -53,15 +54,18 @@ function create_fragment(ctx) { append(p1, t4); insert(target, t5, anchor); insert(target, button2, anchor); - if (remount) run_all(dispose); - dispose = [ - listen(button0, "click", /*updateHandler1*/ ctx[2]), - listen(button1, "click", /*updateHandler2*/ ctx[3]), - listen(button2, "click", function () { - if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments); - }) - ]; + if (!mounted) { + dispose = [ + listen(button0, "click", /*updateHandler1*/ ctx[2]), + listen(button1, "click", /*updateHandler2*/ ctx[3]), + listen(button2, "click", function () { + if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments); + }) + ]; + + mounted = true; + } }, p(new_ctx, [dirty]) { ctx = new_ctx; @@ -75,6 +79,7 @@ function create_fragment(ctx) { if (detaching) detach(p1); if (detaching) detach(t5); if (detaching) detach(button2); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js index 8bf2de7693..4d4b910d4e 100644 --- a/test/js/samples/event-handler-no-passive/expected.js +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -13,6 +13,7 @@ import { function create_fragment(ctx) { let a; + let mounted; let dispose; return { @@ -21,16 +22,20 @@ function create_fragment(ctx) { a.textContent = "this should not navigate to example.com"; attr(a, "href", "https://example.com"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, a, anchor); - if (remount) dispose(); - dispose = listen(a, "touchstart", touchstart_handler); + + if (!mounted) { + dispose = listen(a, "touchstart", touchstart_handler); + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(a); + mounted = false; dispose(); } }; diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index 2eca5f29b8..6aa3c161f9 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -22,6 +22,7 @@ function create_fragment(ctx) { let button1; let t3; let button2; + let mounted; let dispose; return { @@ -36,27 +37,31 @@ function create_fragment(ctx) { button2 = element("button"); button2.textContent = "or me!"; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, div, anchor); append(div, button0); append(div, t1); append(div, button1); append(div, t3); append(div, button2); - if (remount) run_all(dispose); - dispose = [ - listen(button0, "click", stop_propagation(prevent_default(handleClick))), - listen(button1, "click", handleClick, { once: true, capture: true }), - listen(button2, "click", handleClick, true), - listen(div, "touchstart", handleTouchstart, { passive: true }) - ]; + if (!mounted) { + dispose = [ + listen(button0, "click", stop_propagation(prevent_default(handleClick))), + listen(button1, "click", handleClick, { once: true, capture: true }), + listen(button2, "click", handleClick, true), + listen(div, "touchstart", handleTouchstart, { passive: true }) + ]; + + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(div); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js index 1c1e57fc9b..0069c2e5f8 100644 --- a/test/js/samples/input-files/expected.js +++ b/test/js/samples/input-files/expected.js @@ -13,6 +13,7 @@ import { function create_fragment(ctx) { let input; + let mounted; let dispose; return { @@ -21,16 +22,20 @@ function create_fragment(ctx) { attr(input, "type", "file"); input.multiple = true; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input, anchor); - if (remount) dispose(); - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(input); + mounted = false; dispose(); } }; diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js index f72daa22a3..3354aa3111 100644 --- a/test/js/samples/input-no-initial-value/expected.js +++ b/test/js/samples/input-no-initial-value/expected.js @@ -20,6 +20,7 @@ function create_fragment(ctx) { let input; let t0; let button; + let mounted; let dispose; return { @@ -32,18 +33,21 @@ function create_fragment(ctx) { attr(input, "type", "text"); input.required = true; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, form, anchor); append(form, input); set_input_value(input, /*test*/ ctx[0]); append(form, t0); append(form, button); - if (remount) run_all(dispose); - dispose = [ - listen(input, "input", /*input_input_handler*/ ctx[2]), - listen(form, "submit", /*handleSubmit*/ ctx[1]) - ]; + if (!mounted) { + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[2]), + listen(form, "submit", /*handleSubmit*/ ctx[1]) + ]; + + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*test*/ 1 && input.value !== /*test*/ ctx[0]) { @@ -54,6 +58,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(form); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js index 17a8065449..770baa29ed 100644 --- a/test/js/samples/input-range/expected.js +++ b/test/js/samples/input-range/expected.js @@ -16,6 +16,7 @@ import { function create_fragment(ctx) { let input; + let mounted; let dispose; return { @@ -23,15 +24,18 @@ function create_fragment(ctx) { input = element("input"); attr(input, "type", "range"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input, anchor); set_input_value(input, /*value*/ ctx[0]); - if (remount) run_all(dispose); - dispose = [ - listen(input, "change", /*input_change_input_handler*/ ctx[1]), - listen(input, "input", /*input_change_input_handler*/ ctx[1]) - ]; + if (!mounted) { + dispose = [ + listen(input, "change", /*input_change_input_handler*/ ctx[1]), + listen(input, "input", /*input_change_input_handler*/ ctx[1]) + ]; + + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*value*/ 1) { @@ -42,6 +46,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(input); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/input-value/expected.js b/test/js/samples/input-value/expected.js index 31be2895ac..781a2ae603 100644 --- a/test/js/samples/input-value/expected.js +++ b/test/js/samples/input-value/expected.js @@ -20,6 +20,7 @@ function create_fragment(ctx) { let h1; let t1; let t2; + let mounted; let dispose; return { @@ -31,14 +32,17 @@ function create_fragment(ctx) { t2 = text("!"); input.value = /*name*/ ctx[0]; }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input, anchor); insert(target, t0, anchor); insert(target, h1, anchor); append(h1, t1); append(h1, t2); - if (remount) dispose(); - dispose = listen(input, "input", /*onInput*/ ctx[1]); + + if (!mounted) { + dispose = listen(input, "input", /*onInput*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*name*/ 1 && input.value !== /*name*/ ctx[0]) { @@ -53,6 +57,7 @@ function create_fragment(ctx) { if (detaching) detach(input); if (detaching) detach(t0); if (detaching) detach(h1); + mounted = false; dispose(); } }; diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index 1e379032f3..f19f74dc1e 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -13,6 +13,7 @@ import { function create_fragment(ctx) { let input; + let mounted; let dispose; return { @@ -20,11 +21,14 @@ function create_fragment(ctx) { input = element("input"); attr(input, "type", "checkbox"); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, input, anchor); input.checked = /*foo*/ ctx[0]; - if (remount) dispose(); - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) { @@ -35,6 +39,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(input); + mounted = false; dispose(); } }; diff --git a/test/js/samples/instrumentation-script-if-no-block/expected.js b/test/js/samples/instrumentation-script-if-no-block/expected.js index f45e52aebd..7f51c64550 100644 --- a/test/js/samples/instrumentation-script-if-no-block/expected.js +++ b/test/js/samples/instrumentation-script-if-no-block/expected.js @@ -20,6 +20,7 @@ function create_fragment(ctx) { let p; let t2; let t3; + let mounted; let dispose; return { @@ -31,14 +32,17 @@ function create_fragment(ctx) { t2 = text("x: "); t3 = text(/*x*/ ctx[0]); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); insert(target, p, anchor); append(p, t2); append(p, t3); - if (remount) dispose(); - dispose = listen(button, "click", /*foo*/ ctx[1]); + + if (!mounted) { + dispose = listen(button, "click", /*foo*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); @@ -49,6 +53,7 @@ function create_fragment(ctx) { if (detaching) detach(button); if (detaching) detach(t1); if (detaching) detach(p); + mounted = false; dispose(); } }; diff --git a/test/js/samples/instrumentation-script-x-equals-x/expected.js b/test/js/samples/instrumentation-script-x-equals-x/expected.js index 9fe9640978..ea0d65acb9 100644 --- a/test/js/samples/instrumentation-script-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js @@ -21,6 +21,7 @@ function create_fragment(ctx) { let t2; let t3_value = /*things*/ ctx[0].length + ""; let t3; + let mounted; let dispose; return { @@ -32,14 +33,17 @@ function create_fragment(ctx) { t2 = text("number of things: "); t3 = text(t3_value); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); insert(target, p, anchor); append(p, t2); append(p, t3); - if (remount) dispose(); - dispose = listen(button, "click", /*foo*/ ctx[1]); + + if (!mounted) { + dispose = listen(button, "click", /*foo*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); @@ -50,6 +54,7 @@ function create_fragment(ctx) { if (detaching) detach(button); if (detaching) detach(t1); if (detaching) detach(p); + mounted = false; dispose(); } }; diff --git a/test/js/samples/instrumentation-template-if-no-block/expected.js b/test/js/samples/instrumentation-template-if-no-block/expected.js index 6f3bea4010..0c2713a9cc 100644 --- a/test/js/samples/instrumentation-template-if-no-block/expected.js +++ b/test/js/samples/instrumentation-template-if-no-block/expected.js @@ -20,6 +20,7 @@ function create_fragment(ctx) { let p; let t2; let t3; + let mounted; let dispose; return { @@ -31,14 +32,17 @@ function create_fragment(ctx) { t2 = text("x: "); t3 = text(/*x*/ ctx[0]); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); insert(target, p, anchor); append(p, t2); append(p, t3); - if (remount) dispose(); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(button, "click", /*click_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); @@ -49,6 +53,7 @@ function create_fragment(ctx) { if (detaching) detach(button); if (detaching) detach(t1); if (detaching) detach(p); + mounted = false; dispose(); } }; diff --git a/test/js/samples/instrumentation-template-x-equals-x/expected.js b/test/js/samples/instrumentation-template-x-equals-x/expected.js index ed095353bd..55cd310661 100644 --- a/test/js/samples/instrumentation-template-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-template-x-equals-x/expected.js @@ -21,6 +21,7 @@ function create_fragment(ctx) { let t2; let t3_value = /*things*/ ctx[0].length + ""; let t3; + let mounted; let dispose; return { @@ -32,14 +33,17 @@ function create_fragment(ctx) { t2 = text("number of things: "); t3 = text(t3_value); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); insert(target, p, anchor); append(p, t2); append(p, t3); - if (remount) dispose(); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); + + if (!mounted) { + dispose = listen(button, "click", /*click_handler*/ ctx[1]); + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); @@ -50,6 +54,7 @@ function create_fragment(ctx) { if (detaching) detach(button); if (detaching) detach(t1); if (detaching) detach(p); + mounted = false; dispose(); } }; diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index 0849a38b51..bcbc0647b8 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -19,6 +19,7 @@ function create_fragment(ctx) { let audio_updating = false; let audio_animationframe; let audio_is_paused = true; + let mounted; let dispose; function audio_timeupdate_handler() { @@ -42,7 +43,7 @@ function create_fragment(ctx) { if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[18].call(audio)); if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[19].call(audio)); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, audio, anchor); if (!isNaN(/*volume*/ ctx[6])) { @@ -55,21 +56,23 @@ function create_fragment(ctx) { audio.playbackRate = /*playbackRate*/ ctx[8]; } - if (remount) run_all(dispose); - - dispose = [ - listen(audio, "progress", /*audio_progress_handler*/ ctx[11]), - listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[12]), - listen(audio, "timeupdate", audio_timeupdate_handler), - listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[14]), - listen(audio, "play", /*audio_play_pause_handler*/ ctx[15]), - listen(audio, "pause", /*audio_play_pause_handler*/ ctx[15]), - listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[16]), - listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[17]), - listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[18]), - listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[18]), - listen(audio, "ended", /*audio_ended_handler*/ ctx[19]) - ]; + if (!mounted) { + dispose = [ + listen(audio, "progress", /*audio_progress_handler*/ ctx[11]), + listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[12]), + listen(audio, "timeupdate", audio_timeupdate_handler), + listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[14]), + listen(audio, "play", /*audio_play_pause_handler*/ ctx[15]), + listen(audio, "pause", /*audio_play_pause_handler*/ ctx[15]), + listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[16]), + listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[17]), + listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[18]), + listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[18]), + listen(audio, "ended", /*audio_ended_handler*/ ctx[19]) + ]; + + mounted = true; + } }, p(ctx, [dirty]) { if (!audio_updating && dirty & /*currentTime*/ 8 && !isNaN(/*currentTime*/ ctx[3])) { @@ -98,6 +101,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(audio); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/select-dynamic-value/expected.js b/test/js/samples/select-dynamic-value/expected.js index a93a47bd3a..f1a913c65f 100644 --- a/test/js/samples/select-dynamic-value/expected.js +++ b/test/js/samples/select-dynamic-value/expected.js @@ -7,7 +7,8 @@ import { init, insert, noop, - safe_not_equal + safe_not_equal, + select_option } from "svelte/internal"; function create_fragment(ctx) { @@ -33,26 +34,11 @@ function create_fragment(ctx) { append(select, option0); append(select, option1); select_value_value = /*current*/ ctx[0]; - - for (var i = 0; i < select.options.length; i += 1) { - var option = select.options[i]; - - if (option.__value === select_value_value) { - option.selected = true; - break; - } - } + select_option(select, select_value_value); }, p(ctx, [dirty]) { if (dirty & /*current*/ 1 && select_value_value !== (select_value_value = /*current*/ ctx[0])) { - for (var i = 0; i < select.options.length; i += 1) { - var option = select.options[i]; - - if (option.__value === select_value_value) { - option.selected = true; - break; - } - } + select_option(select, select_value_value); } }, i: noop, diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js index 9c5467e1a0..d3920ef8c2 100644 --- a/test/js/samples/video-bindings/expected.js +++ b/test/js/samples/video-bindings/expected.js @@ -19,6 +19,7 @@ function create_fragment(ctx) { let video_updating = false; let video_animationframe; let video_resize_listener; + let mounted; let dispose; function video_timeupdate_handler() { @@ -38,15 +39,18 @@ function create_fragment(ctx) { if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[5].call(video)); add_render_callback(() => /*video_elementresize_handler*/ ctx[6].call(video)); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, video, anchor); video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video)); - if (remount) run_all(dispose); - dispose = [ - listen(video, "timeupdate", video_timeupdate_handler), - listen(video, "resize", /*video_resize_handler*/ ctx[5]) - ]; + if (!mounted) { + dispose = [ + listen(video, "timeupdate", video_timeupdate_handler), + listen(video, "resize", /*video_resize_handler*/ ctx[5]) + ]; + + mounted = true; + } }, p(ctx, [dirty]) { if (!video_updating && dirty & /*currentTime*/ 1 && !isNaN(/*currentTime*/ ctx[0])) { @@ -60,6 +64,7 @@ function create_fragment(ctx) { d(detaching) { if (detaching) detach(video); video_resize_listener(); + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/window-binding-online/expected.js b/test/js/samples/window-binding-online/expected.js index fa955e4fd5..887195bce1 100644 --- a/test/js/samples/window-binding-online/expected.js +++ b/test/js/samples/window-binding-online/expected.js @@ -10,23 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let mounted; let dispose; add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { c: noop, - m(target, anchor, remount) { - if (remount) run_all(dispose); - - dispose = [ - listen(window, "online", /*onlinestatuschanged*/ ctx[1]), - listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) - ]; + m(target, anchor) { + if (!mounted) { + dispose = [ + listen(window, "online", /*onlinestatuschanged*/ ctx[1]), + listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) + ]; + + mounted = true; + } }, p: noop, i: noop, o: noop, d(detaching) { + mounted = false; run_all(dispose); } }; diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index 30723cc142..45d992c721 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -25,6 +25,7 @@ function create_fragment(ctx) { let p; let t0; let t1; + let mounted; let dispose; add_render_callback(/*onwindowscroll*/ ctx[1]); @@ -34,18 +35,21 @@ function create_fragment(ctx) { t0 = text("scrolled to "); t1 = text(/*y*/ ctx[0]); }, - m(target, anchor, remount) { + m(target, anchor) { insert(target, p, anchor); append(p, t0); append(p, t1); - if (remount) dispose(); - dispose = listen(window, "scroll", () => { - scrolling = true; - clearTimeout(scrolling_timeout); - scrolling_timeout = setTimeout(clear_scrolling, 100); - /*onwindowscroll*/ ctx[1](); - }); + if (!mounted) { + dispose = listen(window, "scroll", () => { + scrolling = true; + clearTimeout(scrolling_timeout); + scrolling_timeout = setTimeout(clear_scrolling, 100); + /*onwindowscroll*/ ctx[1](); + }); + + mounted = true; + } }, p(ctx, [dirty]) { if (dirty & /*y*/ 1 && !scrolling) { @@ -61,6 +65,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(p); + mounted = false; dispose(); } }; diff --git a/test/runtime/samples/binding-select-late-2/_config.js b/test/runtime/samples/binding-select-late-2/_config.js new file mode 100644 index 0000000000..42c45d1366 --- /dev/null +++ b/test/runtime/samples/binding-select-late-2/_config.js @@ -0,0 +1,34 @@ +export default { + props: { + items: [], + selected: 'two' + }, + + html: ` + +

selected: two

+ `, + + ssrHtml: ` + +

selected: two

+ `, + + test({ assert, component, target }) { + component.items = [ 'one', 'two', 'three' ]; + + const options = target.querySelectorAll('option'); + assert.ok(!options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + + assert.htmlEqual(target.innerHTML, ` + +

selected: two

+ `); + } +}; diff --git a/test/runtime/samples/binding-select-late-2/main.svelte b/test/runtime/samples/binding-select-late-2/main.svelte new file mode 100644 index 0000000000..52cc14528a --- /dev/null +++ b/test/runtime/samples/binding-select-late-2/main.svelte @@ -0,0 +1,12 @@ + + + + +

selected: {selected || 'nothing'}

\ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-6/Slotted.svelte b/test/runtime/samples/bitmask-overflow-slot-6/Slotted.svelte new file mode 100644 index 0000000000..322a31359e --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-6/Slotted.svelte @@ -0,0 +1,15 @@ + + +
+ + + + {#if open} + + {/if} +
diff --git a/test/runtime/samples/bitmask-overflow-slot-6/_config.js b/test/runtime/samples/bitmask-overflow-slot-6/_config.js new file mode 100644 index 0000000000..8cd8c07a65 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-6/_config.js @@ -0,0 +1,32 @@ +// overflow bitmask + slot missing `let:` +export default { + html: ` +
+ +
+ + `, + + async test({ assert, component, target, window }) { + const button = target.querySelectorAll('button')[1]; + const div = target.querySelector('div'); + await div.dispatchEvent(new window.MouseEvent('click')); + + assert.htmlEqual(target.innerHTML, ` +
+ +
Open
+
+ + `); + + await button.dispatchEvent(new window.MouseEvent('click')); + assert.htmlEqual(target.innerHTML, ` +
+ +
Open
+
+ + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-6/main.svelte b/test/runtime/samples/bitmask-overflow-slot-6/main.svelte new file mode 100644 index 0000000000..8845cb2ef5 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-6/main.svelte @@ -0,0 +1,23 @@ + + + + + +
+ Open +
+
+ + \ No newline at end of file diff --git a/test/runtime/samples/each-block-keyed-component-action/Component.svelte b/test/runtime/samples/each-block-keyed-component-action/Component.svelte new file mode 100644 index 0000000000..18a6c7452a --- /dev/null +++ b/test/runtime/samples/each-block-keyed-component-action/Component.svelte @@ -0,0 +1,5 @@ + + +
diff --git a/test/runtime/samples/each-block-keyed-component-action/_config.js b/test/runtime/samples/each-block-keyed-component-action/_config.js new file mode 100644 index 0000000000..c4421f89ae --- /dev/null +++ b/test/runtime/samples/each-block-keyed-component-action/_config.js @@ -0,0 +1,21 @@ +export default { + test({ assert, component, raf }) { + assert.equal(component.count, 0); + + component.arr = ["2"]; + + assert.equal(component.count, 1); + + component.arr = ["1", "2"]; + + assert.equal(component.count, 2); + + component.arr = ["2", "1"]; + + assert.equal(component.count, 2); + + component.arr = []; + + assert.equal(component.count, 0); + }, +}; diff --git a/test/runtime/samples/each-block-keyed-component-action/main.svelte b/test/runtime/samples/each-block-keyed-component-action/main.svelte new file mode 100644 index 0000000000..bfacdf402a --- /dev/null +++ b/test/runtime/samples/each-block-keyed-component-action/main.svelte @@ -0,0 +1,17 @@ + + +{#each arr as item (item)} + +{/each} diff --git a/test/runtime/samples/reactive-function-called-reassigned/_config.js b/test/runtime/samples/reactive-function-called-reassigned/_config.js new file mode 100644 index 0000000000..317173f8eb --- /dev/null +++ b/test/runtime/samples/reactive-function-called-reassigned/_config.js @@ -0,0 +1,27 @@ +let value; +let called = 0; +function callback(_value) { + called ++; + value = _value; +} + +export default { + props: { + callback, + }, + async test({ assert, component, target, window }) { + assert.equal(called, 1); + + const input = target.querySelector('input'); + + const event = new window.Event('input'); + input.value = 'h'; + await input.dispatchEvent(event); + + assert.equal(called, 2); + assert.equal(value.length, 3); + assert.equal(value[0], 'h'); + assert.equal(value[1], '2'); + assert.equal(value[2], '3'); + } +}; diff --git a/test/runtime/samples/reactive-function-called-reassigned/main.svelte b/test/runtime/samples/reactive-function-called-reassigned/main.svelte new file mode 100644 index 0000000000..10a3c79d14 --- /dev/null +++ b/test/runtime/samples/reactive-function-called-reassigned/main.svelte @@ -0,0 +1,10 @@ + + +{#each refs as ref} + +{/each} \ No newline at end of file diff --git a/test/runtime/samples/spread-element-input-seelct-multiple/_config.js b/test/runtime/samples/spread-element-input-seelct-multiple/_config.js new file mode 100644 index 0000000000..1ddcd9eb6d --- /dev/null +++ b/test/runtime/samples/spread-element-input-seelct-multiple/_config.js @@ -0,0 +1,39 @@ +export default { + async test({ assert, component, target, window }) { + const [input1, input2] = target.querySelectorAll('input'); + const select = target.querySelector('select'); + const [option1, option2] = select.childNodes; + + let selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 2); + assert.ok(selections.includes(option1)); + assert.ok(selections.includes(option2)); + + const event = new window.Event('change'); + + input1.checked = false; + await input1.dispatchEvent(event); + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(!selections.includes(option1)); + assert.ok(selections.includes(option2)); + + input2.checked = false; + await input2.dispatchEvent(event); + input1.checked = true; + await input1.dispatchEvent(event); + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(selections.includes(option1)); + assert.ok(!selections.includes(option2)); + + component.spread = { value: ['Hello', 'World'] }; + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 2); + assert.ok(selections.includes(option1)); + assert.ok(selections.includes(option2)); + } +}; diff --git a/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte b/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte new file mode 100644 index 0000000000..d2fb12dd20 --- /dev/null +++ b/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file