From 670dcae489e0d8b3dc9250f4efcc79d5c57fe639 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 13 Aug 2026 22:52:32 -0400 Subject: [PATCH] Make the rendering test context tracked Test state reaches templates through the top-level component, and tests mutate it with `set(this.context, ...)`. That drives a rerender only because a non-tracked property read still entangles a per-property tag. That read path is legacy: RFC 957's end state removes it, and the async scheduler work needs it gone. Declaring the context properties tracked keeps every existing `set(this.context, ...)` call reactive under modern semantics, so the suite stops depending on the legacy path without touching the 771 call sites. Values that are already decorators (computed properties, injections) define their own reactivity and pass through untouched. No behaviour change on main: 9448 tests, 0 failures. Co-Authored-By: Claude Opus 5 (1M context) --- .../lib/test-cases/rendering.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/internal-test-helpers/lib/test-cases/rendering.ts b/packages/internal-test-helpers/lib/test-cases/rendering.ts index 1dab130a719..0d9ac978be6 100644 --- a/packages/internal-test-helpers/lib/test-cases/rendering.ts +++ b/packages/internal-test-helpers/lib/test-cases/rendering.ts @@ -1,5 +1,6 @@ import type { Renderer } from '@ember/-internals/glimmer'; import { _resetRenderers, helper, Helper } from '@ember/-internals/glimmer'; +import { isClassicDecorator, tracked } from '@ember/-internals/metal'; import { EventDispatcher } from '@ember/-internals/views'; import Component from '@ember/component'; import type { EmberPrecompileOptions } from 'ember-template-compiler'; @@ -17,6 +18,28 @@ import AbstractTestCase from './abstract'; const TextNode = window.Text; +/** + * Test state reaches templates through the top-level component, and tests + * update it with `set(this.context, ...)`. That only drives a rerender + * because non-tracked reads currently entangle a per-property tag, which + * is a legacy read path on its way out (and which the async scheduler's + * end state removes). Declaring the properties tracked makes the same + * `set` calls reactive under modern semantics, so the suite stops + * depending on the legacy path. + * + * Values that are already decorators (computed properties, injections) + * define their own reactivity and are passed through untouched. + */ +function trackedContext(context: object): Record { + let attrs: Record = {}; + + for (let [key, value] of Object.entries(context)) { + attrs[key] = isClassicDecorator(value) ? value : tracked({ value }); + } + + return attrs; +} + export default abstract class RenderingTestCase extends AbstractTestCase { owner: EngineInstance; renderer: Renderer; @@ -106,7 +129,7 @@ export default abstract class RenderingTestCase extends AbstractTestCase { }) ); - let attrs = Object.assign({}, context, { + let attrs = Object.assign(trackedContext(context), { tagName: '', layoutName: '-top-level', });