diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js
index f9cd31f0bee..f9653c3644e 100644
--- a/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js
+++ b/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js
@@ -32,6 +32,37 @@ if (EMBER_METAL_TRACKED_PROPERTIES) {
this.assertText('1');
}
+ '@test tracked properties rerender when updated outside of a runloop'(assert) {
+ let done = assert.async();
+
+ let CountComponent = Component.extend({
+ count: tracked({ value: 0 }),
+
+ increment() {
+ setTimeout(() => {
+ this.count++;
+ }, 100);
+ },
+ });
+
+ this.registerComponent('counter', {
+ ComponentClass: CountComponent,
+ template: '',
+ });
+
+ this.render('');
+
+ this.assertText('0');
+
+ // intentionally outside of a runTask
+ this.$('button').click();
+
+ setTimeout(() => {
+ this.assertText('1');
+ done();
+ }, 200);
+ }
+
'@test nested tracked properties rerender when updated'() {
let Counter = EmberObject.extend({
count: tracked({ value: 0 }),
diff --git a/packages/@ember/-internals/metal/lib/tags.ts b/packages/@ember/-internals/metal/lib/tags.ts
index 61483a1a51d..845e2abc1b9 100644
--- a/packages/@ember/-internals/metal/lib/tags.ts
+++ b/packages/@ember/-internals/metal/lib/tags.ts
@@ -94,7 +94,7 @@ export function markObjectAsDirty(obj: object, propertyKey: string, meta: Meta):
}
}
-function ensureRunloop(): void {
+export function ensureRunloop(): void {
if (hasViews()) {
backburner.ensureInstance();
}
diff --git a/packages/@ember/-internals/metal/lib/tracked.ts b/packages/@ember/-internals/metal/lib/tracked.ts
index d8ef7e0cf4e..da11883e11a 100644
--- a/packages/@ember/-internals/metal/lib/tracked.ts
+++ b/packages/@ember/-internals/metal/lib/tracked.ts
@@ -4,7 +4,7 @@ import { DEBUG } from '@glimmer/env';
import { combine, CONSTANT_TAG, Tag } from '@glimmer/reference';
import { Decorator, ElementDescriptor } from './decorator';
import { setComputedDecorator } from './descriptor_map';
-import { dirty, tagFor, tagForProperty } from './tags';
+import { dirty, ensureRunloop, tagFor, tagForProperty } from './tags';
type Option = T | null;
@@ -255,7 +255,7 @@ export interface Interceptors {
[key: string]: boolean;
}
-let propertyDidChange = function(): void {};
+let propertyDidChange = ensureRunloop;
export function setPropertyDidChange(cb: () => void): void {
propertyDidChange = cb;