diff --git a/packages/@ember/-internals/glimmer/lib/base-renderer.ts b/packages/@ember/-internals/glimmer/lib/base-renderer.ts
index 955511c4389..d4069d23cf4 100644
--- a/packages/@ember/-internals/glimmer/lib/base-renderer.ts
+++ b/packages/@ember/-internals/glimmer/lib/base-renderer.ts
@@ -1,6 +1,7 @@
import { ENV } from '@ember/-internals/environment/lib/env';
import type { InternalOwner } from '@ember/-internals/owner';
import { assert } from '@ember/debug';
+import { registerComponentRenderer } from '@ember/debug/lib/capture-render-tree';
import { _backburner, _getCurrentRunLoop } from '@ember/runloop';
import {
associateDestroyableChild,
@@ -516,6 +517,7 @@ export function renderComponent(
hasDOM: env && 'hasDOM' in env ? Boolean(env?.['hasDOM']) : true,
});
RENDERER_CACHE.set(owner, renderer);
+ registerComponentRenderer(owner, renderer);
}
/**
diff --git a/packages/@ember/-internals/glimmer/tests/integration/application/debug-render-tree-test.ts b/packages/@ember/-internals/glimmer/tests/integration/application/debug-render-tree-test.ts
index c92745f5a3a..2b0143f8621 100644
--- a/packages/@ember/-internals/glimmer/tests/integration/application/debug-render-tree-test.ts
+++ b/packages/@ember/-internals/glimmer/tests/integration/application/debug-render-tree-test.ts
@@ -1,7 +1,11 @@
import { ApplicationTestCase, ModuleBasedTestResolver, moduleFor } from 'internal-test-helpers';
import { ENV } from '@ember/-internals/environment';
-import { Component as EmberComponent, setComponentManager } from '@ember/-internals/glimmer';
+import {
+ Component as EmberComponent,
+ renderComponent,
+ setComponentManager,
+} from '@ember/-internals/glimmer';
import Component from '@glimmer/component';
import type { InternalOwner } from '@ember/-internals/owner';
import Route from '@ember/routing/route';
@@ -1128,6 +1132,53 @@ if (ENV._DEBUG_RENDER_TREE) {
]);
}
+ async '@test components rendered with renderComponent'() {
+ await this.visit('/');
+
+ let HelloWorld = setComponentTemplate(
+ precompileTemplate('Hello {{@name}}', { strictMode: true }),
+ templateOnly()
+ );
+ let Root = setComponentTemplate(
+ precompileTemplate('', {
+ strictMode: true,
+ scope: () => ({ HelloWorld }),
+ }),
+ templateOnly()
+ );
+ let into = document.createElement('div');
+
+ let result = runTask(() => renderComponent(Root, { owner: this.owner, into }));
+
+ let roots = captureRenderTree(this.owner).filter((node) => node.type === 'component');
+
+ this.assertRenderNodes(
+ roots,
+ [
+ {
+ type: 'component',
+ name: '{ROOT}',
+ args: { positional: [], named: {} },
+ instance: null,
+ bounds: this.elementBounds(into),
+ children: [
+ {
+ type: 'component',
+ name: 'HelloWorld',
+ args: { positional: [], named: { name: 'world' } },
+ instance: null,
+ bounds: this.elementBounds(into),
+ children: [],
+ },
+ ],
+ },
+ ],
+ 'root'
+ );
+
+ runTask(() => result.destroy());
+ }
+
async '@test components'() {
this.add(
'template:application',
diff --git a/packages/@ember/debug/lib/capture-render-tree.ts b/packages/@ember/debug/lib/capture-render-tree.ts
index 03c5cd4b3fa..13285172bc3 100644
--- a/packages/@ember/debug/lib/capture-render-tree.ts
+++ b/packages/@ember/debug/lib/capture-render-tree.ts
@@ -1,7 +1,21 @@
import type { Renderer } from '@ember/-internals/glimmer/lib/renderer';
+import type { BaseRenderer } from '@ember/-internals/glimmer/lib/base-renderer';
import type Owner from '@ember/owner';
import type { CapturedRenderNode } from '@glimmer/interfaces';
+/**
+ * `renderComponent` renders with its own renderer per owner,
+ * separate from the owner's `renderer:-dom`.
+ *
+ * The renderer registers itself here,
+ * because importing it would be a circular import.
+ */
+const COMPONENT_RENDERERS = new WeakMap