diff --git a/test/runtime/samples/transition-js-local-and-global/_config.js b/test/runtime/samples/transition-js-local-and-global/_config.js
new file mode 100644
index 0000000000..d0a98c2a4a
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-and-global/_config.js
@@ -0,0 +1,66 @@
+export default {
+ props: {
+ x: false,
+ y: true
+ },
+
+ test({ assert, component, target, raf }) {
+ // first, toggle x — first element should snap in
+ // and out while second one transitions
+ component.x = true;
+
+ let divs = target.querySelectorAll('div');
+ assert.equal(divs[0].foo, undefined);
+ assert.equal(divs[1].foo, 0);
+
+ raf.tick(50);
+ assert.equal(divs[0].foo, undefined);
+ assert.equal(divs[1].foo, 0.5);
+
+ raf.tick(100);
+
+ component.x = false;
+ assert.htmlEqual(target.innerHTML, `
+
snaps if x changes
+ transitions if x changes
+ `);
+
+ raf.tick(150);
+ assert.equal(divs[0].foo, undefined);
+ assert.equal(divs[1].foo, 0.5);
+
+ raf.tick(200);
+ assert.htmlEqual(target.innerHTML, '');
+
+ // then toggle y
+ component.set({ x: true, y: false });
+ component.y = true;
+
+ assert.htmlEqual(target.innerHTML, `
+ snaps if x changes
+ transitions if x changes
+ `);
+ divs = target.querySelectorAll('div');
+
+ raf.tick(250);
+ assert.equal(divs[0].foo, 0.5);
+ assert.equal(divs[1].foo, 0.5);
+
+ raf.tick(300);
+ assert.equal(divs[0].foo, 1);
+ assert.equal(divs[1].foo, 1);
+
+ component.y = false;
+ assert.htmlEqual(target.innerHTML, `
+ snaps if x changes
+ transitions if x changes
+ `);
+
+ raf.tick(320);
+ assert.equal(divs[0].foo, 0.8);
+ assert.equal(divs[1].foo, 0.8);
+
+ raf.tick(400);
+ assert.htmlEqual(target.innerHTML, '');
+ },
+};
diff --git a/test/runtime/samples/transition-js-local-and-global/main.html b/test/runtime/samples/transition-js-local-and-global/main.html
new file mode 100644
index 0000000000..18fbaa1b78
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-and-global/main.html
@@ -0,0 +1,20 @@
+
+
+{#if x}
+ {#if y}
+ snaps if x changes
+ transitions if x changes
+ {/if}
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-await/_config.js b/test/runtime/samples/transition-js-local-nested-await/_config.js
new file mode 100644
index 0000000000..b07d88741f
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-await/_config.js
@@ -0,0 +1,31 @@
+let fulfil;
+
+const promise = new Promise(f => {
+ fulfil = f;
+});
+
+export default {
+ props: {
+ x: false,
+ promise
+ },
+
+ test({ assert, component, target, raf }) {
+ component.x = true;
+ fulfil();
+
+ return promise.then(() => {
+ const div = target.querySelector('div');
+ assert.equal(div.foo, 0);
+
+ raf.tick(100);
+ assert.equal(div.foo, 1);
+
+ component.x = false;
+ assert.htmlEqual(target.innerHTML, '');
+
+ raf.tick(150);
+ assert.equal(div.foo, 1);
+ });
+ }
+};
diff --git a/test/runtime/samples/transition-js-local-nested-await/main.html b/test/runtime/samples/transition-js-local-nested-await/main.html
new file mode 100644
index 0000000000..618dd3088d
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-await/main.html
@@ -0,0 +1,19 @@
+
+
+{#if x}
+ {#await promise then value}
+
+ {/await}
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-component/Widget.html b/test/runtime/samples/transition-js-local-nested-component/Widget.html
new file mode 100644
index 0000000000..f3baa4b004
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-component/Widget.html
@@ -0,0 +1,12 @@
+
+
+
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-component/_config.js b/test/runtime/samples/transition-js-local-nested-component/_config.js
new file mode 100644
index 0000000000..87d7aaa233
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-component/_config.js
@@ -0,0 +1,24 @@
+export default {
+ props: {
+ x: false
+ },
+
+ test({ assert, component, target, raf }) {
+ component.x = true;
+
+ const div = target.querySelector('div');
+ assert.equal(div.foo, 0);
+
+ raf.tick(100);
+ assert.equal(div.foo, 1);
+
+ component.x = false;
+ assert.htmlEqual(target.innerHTML, '');
+
+ raf.tick(150);
+ assert.equal(div.foo, 0.5);
+
+ raf.tick(200);
+ assert.htmlEqual(target.innerHTML, '');
+ }
+};
diff --git a/test/runtime/samples/transition-js-local-nested-component/main.html b/test/runtime/samples/transition-js-local-nested-component/main.html
new file mode 100644
index 0000000000..2eb867a667
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-component/main.html
@@ -0,0 +1,9 @@
+
+
+{#if x}
+
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-each-keyed/_config.js b/test/runtime/samples/transition-js-local-nested-each-keyed/_config.js
new file mode 100644
index 0000000000..854bb301de
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-each-keyed/_config.js
@@ -0,0 +1,30 @@
+export default {
+ props: {
+ x: false,
+ things: ['a']
+ },
+
+ test({ assert, component, target, raf }) {
+ component.x = true;
+
+ const div1 = target.querySelector('div');
+ assert.equal(div1.foo, undefined);
+
+ raf.tick(100);
+ assert.equal(div1.foo, undefined);
+
+ component.set({ things: ['a', 'b'] });
+ assert.htmlEqual(target.innerHTML, '');
+
+ const div2 = target.querySelector('div:last-child');
+ assert.equal(div1.foo, undefined);
+ assert.equal(div2.foo, 0);
+
+ raf.tick(200);
+ assert.equal(div1.foo, undefined);
+ assert.equal(div2.foo, 1);
+
+ component.x = false;
+ assert.htmlEqual(target.innerHTML, '');
+ },
+};
diff --git a/test/runtime/samples/transition-js-local-nested-each-keyed/main.html b/test/runtime/samples/transition-js-local-nested-each-keyed/main.html
new file mode 100644
index 0000000000..90b6d110a7
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-each-keyed/main.html
@@ -0,0 +1,19 @@
+
+
+{#if x}
+ {#each things as thing (thing)}
+
+ {/each}
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-each/_config.js b/test/runtime/samples/transition-js-local-nested-each/_config.js
new file mode 100644
index 0000000000..854bb301de
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-each/_config.js
@@ -0,0 +1,30 @@
+export default {
+ props: {
+ x: false,
+ things: ['a']
+ },
+
+ test({ assert, component, target, raf }) {
+ component.x = true;
+
+ const div1 = target.querySelector('div');
+ assert.equal(div1.foo, undefined);
+
+ raf.tick(100);
+ assert.equal(div1.foo, undefined);
+
+ component.set({ things: ['a', 'b'] });
+ assert.htmlEqual(target.innerHTML, '');
+
+ const div2 = target.querySelector('div:last-child');
+ assert.equal(div1.foo, undefined);
+ assert.equal(div2.foo, 0);
+
+ raf.tick(200);
+ assert.equal(div1.foo, undefined);
+ assert.equal(div2.foo, 1);
+
+ component.x = false;
+ assert.htmlEqual(target.innerHTML, '');
+ },
+};
diff --git a/test/runtime/samples/transition-js-local-nested-each/main.html b/test/runtime/samples/transition-js-local-nested-each/main.html
new file mode 100644
index 0000000000..feaadd9283
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-each/main.html
@@ -0,0 +1,19 @@
+
+
+{#if x}
+ {#each things as thing}
+
+ {/each}
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local-nested-if/_config.js b/test/runtime/samples/transition-js-local-nested-if/_config.js
new file mode 100644
index 0000000000..7dd3f47bac
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-if/_config.js
@@ -0,0 +1,39 @@
+export default {
+ props: {
+ x: false,
+ y: true
+ },
+
+ test({ assert, component, target, raf }) {
+ component.x = true;
+
+ let div = target.querySelector('div');
+ assert.equal(div.foo, undefined);
+
+ component.y = false;
+ assert.htmlEqual(target.innerHTML, '');
+ div = target.querySelector('div');
+
+ raf.tick(50);
+ assert.equal(div.foo, 0.5);
+
+ raf.tick(100);
+ assert.htmlEqual(target.innerHTML, '');
+
+ component.set({ x: false, y: true });
+ assert.htmlEqual(target.innerHTML, '');
+
+ component.x = true;
+ assert.htmlEqual(target.innerHTML, '');
+ div = target.querySelector('div');
+
+ component.y = false;
+ assert.htmlEqual(target.innerHTML, '');
+
+ raf.tick(150);
+ assert.equal(div.foo, 0.5);
+
+ raf.tick(200);
+ assert.htmlEqual(target.innerHTML, '');
+ },
+};
diff --git a/test/runtime/samples/transition-js-local-nested-if/main.html b/test/runtime/samples/transition-js-local-nested-if/main.html
new file mode 100644
index 0000000000..cbdfbd8c25
--- /dev/null
+++ b/test/runtime/samples/transition-js-local-nested-if/main.html
@@ -0,0 +1,19 @@
+
+
+{#if x}
+ {#if y}
+
+ {/if}
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/transition-js-local/_config.js b/test/runtime/samples/transition-js-local/_config.js
new file mode 100644
index 0000000000..fa8a55bfcd
--- /dev/null
+++ b/test/runtime/samples/transition-js-local/_config.js
@@ -0,0 +1,40 @@
+export default {
+ props: {
+ x: false,
+ y: true
+ },
+
+ test({ assert, component, target, window, raf }) {
+ component.x = true;
+
+ let div = target.querySelector('div');
+ assert.equal(div.foo, undefined);
+
+ component.y = false;
+ assert.htmlEqual(target.innerHTML, '');
+ div = target.querySelector('div');
+
+ raf.tick(50);
+ assert.equal(div.foo, 0.5);
+
+ raf.tick(100);
+ assert.htmlEqual(target.innerHTML, '');
+
+ component.x = false;
+ component.y = true;
+ assert.htmlEqual(target.innerHTML, '');
+
+ component.x = true;
+ assert.htmlEqual(target.innerHTML, '');
+ div = target.querySelector('div');
+
+ component.y = false;
+ assert.htmlEqual(target.innerHTML, '');
+
+ raf.tick(120);
+ assert.equal(div.foo, 0.8);
+
+ raf.tick(200);
+ assert.htmlEqual(target.innerHTML, '');
+ },
+};
diff --git a/test/runtime/samples/transition-js-local/main.html b/test/runtime/samples/transition-js-local/main.html
new file mode 100644
index 0000000000..cbdfbd8c25
--- /dev/null
+++ b/test/runtime/samples/transition-js-local/main.html
@@ -0,0 +1,19 @@
+
+
+{#if x}
+ {#if y}
+
+ {/if}
+{/if}
\ No newline at end of file