Improve code coverage on Angular 21 “signal oriented” directive

Summary

The issue at hand is related to insufficient code coverage in an Angular 21 component library, specifically with the use of input and computed signals inside a directive. Despite having unit tests that pass, the V8 coverage engine reports uncovered blocks of code, leading to a failed quality gate in SonarQube.

Root Cause

The root cause of this issue can be attributed to the following factors:

  • Limited test coverage: The current unit tests may not be comprehensive enough to cover all possible scenarios and edge cases.
  • Signal-oriented programming: The use of input and computed signals in the directive can make it challenging to achieve full code coverage.
  • V8 coverage engine limitations: The V8 coverage engine may have limitations in tracking coverage for certain types of code, such as signal-oriented programming.

Why This Happens in Real Systems

This issue can occur in real systems due to:

  • Complexity of signal-oriented programming: The use of input and computed signals can introduce complexity, making it difficult to ensure full code coverage.
  • Limited understanding of signal-oriented programming: Developers may not fully understand how to properly test and cover signal-oriented code.
  • Inadequate testing strategies: Insufficient or inadequate testing strategies can lead to poor code coverage.

Real-World Impact

The real-world impact of this issue includes:

  • Failed quality gates: Insufficient code coverage can lead to failed quality gates, delaying or preventing the release of software.
  • Reduced confidence in code quality: Poor code coverage can reduce confidence in the overall quality of the codebase.
  • Increased maintenance costs: Uncovered code can lead to increased maintenance costs and difficulties in debugging and troubleshooting.

Example or Code

@Directive({
  selector: 'button[customButton]',
  host: {
    '[class]': '_classes()',
  },
})
export class Button {
  // Input signal to set the loading state (true|false)
  public readonly loading = input();

  // Computed signal for getting the CSS class based on the loading state
  private readonly _loading = computed(() => (this.loading() ? 'is-loading' : ''));

  // ...
}

How Senior Engineers Fix It

Senior engineers can fix this issue by:

  • Implementing comprehensive testing strategies: Developing thorough and well-structured tests to cover all possible scenarios and edge cases.
  • Using recommended patterns and workarounds: Utilizing established patterns and workarounds for testing signal-oriented code, such as using spy functions or mock implementations.
  • Leveraging code coverage tools: Using code coverage tools, such as Istanbul or Jest, to identify and address uncovered code.

Why Juniors Miss It

Junior engineers may miss this issue due to:

  • Lack of experience with signal-oriented programming: Limited familiarity with signal-oriented programming concepts and testing strategies.
  • Insufficient understanding of code coverage: Poor understanding of code coverage principles and the importance of achieving full coverage.
  • Inadequate testing habits: Inconsistent or inadequate testing habits, leading to poor code coverage and reduced confidence in code quality.