8000 fix(core): properly handle the case where getSignalGraph is called on… · angular/angular@3353fa5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3353fa5

Browse files
fix(core): properly handle the case where getSignalGraph is called on a componentless NodeInjector
Previously this would throw an error on the assertLView when we try to discover the templateLView. Now this properly returns null for the template consumer and continues discovering other effects on the injector.
1 parent 6adf022 commit 3353fa5

File tree

2 files changed

+72
-4
lines changed

2 files changed

+72
-4
lines changed

packages/core/src/render3/util/signal_debug.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
SIGNAL_NODE,
2626
SignalNode,
2727
} from '../../../primitives/signals';
28+
import {isLView} from '../interfaces/type_checks';
2829

2930
export interface DebugSignalGraphNode {
3031
kind: string;
@@ -82,9 +83,10 @@ function getTemplateConsumer(injector: NodeInjector): ReactiveLViewConsumer | nu
8283
const lView = getNodeInjectorLView(injector)!;
8384
assertLView(lView);
8485
const templateLView = lView[tNode.index]!;
85-
assertLView(templateLView);
86-
87-
return templateLView[REACTIVE_TEMPLATE_CONSUMER];
86+
if (isLView(templateLView)) {
87+
return templateLView[REACTIVE_TEMPLATE_CONSUMER] ?? null;
88+
}
89+
return null;
8890
}
8991

9092
const signalDebugMap = new WeakMap<ReactiveNode, string>();

packages/core/test/acceptance/signal_debug_spec.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,18 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Component, computed, effect, inject, Injectable, signal} from '../../src/core';
9+
import {NodeInjector} from '../../../core/src/render3/di';
10+
import {getDirectives} from '../../../core/src/render3/util/discovery_utils';
11+
import {
12+
Component,
13+
Directive,
14+
computed,
15+
effect,
16+
inject,
17+
Injectable,
18+
signal,
19+
Injector,
20+
} from '../../src/core';
1021
import {
1122
getFrameworkDIDebugData,
1223
setupFrameworkInjectorProfiler,
@@ -302,4 +313,59 @@ describe('getSignalGraph', () => {
302313
producer: fourFiveSixNode,
303314
});
304315
}));
316+
317+
it('should return no nodes or edges for a NodeInjector that only has directives and no component', () => {
318+
@Directive({
319 10000 +
selector: '[myDirective]',
320+
})
321+
class MyDirective {
322+
injector = inject(Injector);
323+
324+
readonly fooSignal = signal('foo', {debugName: 'fooSignal'});
325+
326+
barEffect = effect(
327+
() => {
328+
this.fooSignal();
329+
},
330+
{debugName: 'barEffect'},
331+
);
332+
}
333+
334+
@Component({
335+
selector: 'component-with-directive',
336+
template: `<div id="element-with-directive" myDirective></div>`,
337+
imports: [MyDirective],
338+
})
339+
class WithDirective {}
340+
341+
TestBed.configureTestingModule({imports: [WithDirective]});
342+
const fixture = TestBed.createComponent(WithDirective);
343+
fixture.detectChanges();
344+
345+
const element = fixture.nativeElement.querySelector('#element-with-directive');
346+
// get the directive instance
347+
const directiveInstances = getDirectives(element);
348+
expect(directiveInstances.length).toBe(1);
349+
const directiveInstance = directiveInstances[0];
350+
expect(directiveInstance).toBeInstanceOf(MyDirective);
351+
const injector = (directiveInstance as MyDirective).injector;
352+
expect(injector).toBeInstanceOf(NodeInjector);
353+
const signalGraph = getSignalGraph(injector);
354+
expect(signalGraph).toBeDefined();
355+
356+
const {nodes, edges} = signalGraph;
357+
expect(nodes.length).toBe(2);
358+
expect(edges.length).toBe(1);
359+
360+
const fooNode = nodes.find((node) => node.label === 'fooSignal');
361+
expect(fooNode).toBeDefined();
362+
expect(fooNode!.value).toBe('foo');
363+
364+
const barNode = nodes.find((node) => node.label === 'barEffect');
365+
expect(barNode).toBeDefined();
366+
expect(barNode!.kind).toBe('effect');
367+
368+
const edgesWithNodes = mapEdgeIndicesIntoNodes(edges, nodes);
369+
expect(edgesWithNodes).toContain({consumer: barNode!, producer: fooNode!});
370+
});
305371
});

0 commit comments

Comments
 (0)
0