Skip to content

Merge main into nvp/deprecate-mixin-followups - #21693

Closed
NullVoxPopuli-ai-agent wants to merge 74 commits into
emberjs:nvp/deprecate-mixin-followupsfrom
NullVoxPopuli-ai-agent:nvp/mixin-followups-merge-main
Closed

NullVoxPopuli-ai-agent wants to merge 74 commits into
emberjs:nvp/deprecate-mixin-followupsfrom
NullVoxPopuli-ai-agent:nvp/mixin-followups-merge-main

Conversation

@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Contributor

This PR brings nvp/deprecate-mixin-followups (#21588) up to date with main. It is one merge commit with no conflicts.

Why

#21687 is on top of this branch, and it needs #21690 (merged to main on 2026-10-11). This branch is 73 commits behind main, so #21687 cannot drop its copy of that test change, and I cannot push to this branch.

After this PR merges, I push the rebased #21687. It then has one commit, with only the deprecation.

If you prefer to rebase #21588 on main yourself, close this PR. The rebased #21687 commit applies in the same way.

Test results

Local runs of the full suite on this merge plus the #21687 commit:

default                            9287 pass, 18 skip, 0 fail
ALL_DEPRECATIONS_ENABLED=true      9287 pass, 18 skip, 0 fail
OVERRIDE_DEPRECATION_VERSION=15    7729 pass, 599 skip, 0 fail

I did not run the suite on the merge commit alone.

🤖 Generated with Claude Code

NullVoxPopuli and others added 30 commits October 1, 2026 00:34
Twelve test files check features that stay after the classic `Component`
is removed (RFC 1216). These files no longer import the classic class.

Each test that uses the classic class moves, unchanged, to a file of the
same name in `tests/integration/components/classic/`. These tests check
classic-only API: the wrapper element, `elementId`, lifecycle hooks,
`this.attrs`, `positionalParams`, two-way bindings, `appendTo`, the view
utilities, and `render.component` instrumentation.

- `append-test.js`, `instrumentation-test.js`, `life-cycle-test.js` and
  `utils-test.js` move whole. Every test in them is classic-only.
- The other eight files split. The new modules have the old name plus
  "(classic component)".
- Six curly tests that only extend the classic class, and never create
  an instance, move too.

No test is deleted and no test body changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The subject of these tests stays after the classic `Component` is
removed. Each one now also has a version without the classic class, in
the original file.

- angle bracket: positional parameters are not allowed
  (`PositionalComponent`).
- contextual: a curried positional argument does not leak with a dot
  path (`PositionalComponent`), and a dot path updates attributes.
- error handling: an error during destroy (`willDestroy`), and an error
  while a modifier installs. The modifier takes the place of
  `didInsertElement`.
- life cycle: "afterRender set" and "afterRender set on parent". A
  modifier schedules the `afterRender` work.
- `mut`: a binding propagates through one and two `mut` layers. The
  bottom component sets the value with `(fn (mut @setme) 13)`.

The classic module "Run loop and lifecycle hooks" gets the
"(classic component)" suffix, because the original file has that module
again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Seven more test files no longer import the classic `Component`. Their
classic-only tests move, unchanged, to
`tests/integration/components/classic/`.

- `helpers/readonly-test.js` moves whole. Each test checks two-way
  binding or `this.attrs`.
- `event-dispatcher-test.js`: the ten tests of event handler methods and
  `customEvents`.
- `helpers/yield-test.js`: the `parentView` test.
- `content-test.js`: the `attributeBindings: ["style"]` warning test.
- `packages/ember/tests`: the `customEvents` tests of the application
  lifecycle, the tests of a component without a template, and the
  `layout` and `layoutName` tests.

The new modules have the old name plus "(classic component)". A module
that needs setup code gets a copy of it.

No test is deleted and no test body changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- `each-test.js`: "updating and setting within #each" sets tracked state
  from a modifier update. The modifier takes the place of `didUpdate`.
- `template_rendering_test.js`: the outlet test counts modifier installs.
  The modifier takes the place of `didInsertElement`, so the test name
  now says "modifiers installed".
- `helpers/readonly-test.js`: three new tests check `(readonly)` with
  Glimmer components. The classic tests of this helper are in
  `components/classic/readonly-test.js`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A test that can use a Glimmer component now has two versions: the
classic one in `components/classic/`, and a Glimmer one in the original
file. When the classic `Component` is removed, only classic coverage
goes away.

Classic versions that the last commit dropped come back:

- `classic/each-test.js`: "updating and setting within #each", with
  `didUpdate`.
- `classic/template-rendering-test.js`: the outlet test, with
  `didInsertElement`.

New Glimmer versions of moved tests:

- `readonly`: `(mut @foo)` of a `(readonly)` argument is not allowed.
- content: `style` on a component with `...attributes` gives the style
  warning.
- component context: arguments called `data` and `attrs` do not collide
  with internal structures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The classic tests in `tests/integration/components/classic/` go away
together with the classic `Component`. These eight subjects also exist
for Glimmer components, and had no Glimmer test:

- angle bracket: an `id` attribute is bound, and named arguments are on
  `this.args`.
- contextual: GH#13494, a component without content that gets a bound
  argument.
- curly: a class is on the element before a modifier installs,
  GH#13846 (a child sets state on its parent during destruction), and
  GH#14273 (a tracked property set in `willDestroy`).
- life cycle: the order of constructors, modifier installs, modifier
  destructors and `willDestroy` in a component tree.
- `mut`: emberjs#11023, `(mut this.val)` on a getter that reads tracked state.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…yPraam

use queryParamType for serializing
…s-without-classic-component-2

[CLEANUP] Move classic Component tests into components/classic
…royed

`RenderResult#destroy()` only destroyed the inner Glimmer render result,
never the `ComponentRootState` that wraps it. The root stayed in the
renderer's `roots` list, so the renderer was never deregistered from the
global `renderers` list, which kept the root, its args and its `into`
element alive forever.

This is most visible when `renderComponent` is called without an owner
(e.g. from a modifier): each call creates a new renderer, so every
render/destroy cycle leaked a whole renderer and the detached element.

Now destroying the result (or the owner) destroys the root, and a
destroyed root removes itself from its renderer, deregistering the
renderer once it has no roots left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6oM2SghwZ7bgTerTEx2hd
Adds API docs for the public `setModifierManager` and `capabilities`
exports of `@ember/modifier`, and declares `@ember/modifier` as a public
docs module so they show up on api.emberjs.com.

Closes emberjs#18967
Closes emberjs#20273

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JirFwqPVyTTFj5zPbonSh
The key passed to `{{get}}` is a path, so `{{get obj "some.key"}}`
reads `obj.some.key`. Document that, and show a plain function as the
way to read a property whose name contains a period. Also fix the
sentence after the dynamic key example, which referred to an example
that no longer exists.

Closes emberjs#21411

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JirFwqPVyTTFj5zPbonSh
…dlers

Adds a "Listener Order" section to the `{{on}}` docs covering:

- listeners passed in through `...attributes` run before the element's
  own `{{on}}` listeners, wherever `...attributes` appears
- classic component event handler methods like `click()` run after
  `{{on}}` listeners, and `stopPropagation()` in one of those listeners
  prevents them

Both behaviors are pinned with tests so the docs stay accurate.

Closes emberjs#17877

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JirFwqPVyTTFj5zPbonSh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JirFwqPVyTTFj5zPbonSh
Replace the classic component `click()` test with a @glimmer/component
that has a listener on a wrapping element, and drop the classic handler
section from the docs. Also document that changing an {{on}}'s
arguments re-adds the listener, which moves it after the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JirFwqPVyTTFj5zPbonSh
Garbage from one phase (render10000Items, for example) was collected
inside a later phase, wherever V8 decided to. A change that allocates
more or less moved those collections between phases, so phase times
shifted for reasons unrelated to the phase itself.

Chrome now runs with --expose-gc, and waitForIdle() calls gc() before
the next phase starts, outside the measured marks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqJMavyH9FWrQWG3PAGzsT
Four RouterService#transitionTo tests started a transition inside
`run(() => ...)`. They now start the transition directly and wait with
`await settled()`, as an application test does.

`@ember/test-helpers` was not available in the main test build. This
commit adds it:

- `@ember/test-helpers` is a devDependency of the root package.
- `testDependencies` in rollup.config.mjs lets the test build resolve
  `@ember/test-helpers`, `@ember/test-waiters` and
  `dom-element-descriptors` from node_modules.
- babel.test.config.mjs runs the `@embroider/macros` plugin, because
  those two addons use macros.

`buildMacros()` reads NODE_ENV, but the test build selects its mode with
EMBER_ENV. The `configure` hook enables development mode from EMBER_ENV,
so `isDevelopingApp()` is the same with and without NODE_ENV.

The published build does not use babel.test.config.mjs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each tracking frame made one Tracker, one Set, and one array from that
Set. Frames are strictly nested, so beginTrackFrame now takes the
tracker for its depth from a pool.

A tracker keeps its tags in an array. A tag keeps the index at which a
tracker took it last, in a new field `slot`. A tracker has the tag if
its entry at that index is the tag, so a tag that the frame consumes
again costs one comparison.

resetTracking clears the pooled trackers. An untrack frame takes a depth
but no tracker, so the pool can have holes.

Split out of emberjs#21650.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each TrackedValue made four arrow functions and one options object.
`get`, `set`, `update` and `freeze` are now accessors that make the
bound function on its first read, and keep it. Each one has a setter,
so code can still assign to them.

The default options are one frozen object.

Split out of emberjs#21650.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
All instances have one hidden class, and V8 records which kind of value
the `#value` field held so far. If no instance held a number yet, the
first number makes V8 throw away the optimized code of each function
that reads a TrackedValue.

The constructor now stores a number before the value, so the field is
general from the first instance.

Split out of emberjs#21650.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The `for...of` loop made one iterator for each computation of a
combined tag.

The loop keeps `Math.max`. A `>` comparison ignores the NaN revision of
the volatile tag.

Split out of emberjs#21650.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The comment blocks now show the tags array of a tracker, how `slot`
finds a tag that the frame has already, the nested frame that gives a
duplicate, and which tracker of the pool each frame depth uses.

Comments only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mer-versions-of-classic-tests

[CLEANUP] Add Glimmer versions of classic component tests
…er-component-root-leak

[BUGFIX lts] Release renderComponent roots (and renderers) when the result is destroyed
The renderComponent tests wrapped each render, update and destroy in
`run(() => ...)`. The tests now call the API directly and wait with
`await renderSettled()`, as an application does.

- `renderComponent()` renders synchronously. The test helper asserts the
  HTML immediately after the call, with no wait.
- Each tracked update and each destroy is followed by
  `await renderSettled()`.
- `AbstractStrictTestCase` no longer uses `runTask` and `runDestroy`.
  Only this test file extends that class.

No test was added, removed or renamed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Removed setter methods for get, set, update, and freeze in TrackedValue.
…led-from-test-helpers

Use settled from @ember/test-helpers in the RouterService transitionTo tests
…ker-pool

Pool the trackers of tracking frames
Updated comments in the constructor for clarity.

Linting
ef4 and others added 28 commits October 9, 2026 12:13
… in tests

Glimmer was developed in a separate repository, so the Glimmer integration
tests (`@glimmer-workspace/integration-tests`) and Ember's own tests each
grew stand-ins for the other. Both now run in the same page, so the real
thing is available to both. This series removes those stand-ins one step at
a time, keeping every behavior covered. Each PR leaves the whole browser
suite green.

This first step is mechanical:

- The Glimmer harness's `GlimmerishComponent`
  (`lib/components/emberish-glimmer.ts`) is replaced by `@glimmer/component`
  in 36 files and deleted. The `Glimmer` component kind now uses the real
  class.
  Test components that define a constructor type its owner as `Owner` from
  `@ember/owner`, a new devDependency of the integration-tests package.
- Ember's second copy, `tests/utils/glimmerish-component.js`, is replaced by
  `@glimmer/component` in its 7 users and deleted.
- 9 Ember test files import `hash`, `array`, `concat`, `get`, `fn` and
  `invokeHelper` from `@ember/helper`, `on` from `@ember/modifier`, and
  template-only components from `@ember/component/template-only`, instead of
  reaching into `@glimmer/runtime`.

No test is added or removed. The suite runs 9541 tests: 9523 pass, 0 fail,
18 skipped, the same as `main`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…l Ember tests cover

Depends on ef4/test-cleanup-1.

The Glimmer harness tested several hand-written imitations of Ember. Where
an Ember test already checks the same behavior on the real thing, the
Glimmer copy is deleted. Each deletion was compared assertion by assertion
with its twin, not only by name.

- `helpers/fn-test.ts`: the two tests built on a fake `mut` are deleted,
  along with the fake. They are twinned by `helpers/fn-test.js` "can be used on
  the result of `mut`" (and "... with a falsy value"), which use the real
  `mut`.
- The fake safe strings (`makeSafeString` and a `{ toHTML }` literal) are
  replaced by `htmlSafe` from `@ember/template`. The one duck-typing test of a
  plain `{ toHTML }` object stays.
- `owner-test.ts`:
  - The two per-template-owner tests are deleted, and with them the fake
    `OwnerJitRuntimeResolver`. They are twinned by `application/engine-test.js`
    "sharing a template/layout between engine and application has separate
    refinements".
  - A new `mount-test.js` test, "components rendered inside an engine are
    created with the engine as their owner", pins owner identity of nested
    components in an engine.
- `ember-component-test.ts` ran on a fake classic component. 34 of its 74
  tests have a twin on real classic components (`curly-components-test.js`,
  `contextual-components-test.js`, `dynamic-components-test.js`,
  `components/classic/*`, `fragment-components-test.js`,
  `attribute-bindings-test.js`) and are deleted. The other 40 stay until
  cleanup 4 ports them.

Suite: 9504 tests (38 removed, 1 added), 0 fail.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…blic managers

Depends on ef4/test-cleanup-2.

The Glimmer harness registered helpers as hand-built references
(`createComputeRef` over reified arguments) and modifiers through an
internal modifier manager. Now both go through the public manager APIs, so
no test builds references or uses an internal manager:

- `registerHelper(name, fn)` keeps its `(positional, named)` signature but
  now registers a `setHelperManager` helper with 3.23 capabilities.
- `registerModifier` builds a `setModifierManager` modifier with 3.22
  capabilities. Its manager (`LegacyHookModifierManager`) maps the old hook
  names the tests use (`didInsertElement`, `didUpdate`, `willDestroyElement`)
  to `installModifier`, `updateModifier` and `destroyModifier`. All 17 tests in
  `modifiers-test.ts` pass unchanged on it.
- The `registerInternalHelper` uses in `updating-test.ts` are rewritten as
  plain helpers or as subclasses of the existing public `TestHelper`. They
  still observe destruction through the same destructor counts.
- `createHelperRef`, `registerInternalHelper`, `registerInternalModifier` and
  the old `TestModifierManager` are deleted.

No test is added or removed: the suite stays at 9504 tests, 0 fail.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
use the real @glimmer/component and public imports in tests
Delete Glimmer tests of fake Ember pieces that real Ember tests cover
The tests now use module and test from qunit, setupRenderingTest from
ember-qunit, and render and settled from @ember/test-helpers.

No test is added, removed or renamed.

Two additions support the tests:

- qunit-dom is a dev dependency, for assert.dom().hasText() after an
  update.
- assert.stableRender() records the DOM nodes, waits for settled(), then
  checks that each node is the same node. With a string, it also
  compares the rendered HTML. It replaces assertStableRerender() and the
  expect option of renderComponent() of RenderingTestCase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
register test helpers and modifiers through the public managers
…lla-gjs-tests-2

Migrate five more glimmer integration tests to plain .gjs tests with setupRenderingTest
A separate commit keeps the file history, because git does not detect
the rename after the rewrite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts and delete the fake classic component

Depends on ef4/test-cleanup-3.

`componentModule` registers each component test once per invocation form:
Glimmer (`<TestComponent>`), Curly (`{{#test-component}}`) and Dynamic
(`{{#component this.componentName}}`). Curly and Dynamic ran on
`EmberishCurlyComponent`, a hand-written imitation of Ember's classic
`Component` and `CurlyComponentManager`. Its hook order, wrapper element,
`attributeBindings` and positional params were copies that could drift from
the real ones.

This PR keeps the three forms, and all three now invoke a real
`@glimmer/component`, registered on a real owner and resolved through Ember's
resolver. Curly and Dynamic are kept because they test the caller side of
curly invocation across the has-block / has-block-params / yield matrix:
default and `{{else}}` blocks and block params passed through
`{{#foo-bar}}…{{else}}…{{/foo-bar}}` and `{{#component x}}…{{else}}…`. Ember's
own tests have no `{{else}}`, `to="inverse"` or `has-block-params` after
`{{component`, so for dynamic invocation these tests are the only coverage.

Harness:

- Each test delegate has a real owner (`buildOwner()` from
  `internal-test-helpers`), destroyed after each test; the rehydration
  delegate has one per side. Components are registered on it and resolved by
  Ember's `ResolverImpl`, and templates are created with it.
- Helpers and modifiers keep the test registry, and rendering stays on the
  VM's `renderMain`, until cleanup 5.
- The three forms register the same component and the same layout, so there
  is no wrapper element and `assertComponent` checks the same element for
  all of them. Arguments are named arguments (`foo=bar` in curly form, read as
  `@foo`). Angle brackets pass an `{{else}}` block as `<:else>`.

First, every classic-specific case is ported:

- 22 new tests run on real classic components. The ported cases cover:
  - invocation attributes vs `attributeBindings`;
  - `...attributes` in a classic layout;
  - class merging with `classNames`;
  - named blocks;
  - `yield to="else"`;
  - positional params and currying;
  - unique ids, value binding to null, and destroyed-once;
  - range inputs.

  They go into `components/classic/angle-bracket-invocation-test.js`,
  `curly-components-test.js`, `classic/contextual-components-test.js` and
  others.
- Of the 40 tests that ran only as Curly and Dynamic (has-block 11,
  has-block-params 26, yield 3), 39 now run in all three forms; the other,
  which renders its own template, runs as Glimmer. Three has-block-params
  tests whose names did not match their templates are fixed. The three named-block tests
  of the fake become Glimmer tests.
- `ember-component-test.ts` becomes `components-test.ts`, with 26 tests on
  `@glimmer/component` or template-only components.

Then the fake is removed:

- Deleted: `EmberishCurlyComponent` and its manager,
  `registerEmberishCurlyComponent`, `assertEmberishElement`, and the
  `ember-view` branches in shared tests.
- The other 6 classic-only tests of the blocks suite (`attributeBindings`,
  `...attributes` on the wrapper, named blocks on a classic component) are
  ported above or have a real classic twin; 3 skipped `ariaRole` tests go.
- Four tests pinned behavior only the fake had, and are dropped:
  - `targetObject` threading;
  - components reading dynamic scope;
  - `attributeBindings = ['class']`, which real Ember rejects
    (`attribute-bindings-test.js`);
  - `recompute()` re-firing `didReceiveAttrs`, which a real `rerender()` does
    not.
- Not fanned out any more: the two debugger tests and the element-modifier
  test, which render a string template, so their Curly and Dynamic runs were
  identical to the Glimmer one; and the rehydration component suite, most of
  whose tests render no component. Four rehydration cases that used classic
  components come back in cleanup 6.

Suite: 9290 tests, 0 fail.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The tests now use module and test from qunit, setupRenderingTest from
ember-qunit, and render and settled from @ember/test-helpers.

No test is added, removed or renamed.

The {{element}} helper tests, which are already plain tests, now use
assert.dom() and the same template layout as the ten files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The root package and the two smoke test app templates used 5.5.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ade-test-helpers

Upgrade @ember/test-helpers to 5.7.0
Many tests call `A()` from `@ember/array` only for historical reasons.
RFC 1114 deprecates `A()`, so each such test would need a deprecation
expectation and a removal guard, and its coverage would go away with
`A()`.

These tests now use a native array, or `trackedArray` when the test
changes the array in place. The assertions are the same.

- Rendering tests: positional params, curly components, life cycle,
  `link-to`, `let`, `if`, `unbound`.
- Application tests: route models and query param values.
- `ArrayProxy` tests where the content does not need Ember array
  methods.
- `it considers empty arrays falsy` has a native array version and an
  Ember array version.
- `observable_test.js` makes the Ember array in the one test that
  needs it.

Tests about Ember arrays do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er and resolver

The Glimmer harness had its own environment (`BaseEnv`), a test registry and
resolver for helpers and modifiers (`TestJitRegistry`,
`TestJitRuntimeResolver`), and hand-driven transactions
(`env.begin()`/`commit()`, `inTransaction`). `RenderTest.set` dirtied tags
by hand. All of that is replaced by Ember's real pieces.

Renderer:
- Every delegate builds an Ember `BaseRenderer` (`lib/modes/renderer.ts`).
  Components render through public `renderComponent`.
- Tests get a `RenderHandle` (`{ rerender, destroy }`) instead of the VM's
  `RenderResult`.
- The server side of the SSR and rehydration delegates uses the same renderer
  with the serialize builder, and the client side with the rehydrate builder.
  Partial rehydration calls `BaseRenderer.render` into a cursor, because
  `renderComponent`'s replace-on-rerender does not apply there.
- `BaseEnv` is deleted, along with the hand-driven transactions.

Owner and resolver (cleanup 4 gave each delegate a real owner, destroyed
after each test, and resolved components through Ember's `ResolverImpl`):
- The owner now also owns the renderer, so destroying it after each test
  destroys every root. It registers `-view-registry:main`, which classic
  components need.
- `registerHelper` and `registerModifier` register on the owner too, and
  every name, built-in keywords included, resolves through `ResolverImpl`.
  The test registry and resolver are deleted.
- In rehydration tests, registrations of every kind reach both owners until
  the server render, and only the client owner after it (as components
  already did). That is how the "mismatched" tests give the client a
  different layout.

Test context:
- The test context is a `trackedObject` from `@ember/reactive/collections`.
- The collection tests import from `@ember/reactive/collections`.
- Hand-made tags became tracked counters.
- 18 tests mutate untracked nested objects and then re-set the same object to
  force an update. The context uses `equals: () => false` to keep them
  working. They should move to tracked data later.

Other changes:
- Remaining public imports: template-only components, `@ember/helper`,
  `@ember/modifier`.
- `captureRenderTree` comes from `@ember/debug`.
- New devDependencies of the integration-tests package: `@ember/renderer`,
  `@ember/destroyable`, `@ember/component`, `@ember/reactive`,
  `@ember/debug`.

Behavior changes in tests, all following from the real implementation:
- Tests that destroy explicitly do so inside `run()`, before the DOM is
  cleared: "Void Elements" and the chaos-rehydration iterations. Two 3.22
  modifier-manager tests destroy before their final assertions.
- The 8 tests that overrode the built-in `hash` helper no longer do: Ember
  refuses to override a built-in. The tests themselves stay.
- "Updating: missing helper" asserts the throw from `render`.
- "Non-native keyword" is deleted. It tested the compiler's `keywords`
  option and a `$keyword.` resolver hook, which have no Ember API.
- `lib/suites/entry-point.ts` is deleted. It was exported but never
  registered.

Suite: 9289 tests (1 removed), 0 fail.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The integration-tests package re-exported `tracked` from `@glimmer/tracking`
(`lib/test-helpers/tracked.ts`, with a TODO to remove the indirection). Its
users now import it from `@glimmer/tracking`, and the re-export is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- `defComponent(source, { scope, component })` compiled a strict-mode
  template and attached it to a component: that is the public runtime
  `template(source, { scope: () => scope, component })` from
  `@ember/template-compiler/runtime`, which the debug-render-tree tests now
  call directly.
- `elementId(element)` (`element.getAttribute('id')`) had no callers.
- `owner.ts` no longer imports `associateDestroyableChild` or the
  `BaseRenderer` type, which the previous commit left unused.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
These tests are about routing, locations and the router service.
They used `.extend()`, `reopen()`, the `get` and `set` methods,
`EmberObject` fixtures and `computed` only for historical reasons.

- `.extend()` and `reopen()` become native classes and assignments.
- The `get` method becomes a property read.
- The `set` method becomes the `set` function.
- `EmberObject` fixtures become plain classes.
- `subclass()` on the application test case replaces a registration
  with a subclass of it.

The classic class changes come from emberjs#21673, so that PR can show only
the deprecation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`typeOf` must return 'class' for a classic class and for a native
class. The test now has one assertion for each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Render Glimmer tests through Ember's renderer, owner, and resolver
…y-tests-native

Use native and tracked arrays in tests that are not about Ember arrays
…ing-tests-native-classes

Use native classes in routing tests that are not about classic classes
@NullVoxPopuli
NullVoxPopuli deleted the nvp/mixin-followups-merge-main branch October 11, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants