From a422d2aba5661d9f9ca54db8a1e7b11692d4cde4 Mon Sep 17 00:00:00 2001
From: Tan Li Hau <tanhauhau@users.noreply.github.com>
Date: Sat, 11 Jan 2020 22:01:40 +0800
Subject: [PATCH] fix actions having no access to parent nodes (#4252)

---
 CHANGELOG.md                                  |  1 +
 src/compiler/compile/render_dom/Block.ts      |  4 ++--
 .../action-custom-event-handler/expected.js   |  4 ++--
 test/js/samples/action/expected.js            |  2 +-
 test/js/samples/bind-online/expected.js       |  4 ++--
 test/js/samples/bind-open/expected.js         |  3 +--
 .../bindings-readonly-order/expected.js       | 10 ++++-----
 .../capture-inject-dev-only/expected.js       |  2 +-
 .../samples/component-static-var/expected.js  |  2 +-
 .../expected.js                               |  2 +-
 .../samples/dont-invalidate-this/expected.js  |  2 +-
 .../samples/event-handler-dynamic/expected.js | 16 +++++++-------
 .../event-handler-no-passive/expected.js      |  2 +-
 test/js/samples/event-modifiers/expected.js   | 14 ++++++------
 test/js/samples/input-files/expected.js       |  2 +-
 .../input-no-initial-value/expected.js        | 10 ++++-----
 test/js/samples/input-range/expected.js       |  8 +++----
 test/js/samples/input-value/expected.js       |  2 +-
 .../input-without-blowback-guard/expected.js  |  2 +-
 .../expected.js                               |  2 +-
 .../expected.js                               |  2 +-
 .../expected.js                               |  2 +-
 .../expected.js                               |  2 +-
 test/js/samples/media-bindings/expected.js    | 22 +++++++++----------
 test/js/samples/video-bindings/expected.js    |  8 +++----
 .../samples/window-binding-online/expected.js |  4 ++--
 .../samples/window-binding-scroll/expected.js | 10 ++++-----
 .../_config.js                                |  8 +++++++
 .../main.svelte                               |  8 +++++++
 29 files changed, 88 insertions(+), 72 deletions(-)
 create mode 100644 test/runtime/samples/action-receives-element-mounted/_config.js
 create mode 100644 test/runtime/samples/action-receives-element-mounted/main.svelte

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e5d5df95f..f6af419913 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 * Prevent text input cursor jumping in Safari with one-way binding ([#3449](https://github.com/sveltejs/svelte/issues/3449))
 * Expose compiler version in dev events ([#4047](https://github.com/sveltejs/svelte/issues/4047))
+* Don't run actions before their element is in the document ([#4166](https://github.com/sveltejs/svelte/issues/4166))
 * Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170))
 * Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212))
 
diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts
index c8fa884721..68d28024fe 100644
--- a/src/compiler/compile/render_dom/Block.ts
+++ b/src/compiler/compile/render_dom/Block.ts
@@ -450,7 +450,7 @@ export default class Block {
 			this.add_variable(dispose);
 
 			if (this.event_listeners.length === 1) {
-				this.chunks.hydrate.push(
+				this.chunks.mount.push(
 					b`${dispose} = ${this.event_listeners[0]};`
 				);
 
@@ -458,7 +458,7 @@ export default class Block {
 					b`${dispose}();`
 				);
 			} else {
-				this.chunks.hydrate.push(b`
+				this.chunks.mount.push(b`
 					${dispose} = [
 						${this.event_listeners}
 					];
diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js
index da42603895..968b5965d5 100644
--- a/test/js/samples/action-custom-event-handler/expected.js
+++ b/test/js/samples/action-custom-event-handler/expected.js
@@ -20,10 +20,10 @@ function create_fragment(ctx) {
 		c() {
 			button = element("button");
 			button.textContent = "foo";
-			dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
 		},
 		m(target, anchor) {
 			insert(target, button, anchor);
+			dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
 		},
 		p(ctx, [dirty]) {
 			if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
@@ -42,7 +42,7 @@ function handleFoo(bar) {
 }
 
 function foo(node, callback) {
-
+	
 }
 
 function instance($$self, $$props, $$invalidate) {
diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js
index dc3ebb5cf8..22d9cd939c 100644
--- a/test/js/samples/action/expected.js
+++ b/test/js/samples/action/expected.js
@@ -21,10 +21,10 @@ function create_fragment(ctx) {
 			a = element("a");
 			a.textContent = "Test";
 			attr(a, "href", "#");
-			dispose = action_destroyer(link_action = link.call(null, a));
 		},
 		m(target, anchor) {
 			insert(target, a, anchor);
+			dispose = action_destroyer(link_action = link.call(null, a));
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js
index 8285646481..e129e66d71 100644
--- a/test/js/samples/bind-online/expected.js
+++ b/test/js/samples/bind-online/expected.js
@@ -14,13 +14,13 @@ function create_fragment(ctx) {
 	add_render_callback(/*onlinestatuschanged*/ ctx[1]);
 
 	return {
-		c() {
+		c: noop,
+		m(target, anchor) {
 			dispose = [
 				listen(window, "online", /*onlinestatuschanged*/ ctx[1]),
 				listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
 			];
 		},
-		m: noop,
 		p: noop,
 		i: noop,
 		o: noop,
diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js
index d4f148cac9..7d66145f0a 100644
--- a/test/js/samples/bind-open/expected.js
+++ b/test/js/samples/bind-open/expected.js
@@ -20,12 +20,11 @@ function create_fragment(ctx) {
 
 			details.innerHTML = `<summary>summary</summary>content
 `;
-
-			dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, details, anchor);
 			details.open = /*open*/ ctx[0];
+			dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*open*/ 1) {
diff --git a/test/js/samples/bindings-readonly-order/expected.js b/test/js/samples/bindings-readonly-order/expected.js
index cf30686662..db0e7cb007 100644
--- a/test/js/samples/bindings-readonly-order/expected.js
+++ b/test/js/samples/bindings-readonly-order/expected.js
@@ -26,16 +26,16 @@ function create_fragment(ctx) {
 			input1 = element("input");
 			attr(input0, "type", "file");
 			attr(input1, "type", "file");
-
-			dispose = [
-				listen(input0, "change", /*input0_change_handler*/ ctx[1]),
-				listen(input1, "change", /*input1_change_handler*/ ctx[2])
-			];
 		},
 		m(target, anchor) {
 			insert(target, input0, anchor);
 			insert(target, t, anchor);
 			insert(target, input1, anchor);
+
+			dispose = [
+				listen(input0, "change", /*input0_change_handler*/ ctx[1]),
+				listen(input1, "change", /*input1_change_handler*/ ctx[2])
+			];
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/capture-inject-dev-only/expected.js b/test/js/samples/capture-inject-dev-only/expected.js
index 6c639d9207..a314b0cff3 100644
--- a/test/js/samples/capture-inject-dev-only/expected.js
+++ b/test/js/samples/capture-inject-dev-only/expected.js
@@ -28,7 +28,6 @@ function create_fragment(ctx) {
 			t0 = text(/*foo*/ ctx[0]);
 			t1 = space();
 			input = element("input");
-			dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, p, anchor);
@@ -36,6 +35,7 @@ function create_fragment(ctx) {
 			insert(target, t1, anchor);
 			insert(target, input, anchor);
 			set_input_value(input, /*foo*/ ctx[0]);
+			dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]);
diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js
index e01402b6d4..a65d9186a7 100644
--- a/test/js/samples/component-static-var/expected.js
+++ b/test/js/samples/component-static-var/expected.js
@@ -35,7 +35,6 @@ function create_fragment(ctx) {
 			create_component(bar.$$.fragment);
 			t1 = space();
 			input = element("input");
-			dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			mount_component(foo, target, anchor);
@@ -45,6 +44,7 @@ function create_fragment(ctx) {
 			insert(target, input, anchor);
 			set_input_value(input, /*z*/ ctx[0]);
 			current = true;
+			dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			const bar_changes = {};
diff --git a/test/js/samples/component-store-reassign-invalidate/expected.js b/test/js/samples/component-store-reassign-invalidate/expected.js
index 02a74cf22e..771b20dec4 100644
--- a/test/js/samples/component-store-reassign-invalidate/expected.js
+++ b/test/js/samples/component-store-reassign-invalidate/expected.js
@@ -31,13 +31,13 @@ function create_fragment(ctx) {
 			t1 = space();
 			button = element("button");
 			button.textContent = "reset";
-			dispose = listen(button, "click", /*click_handler*/ ctx[2]);
 		},
 		m(target, anchor) {
 			insert(target, h1, anchor);
 			append(h1, t0);
 			insert(target, t1, anchor);
 			insert(target, button, anchor);
+			dispose = listen(button, "click", /*click_handler*/ ctx[2]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]);
diff --git a/test/js/samples/dont-invalidate-this/expected.js b/test/js/samples/dont-invalidate-this/expected.js
index 98f638dfcf..f5f6d07812 100644
--- a/test/js/samples/dont-invalidate-this/expected.js
+++ b/test/js/samples/dont-invalidate-this/expected.js
@@ -17,10 +17,10 @@ function create_fragment(ctx) {
 	return {
 		c() {
 			input = element("input");
-			dispose = listen(input, "input", make_uppercase);
 		},
 		m(target, anchor) {
 			insert(target, input, anchor);
+			dispose = listen(input, "input", make_uppercase);
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/event-handler-dynamic/expected.js b/test/js/samples/event-handler-dynamic/expected.js
index 42c6b2951a..16b4a3f626 100644
--- a/test/js/samples/event-handler-dynamic/expected.js
+++ b/test/js/samples/event-handler-dynamic/expected.js
@@ -42,14 +42,6 @@ function create_fragment(ctx) {
 			t5 = space();
 			button2 = element("button");
 			button2.textContent = "click";
-
-			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);
-				})
-			];
 		},
 		m(target, anchor) {
 			insert(target, p0, anchor);
@@ -61,6 +53,14 @@ function create_fragment(ctx) {
 			append(p1, t4);
 			insert(target, t5, anchor);
 			insert(target, button2, anchor);
+
+			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);
+				})
+			];
 		},
 		p(new_ctx, [dirty]) {
 			ctx = new_ctx;
diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js
index 6f04e67808..c519fac668 100644
--- a/test/js/samples/event-handler-no-passive/expected.js
+++ b/test/js/samples/event-handler-no-passive/expected.js
@@ -20,10 +20,10 @@ function create_fragment(ctx) {
 			a = element("a");
 			a.textContent = "this should not navigate to example.com";
 			attr(a, "href", "https://example.com");
-			dispose = listen(a, "touchstart", touchstart_handler);
 		},
 		m(target, anchor) {
 			insert(target, a, anchor);
+			dispose = listen(a, "touchstart", touchstart_handler);
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js
index 3f324bb76d..252034a431 100644
--- a/test/js/samples/event-modifiers/expected.js
+++ b/test/js/samples/event-modifiers/expected.js
@@ -35,13 +35,6 @@ function create_fragment(ctx) {
 			t3 = space();
 			button2 = element("button");
 			button2.textContent = "or me!";
-
-			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 })
-			];
 		},
 		m(target, anchor) {
 			insert(target, div, anchor);
@@ -50,6 +43,13 @@ function create_fragment(ctx) {
 			append(div, button1);
 			append(div, t3);
 			append(div, button2);
+
+			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 })
+			];
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js
index c3e46f0c79..2a2254fbd7 100644
--- a/test/js/samples/input-files/expected.js
+++ b/test/js/samples/input-files/expected.js
@@ -20,10 +20,10 @@ function create_fragment(ctx) {
 			input = element("input");
 			attr(input, "type", "file");
 			input.multiple = true;
-			dispose = listen(input, "change", /*input_change_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, input, anchor);
+			dispose = listen(input, "change", /*input_change_handler*/ ctx[1]);
 		},
 		p: noop,
 		i: noop,
diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js
index 8ff2b2798b..d588f0bf73 100644
--- a/test/js/samples/input-no-initial-value/expected.js
+++ b/test/js/samples/input-no-initial-value/expected.js
@@ -31,11 +31,6 @@ function create_fragment(ctx) {
 			button.textContent = "Store";
 			attr(input, "type", "text");
 			input.required = true;
-
-			dispose = [
-				listen(input, "input", /*input_input_handler*/ ctx[2]),
-				listen(form, "submit", /*handleSubmit*/ ctx[1])
-			];
 		},
 		m(target, anchor) {
 			insert(target, form, anchor);
@@ -43,6 +38,11 @@ function create_fragment(ctx) {
 			set_input_value(input, /*test*/ ctx[0]);
 			append(form, t0);
 			append(form, button);
+
+			dispose = [
+				listen(input, "input", /*input_input_handler*/ ctx[2]),
+				listen(form, "submit", /*handleSubmit*/ ctx[1])
+			];
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*test*/ 1 && input.value !== /*test*/ ctx[0]) {
diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js
index 5a074d9754..12dfd3e90e 100644
--- a/test/js/samples/input-range/expected.js
+++ b/test/js/samples/input-range/expected.js
@@ -22,16 +22,16 @@ function create_fragment(ctx) {
 		c() {
 			input = element("input");
 			attr(input, "type", "range");
+		},
+		m(target, anchor) {
+			insert(target, input, anchor);
+			set_input_value(input, /*value*/ ctx[0]);
 
 			dispose = [
 				listen(input, "change", /*input_change_input_handler*/ ctx[1]),
 				listen(input, "input", /*input_change_input_handler*/ ctx[1])
 			];
 		},
-		m(target, anchor) {
-			insert(target, input, anchor);
-			set_input_value(input, /*value*/ ctx[0]);
-		},
 		p(ctx, [dirty]) {
 			if (dirty & /*value*/ 1) {
 				set_input_value(input, /*value*/ ctx[0]);
diff --git a/test/js/samples/input-value/expected.js b/test/js/samples/input-value/expected.js
index 81753441e4..21c7bfc83b 100644
--- a/test/js/samples/input-value/expected.js
+++ b/test/js/samples/input-value/expected.js
@@ -30,7 +30,6 @@ function create_fragment(ctx) {
 			t1 = text(/*name*/ ctx[0]);
 			t2 = text("!");
 			input.value = /*name*/ ctx[0];
-			dispose = listen(input, "input", /*onInput*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, input, anchor);
@@ -38,6 +37,7 @@ function create_fragment(ctx) {
 			insert(target, h1, anchor);
 			append(h1, t1);
 			append(h1, t2);
+			dispose = listen(input, "input", /*onInput*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*name*/ 1 && input.value !== /*name*/ ctx[0]) {
diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js
index 344976ade6..fefe867e14 100644
--- a/test/js/samples/input-without-blowback-guard/expected.js
+++ b/test/js/samples/input-without-blowback-guard/expected.js
@@ -19,11 +19,11 @@ function create_fragment(ctx) {
 		c() {
 			input = element("input");
 			attr(input, "type", "checkbox");
-			dispose = listen(input, "change", /*input_change_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, input, anchor);
 			input.checked = /*foo*/ ctx[0];
+			dispose = listen(input, "change", /*input_change_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*foo*/ 1) {
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 4127a6d7d6..7634481a2d 100644
--- a/test/js/samples/instrumentation-script-if-no-block/expected.js
+++ b/test/js/samples/instrumentation-script-if-no-block/expected.js
@@ -30,7 +30,6 @@ function create_fragment(ctx) {
 			p = element("p");
 			t2 = text("x: ");
 			t3 = text(/*x*/ ctx[0]);
-			dispose = listen(button, "click", /*foo*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, button, anchor);
@@ -38,6 +37,7 @@ function create_fragment(ctx) {
 			insert(target, p, anchor);
 			append(p, t2);
 			append(p, t3);
+			dispose = listen(button, "click", /*foo*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]);
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 0d4493baf3..c154608cd5 100644
--- a/test/js/samples/instrumentation-script-x-equals-x/expected.js
+++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js
@@ -31,7 +31,6 @@ function create_fragment(ctx) {
 			p = element("p");
 			t2 = text("number of things: ");
 			t3 = text(t3_value);
-			dispose = listen(button, "click", /*foo*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, button, anchor);
@@ -39,6 +38,7 @@ function create_fragment(ctx) {
 			insert(target, p, anchor);
 			append(p, t2);
 			append(p, t3);
+			dispose = listen(button, "click", /*foo*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value);
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 0bd627eb87..77780baa99 100644
--- a/test/js/samples/instrumentation-template-if-no-block/expected.js
+++ b/test/js/samples/instrumentation-template-if-no-block/expected.js
@@ -30,7 +30,6 @@ function create_fragment(ctx) {
 			p = element("p");
 			t2 = text("x: ");
 			t3 = text(/*x*/ ctx[0]);
-			dispose = listen(button, "click", /*click_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, button, anchor);
@@ -38,6 +37,7 @@ function create_fragment(ctx) {
 			insert(target, p, anchor);
 			append(p, t2);
 			append(p, t3);
+			dispose = listen(button, "click", /*click_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]);
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 e049a6d39b..4fe45616c7 100644
--- a/test/js/samples/instrumentation-template-x-equals-x/expected.js
+++ b/test/js/samples/instrumentation-template-x-equals-x/expected.js
@@ -31,7 +31,6 @@ function create_fragment(ctx) {
 			p = element("p");
 			t2 = text("number of things: ");
 			t3 = text(t3_value);
-			dispose = listen(button, "click", /*click_handler*/ ctx[1]);
 		},
 		m(target, anchor) {
 			insert(target, button, anchor);
@@ -39,6 +38,7 @@ function create_fragment(ctx) {
 			insert(target, p, anchor);
 			append(p, t2);
 			append(p, t3);
+			dispose = listen(button, "click", /*click_handler*/ ctx[1]);
 		},
 		p(ctx, [dirty]) {
 			if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value);
diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js
index b5548a3efe..52fef36792 100644
--- a/test/js/samples/media-bindings/expected.js
+++ b/test/js/samples/media-bindings/expected.js
@@ -41,6 +41,17 @@ function create_fragment(ctx) {
 			if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[13].call(audio));
 			if (/*seeking*/ ctx[8] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[17].call(audio));
 			if (/*ended*/ ctx[9] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[18].call(audio));
+		},
+		m(target, anchor) {
+			insert(target, audio, anchor);
+
+			if (!isNaN(/*volume*/ ctx[6])) {
+				audio.volume = /*volume*/ ctx[6];
+			}
+
+			if (!isNaN(/*playbackRate*/ ctx[7])) {
+				audio.playbackRate = /*playbackRate*/ ctx[7];
+			}
 
 			dispose = [
 				listen(audio, "progress", /*audio_progress_handler*/ ctx[10]),
@@ -56,17 +67,6 @@ function create_fragment(ctx) {
 				listen(audio, "ended", /*audio_ended_handler*/ ctx[18])
 			];
 		},
-		m(target, anchor) {
-			insert(target, audio, anchor);
-
-			if (!isNaN(/*volume*/ ctx[6])) {
-				audio.volume = /*volume*/ ctx[6];
-			}
-
-			if (!isNaN(/*playbackRate*/ ctx[7])) {
-				audio.playbackRate = /*playbackRate*/ ctx[7];
-			}
-		},
 		p(ctx, [dirty]) {
 			if (!audio_updating && dirty & /*currentTime*/ 8 && !isNaN(/*currentTime*/ ctx[3])) {
 				audio.currentTime = /*currentTime*/ ctx[3];
diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js
index 5b734a70a6..c8cd1d84ce 100644
--- a/test/js/samples/video-bindings/expected.js
+++ b/test/js/samples/video-bindings/expected.js
@@ -37,16 +37,16 @@ function create_fragment(ctx) {
 			video = element("video");
 			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) {
+			insert(target, video, anchor);
+			video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video));
 
 			dispose = [
 				listen(video, "timeupdate", video_timeupdate_handler),
 				listen(video, "resize", /*video_resize_handler*/ ctx[5])
 			];
 		},
-		m(target, anchor) {
-			insert(target, video, anchor);
-			video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video));
-		},
 		p(ctx, [dirty]) {
 			if (!video_updating && dirty & /*currentTime*/ 1 && !isNaN(/*currentTime*/ ctx[0])) {
 				video.currentTime = /*currentTime*/ ctx[0];
diff --git a/test/js/samples/window-binding-online/expected.js b/test/js/samples/window-binding-online/expected.js
index 8285646481..e129e66d71 100644
--- a/test/js/samples/window-binding-online/expected.js
+++ b/test/js/samples/window-binding-online/expected.js
@@ -14,13 +14,13 @@ function create_fragment(ctx) {
 	add_render_callback(/*onlinestatuschanged*/ ctx[1]);
 
 	return {
-		c() {
+		c: noop,
+		m(target, anchor) {
 			dispose = [
 				listen(window, "online", /*onlinestatuschanged*/ ctx[1]),
 				listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
 			];
 		},
-		m: noop,
 		p: noop,
 		i: noop,
 		o: noop,
diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js
index f79212e25e..70c39eedd2 100644
--- a/test/js/samples/window-binding-scroll/expected.js
+++ b/test/js/samples/window-binding-scroll/expected.js
@@ -33,6 +33,11 @@ function create_fragment(ctx) {
 			p = element("p");
 			t0 = text("scrolled to ");
 			t1 = text(/*y*/ ctx[0]);
+		},
+		m(target, anchor) {
+			insert(target, p, anchor);
+			append(p, t0);
+			append(p, t1);
 
 			dispose = listen(window, "scroll", () => {
 				scrolling = true;
@@ -41,11 +46,6 @@ function create_fragment(ctx) {
 				/*onwindowscroll*/ ctx[1]();
 			});
 		},
-		m(target, anchor) {
-			insert(target, p, anchor);
-			append(p, t0);
-			append(p, t1);
-		},
 		p(ctx, [dirty]) {
 			if (dirty & /*y*/ 1 && !scrolling) {
 				scrolling = true;
diff --git a/test/runtime/samples/action-receives-element-mounted/_config.js b/test/runtime/samples/action-receives-element-mounted/_config.js
new file mode 100644
index 0000000000..0806d0fa90
--- /dev/null
+++ b/test/runtime/samples/action-receives-element-mounted/_config.js
@@ -0,0 +1,8 @@
+const result = {};
+
+export default {
+	props: { result },
+	async test({ assert, component, target, window }) {
+		assert.notEqual(result.parentElement, null);
+	}
+};
diff --git a/test/runtime/samples/action-receives-element-mounted/main.svelte b/test/runtime/samples/action-receives-element-mounted/main.svelte
new file mode 100644
index 0000000000..a53ce81de0
--- /dev/null
+++ b/test/runtime/samples/action-receives-element-mounted/main.svelte
@@ -0,0 +1,8 @@
+<script>
+	export let result;
+	function onMountAction(node) {
+		result.parentElement = node.parentElement;
+	}
+</script>
+
+<h1 use:onMountAction>Hello!</h1>
\ No newline at end of file