Skip to content

Commit 05d022d

Browse files
dgp1130atscott
authored andcommitted
fix(compiler-cli): ignore generated ngDevMode signal branch for code coverage
The Angular compiler unconditionally adds a debug name transform for signals which generates a conditional on `ngDevMode` (e.g., `ngDevMode ? { debugName: "xyz" } : []`). During testing, `ngDevMode` is true, so the true branch executes but the false branch is never executed. Consequently, coverage tools report the false branch as an untested line/branch, preventing 100% test coverage. This commit adds a synthetic `/* istanbul ignore next */` comment to the generated false branch so that Istanbul ignores it. We only include the istanbul comment (instead of additionally including c8) to focus on the established standard for Angular CLI/Karma coverage while maintaining compatibility with modern Vitest setups, since @vitest/coverage-v8 now natively respects the fallback istanbul comment. Fixes #64583 (cherry picked from commit dc4cf64)
1 parent 1df1697 commit 05d022d

File tree

9 files changed

+86
-80
lines changed

9 files changed

+86
-80
lines changed

packages/compiler-cli/src/ngtsc/transform/src/implicit_signal_debug_name_transform.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ function createNgDevModeConditional(
8989
devModeExpression: ts.Expression,
9090
prodModeExpression: ts.Expression,
9191
): ts.ParenthesizedExpression {
92+
ts.addSyntheticLeadingComment(
93+
prodModeExpression,
94+
ts.SyntaxKind.MultiLineCommentTrivia,
95+
' istanbul ignore next ',
96+
false,
97+
);
9298
return ts.factory.createParenthesizedExpression(
9399
ts.factory.createConditionalExpression(
94100
ts.factory.createIdentifier('ngDevMode'),

packages/compiler-cli/test/compliance/test_cases/model_inputs/GOLDEN_PARTIAL.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import { Directive, model } from '@angular/core';
55
import * as i0 from "@angular/core";
66
export class TestDir {
7-
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
8-
name = model.required(...(ngDevMode ? [{ debugName: "name" }] : []));
7+
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
8+
name = model.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
99
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1010
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestDir, isStandalone: true, inputs: { counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { counter: "counterChange", name: "nameChange" }, ngImport: i0 });
1111
}
@@ -31,8 +31,8 @@ export declare class TestDir {
3131
import { Component, model } from '@angular/core';
3232
import * as i0 from "@angular/core";
3333
export class TestComp {
34-
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
35-
name = model.required(...(ngDevMode ? [{ debugName: "name" }] : []));
34+
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
35+
name = model.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
3636
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComp, deps: [], target: i0.ɵɵFactoryTarget.Component });
3737
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestComp, isStandalone: true, selector: "ng-component", inputs: { counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { counter: "counterChange", name: "nameChange" }, ngImport: i0, template: 'Works', isInline: true });
3838
}
@@ -60,8 +60,8 @@ export declare class TestComp {
6060
import { Directive, EventEmitter, Input, model, Output } from '@angular/core';
6161
import * as i0 from "@angular/core";
6262
export class TestDir {
63-
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
64-
modelWithAlias = model(false, { ...(ngDevMode ? { debugName: "modelWithAlias" } : {}), alias: 'alias' });
63+
counter = model(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
64+
modelWithAlias = model(false, { ...(ngDevMode ? { debugName: "modelWithAlias" } : /* istanbul ignore next */ {}), alias: 'alias' });
6565
decoratorInput = true;
6666
decoratorInputWithAlias = true;
6767
decoratorOutput = new EventEmitter();

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/GOLDEN_PARTIAL.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ export declare class MyComponent {
187187
import { Component, signal } from '@angular/core';
188188
import * as i0 from "@angular/core";
189189
export class MyComponent {
190-
enterClass = signal('slide', ...(ngDevMode ? [{ debugName: "enterClass" }] : []));
190+
enterClass = signal('slide', ...(ngDevMode ? [{ debugName: "enterClass" }] : /* istanbul ignore next */ []));
191191
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
192192
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: true, selector: "my-component", ngImport: i0, template: `
193193
<div>
@@ -296,7 +296,7 @@ export declare class MyComponent {
296296
import { Component, signal } from '@angular/core';
297297
import * as i0 from "@angular/core";
298298
export class MyComponent {
299-
leaveClass = signal('fade', ...(ngDevMode ? [{ debugName: "leaveClass" }] : []));
299+
leaveClass = signal('fade', ...(ngDevMode ? [{ debugName: "leaveClass" }] : /* istanbul ignore next */ []));
300300
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
301301
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: true, selector: "my-component", ngImport: i0, template: `
302302
<div>

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_arrow_functions/GOLDEN_PARTIAL.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import { Component, signal } from '@angular/core';
55
import * as i0 from "@angular/core";
66
export class TestComp {
7-
sigA = signal(1, ...(ngDevMode ? [{ debugName: "sigA" }] : []));
8-
sigB = signal(2, ...(ngDevMode ? [{ debugName: "sigB" }] : []));
7+
sigA = signal(1, ...(ngDevMode ? [{ debugName: "sigA" }] : /* istanbul ignore next */ []));
8+
sigB = signal(2, ...(ngDevMode ? [{ debugName: "sigB" }] : /* istanbul ignore next */ []));
99
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComp, deps: [], target: i0.ɵɵFactoryTarget.Component });
1010
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: TestComp, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
1111
<button (click)="sigA.update(value => value + 1)">Increment A</button>
@@ -144,7 +144,7 @@ export declare class TestComp {
144144
import { Component, signal } from '@angular/core';
145145
import * as i0 from "@angular/core";
146146
export class TestComp {
147-
someSignal = signal('', ...(ngDevMode ? [{ debugName: "someSignal" }] : []));
147+
someSignal = signal('', ...(ngDevMode ? [{ debugName: "someSignal" }] : /* istanbul ignore next */ []));
148148
componentProp = 0;
149149
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComp, deps: [], target: i0.ɵɵFactoryTarget.Component });
150150
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "0.0.0-PLACEHOLDER", type: TestComp, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
@@ -272,7 +272,7 @@ export declare class TestDir {
272272
import { Directive, signal } from '@angular/core';
273273
import * as i0 from "@angular/core";
274274
export class TestDir {
275-
someSignal = signal(0, ...(ngDevMode ? [{ debugName: "someSignal" }] : []));
275+
someSignal = signal(0, ...(ngDevMode ? [{ debugName: "someSignal" }] : /* istanbul ignore next */ []));
276276
componentProp = 1;
277277
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
278278
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: TestDir, isStandalone: true, host: { listeners: { "click": "someSignal.update(prev => prev + 1)", "mousedown": "someSignal.update(() => componentProp + 1)" } }, ngImport: i0 });
@@ -611,7 +611,7 @@ import { Component, signal } from '@angular/core';
611611
import * as i0 from "@angular/core";
612612
export class TestComp {
613613
componentProp = 0;
614-
result = signal('', ...(ngDevMode ? [{ debugName: "result" }] : []));
614+
result = signal('', ...(ngDevMode ? [{ debugName: "result" }] : /* istanbul ignore next */ []));
615615
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComp, deps: [], target: i0.ɵɵFactoryTarget.Component });
616616
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "0.0.0-PLACEHOLDER", type: TestComp, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
617617
@let topLevelLet = 1;

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/control_bindings/GOLDEN_PARTIAL.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { Component, Directive, input } from '@angular/core';
55
import * as i0 from "@angular/core";
66
export class FormField {
7-
formField = input(...(ngDevMode ? [undefined, { debugName: "formField" }] : []));
7+
formField = input(...(ngDevMode ? [undefined, { debugName: "formField" }] : /* istanbul ignore next */ []));
88
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: FormField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
99
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: FormField, isStandalone: true, selector: "[formField]", inputs: { formField: { classPropertyName: "formField", publicName: "formField", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
1010
}
@@ -54,7 +54,7 @@ export declare class MyComponent {
5454
import { Component, Directive, input } from '@angular/core';
5555
import * as i0 from "@angular/core";
5656
export class FormField {
57-
formField = input(...(ngDevMode ? [undefined, { debugName: "formField" }] : []));
57+
formField = input(...(ngDevMode ? [undefined, { debugName: "formField" }] : /* istanbul ignore next */ []));
5858
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: FormField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5959
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: FormField, isStandalone: true, selector: "[formField]", inputs: { formField: { classPropertyName: "formField", publicName: "formField", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
6060
}

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_listener/GOLDEN_PARTIAL.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ export declare class App {
953953
import { Component, Directive, model, signal } from '@angular/core';
954954
import * as i0 from "@angular/core";
955955
export class NgModelDirective {
956-
ngModel = model.required(...(ngDevMode ? [{ debugName: "ngModel" }] : []));
956+
ngModel = model.required(...(ngDevMode ? [{ debugName: "ngModel" }] : /* istanbul ignore next */ []));
957957
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: NgModelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
958958
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: NgModelDirective, isStandalone: true, selector: "[ngModel]", inputs: { ngModel: { classPropertyName: "ngModel", publicName: "ngModel", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { ngModel: "ngModelChange" }, ngImport: i0 });
959959
}
@@ -1005,7 +1005,7 @@ export declare class TestCmp {
10051005
import { Component, Directive, model } from '@angular/core';
10061006
import * as i0 from "@angular/core";
10071007
export class NgModelDirective {
1008-
ngModel = model('', ...(ngDevMode ? [{ debugName: "ngModel" }] : []));
1008+
ngModel = model('', ...(ngDevMode ? [{ debugName: "ngModel" }] : /* istanbul ignore next */ []));
10091009
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: NgModelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
10101010
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: NgModelDirective, isStandalone: true, selector: "[ngModel]", inputs: { ngModel: { classPropertyName: "ngModel", publicName: "ngModel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { ngModel: "ngModelChange" }, ngImport: i0 });
10111011
}

packages/compiler-cli/test/compliance/test_cases/signal_inputs/GOLDEN_PARTIAL.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import { Directive, input } from '@angular/core';
55
import * as i0 from "@angular/core";
66
export class TestDir {
7-
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
8-
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
7+
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
8+
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
99
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1010
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestDir, isStandalone: true, inputs: { counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
1111
}
@@ -31,8 +31,8 @@ export declare class TestDir {
3131
import { Component, input } from '@angular/core';
3232
import * as i0 from "@angular/core";
3333
export class TestComp {
34-
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
35-
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
34+
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
35+
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
3636
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComp, deps: [], target: i0.ɵɵFactoryTarget.Component });
3737
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestComp, isStandalone: true, selector: "ng-component", inputs: { counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: 'Works', isInline: true });
3838
}
@@ -63,9 +63,9 @@ function convertToBoolean(value) {
6363
return value === true || value !== '';
6464
}
6565
export class TestDir {
66-
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : []));
67-
signalWithTransform = input(false, { ...(ngDevMode ? { debugName: "signalWithTransform" } : {}), transform: convertToBoolean });
68-
signalWithTransformAndAlias = input(false, { ...(ngDevMode ? { debugName: "signalWithTransformAndAlias" } : {}), alias: 'publicNameSignal', transform: convertToBoolean });
66+
counter = input(0, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
67+
signalWithTransform = input(false, { ...(ngDevMode ? { debugName: "signalWithTransform" } : /* istanbul ignore next */ {}), transform: convertToBoolean });
68+
signalWithTransformAndAlias = input(false, { ...(ngDevMode ? { debugName: "signalWithTransformAndAlias" } : /* istanbul ignore next */ {}), alias: 'publicNameSignal', transform: convertToBoolean });
6969
decoratorInput = true;
7070
decoratorInputWithAlias = true;
7171
decoratorInputWithTransformAndAlias = true;
@@ -110,7 +110,7 @@ function convertToBoolean(value) {
110110
return value === true || value !== '';
111111
}
112112
export class TestDir {
113-
name = input.required({ ...(ngDevMode ? { debugName: "name" } : {}), transform: convertToBoolean });
113+
name = input.required({ ...(ngDevMode ? { debugName: "name" } : /* istanbul ignore next */ {}), transform: convertToBoolean });
114114
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
115115
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestDir, isStandalone: true, inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
116116
}
@@ -139,10 +139,10 @@ const toBoolean = (v) => v === true || v !== '';
139139
// Note: `@Input` non-signal inputs did not support transform function "builders" and generics.
140140
const complexTransform = (defaultVal) => (v) => v || defaultVal;
141141
export class TestDir {
142-
name = input.required({ ...(ngDevMode ? { debugName: "name" } : {}), transform: (v) => v === true || v !== '' });
143-
name2 = input.required({ ...(ngDevMode ? { debugName: "name2" } : {}), transform: toBoolean });
144-
genericTransform = input.required({ ...(ngDevMode ? { debugName: "genericTransform" } : {}), transform: complexTransform(1) });
145-
genericTransform2 = input.required({ ...(ngDevMode ? { debugName: "genericTransform2" } : {}), transform: complexTransform(null) });
142+
name = input.required({ ...(ngDevMode ? { debugName: "name" } : /* istanbul ignore next */ {}), transform: (v) => v === true || v !== '' });
143+
name2 = input.required({ ...(ngDevMode ? { debugName: "name2" } : /* istanbul ignore next */ {}), transform: toBoolean });
144+
genericTransform = input.required({ ...(ngDevMode ? { debugName: "genericTransform" } : /* istanbul ignore next */ {}), transform: complexTransform(1) });
145+
genericTransform2 = input.required({ ...(ngDevMode ? { debugName: "genericTransform2" } : /* istanbul ignore next */ {}), transform: complexTransform(null) });
146146
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
147147
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "0.0.0-PLACEHOLDER", type: TestDir, isStandalone: true, inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, name2: { classPropertyName: "name2", publicName: "name2", isSignal: true, isRequired: true, transformFunction: null }, genericTransform: { classPropertyName: "genericTransform", publicName: "genericTransform", isSignal: true, isRequired: true, transformFunction: null }, genericTransform2: { classPropertyName: "genericTransform2", publicName: "genericTransform2", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
148148
}

0 commit comments

Comments
 (0)