Skip to content

Inaccurate code coverage with aot testing #64583

Closed

Description

@cexbrayat

Command

test

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Running ng test with AoT enabled produced inaccurate code coverage for branches, with signals (always?) marked as a not tested branch.

For example: input.required<UserModel>(); has <UserModel>() marked as untested (but input.required is marked as tested),
computed(...) or signal(...) have their last parenthesis marked as an untested branch as well.

Minimal Reproduction

This can be reproduced in a brand new CLI app.

npx @angular/cli@21.0.0-next.8 new aot-coverage --defaults --no-routing
cd aot-coverage

Running ng test --no-watch --code-coverage gives:

=============================== Coverage summary ===============================
Statements   : 100% ( 5/5 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 0/0 )
Lines        : 100% ( 3/3 )
================================================================================

Running ng test --no-watch --code-coverage --aot gives:

=============================== Coverage summary ===============================
Statements   : 100% ( 50/50 )
Branches     : 85.71% ( 6/7 )
Functions    : 100% ( 7/7 )
Lines        : 100% ( 43/43 )
================================================================================

In coverage/aot-coverage/app.ts.html we can see the last parenthesis of the signal is marked as not tested:

Image

Exception or Error


Your Environment

Angular CLI       : 21.0.0-next.8
Angular           : 21.0.0-next.8
Node.js           : 22.18.0
Package Manager   : npm 10.9.0
Operating System  : darwin arm64

┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package                   │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build            │ 21.0.0-next.8     │ ^21.0.0-next.8    │
│ @angular/cli              │ 21.0.0-next.8     │ ^21.0.0-next.8    │
│ @angular/common           │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/compiler         │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/compiler-cli     │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/core             │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/forms            │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/platform-browser │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ @angular/router           │ 21.0.0-next.8     │ ^21.0.0-next.0    │
│ rxjs                      │ 7.8.2             │ ~7.8.0            │
│ typescript                │ 5.9.3             │ ~5.9.2            │
└───────────────────────────┴───────────────────┴───────────────────┘

Anything else relevant?

Note that the same happens with the unit-test runner, with Vitest or Karma.

Activity

  1. changed the title [-]Inaccurate code coverage ith aot testing[/-] [+]Inaccurate code coverage with aot testing[/+] on Oct 22, 2025
  2. clydin commented on Oct 22, 2025

    @clydin
    Member

    Most likely cause is the signalMetadataTransform located here in the Angular compiler:

    export function signalMetadataTransform(program: ts.Program): ts.TransformerFactory<ts.SourceFile> {

    Transferring to the framework repo for further triage.

  3. transferred this issue fromangular/angular-clion Oct 22, 2025
  4. added this to the needsTriage milestone on Oct 22, 2025
  5. added
    area: compilerIssues related to `ngc`, Angular's template compiler
    and removed
    area: coreIssues related to the framework runtime
    on Oct 23, 2025
  6. JeanMeche commented on Oct 23, 2025

    @JeanMeche
    Member

    I'm seeing that we apply the transform unconditionnaly. This raises 2 issues

    • It applied even in prod mode, but DCE takes care of removing all the code we generate (this is sub optimal)
    • We should probably only enable it for runtime only dev mode.
  7. dgp1130 commented on Oct 27, 2025

    @dgp1130
    Contributor

    I'm assuming the issue here is that we're effectively generating a conditional on ngDevMode along the lines of ngDevMode ? 'someDebugName' : undefined. Since testing only runs with ngDevMode === true, the false part of this branch is never executed, triggering coverage with weird line numbers, since this isn't present in source code.

    We could disable the transform for ng test, but this is not trivial to do in google3, since we share a single emit format for both testing and non-testing use cases, so we can't easily determine when to enable / disable this transform.

    I think the better solution is likely to continue to always use this transform but then include some kind of ignore comment telling the coverage tool to ignore the false conditional. c8 seems to support an ignore statement and I vaguely recall some kind of LCOV_IGNORE directive? Not sure of the full matrix of support coverage tools and their opt-outs to know how viable this really is.

  8. fagia commented on Dec 22, 2025

    @fagia

    Still same issue also with Angular 21.0.1

  9. Ritzlgrmft commented on Jan 12, 2026

    @Ritzlgrmft

    still the same issue with Angular 21.0.5

    is there any workaround beside ignoring signal lines like:

    // c8 ignore next 
    protected readonly title = signal('my-signal');
    
  10. Martinspire commented on Feb 26, 2026

    @Martinspire

    So what can we do about this? Is there some setting that is conflicting or what? With Analog Vitest, I did not have this issue (perhaps because they compiled it themselves). But migration is blocked if the numbers aren't reported properly. I also think that ignoring code might lead to other issues as well.

  11. mpalourdio commented on Feb 26, 2026

    @mpalourdio

    I find this a little irritating too. We force quality gates in our CI (based on code coverage among other metrics), but for now, we had to disable this check for angular 21 projects.

    Could this get a bit of love please ? Thanks!

  12. added a commit that references this issue on Feb 26, 2026
    2e53627
  13. added a commit that references this issue on Mar 4, 2026
    05d022d
  14. added a commit that references this issue on Mar 4, 2026
    dc4cf64
  15. added a commit that references this issue on Mar 24, 2026
    292f0e9
  16. angular-automatic-lock-bot commented on Apr 4, 2026

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions