angularjasminekarma-jasmineangular-testangular18

Angular test case fails with NG0203: inject() must be called from an injection context


I'm testing an Angular 18 standalone component using TestBed and running into this error when the component is initialized during a unit test: Error: NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with runInInjectionContext. Find more at https://angular.dev/errors/NG0203

Below are the test cases for the component:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SomeComponent } from './some-component.component';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';

describe('SomeComponent', () => {
  let component: SomeComponent;
  let fixture: ComponentFixture<SomeComponent>;
  let mockRoute: jasmine.SpyObj<ActivatedRoute>;

  beforeEach(async () => {
    mockRoute = jasmine.createSpyObj('ActivatedRoute', ['fragment'], { fragment: of('test-anchor') });

    await TestBed.configureTestingModule({
      imports: [SomeComponent], 
      providers: [{ provide: ActivatedRoute, useValue: mockRoute }],
    }).compileComponents();

    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Component code:

import { Component, OnDestroy } from '@angular/core';
import { LibCommonService, PLATFORM_BEHAVIOR_TYPE_ENUM, PreferencesDashboardComponent } from '@pseudoLib/pseudo-common-elements';
import { TranslateModule } from '@ngx-translate/core';
import { ActivatedRoute } from '@angular/router';
import { Subject, takeUntil } from 'rxjs';
import { NgIf } from '@angular/common';
import { DetailsService } from 'src/shared/services/details.service';
import { MEMBER_TYPE_ENUM } from 'src/shared/models/enums/details.enum';

@Component({
  selector: 'app-some',
  standalone: true,
  imports: [TranslateModule, NgIf, PreferencesDashboardComponent],
  templateUrl: './some.component.html',
  styleUrl: './some.component.scss',
})
export class SomeComponent implements OnDestroy {
  private destroy$ = new Subject<void>();

  PLATFORM_BEHAVIOR_TYPE_ENUM = PLATFORM_BEHAVIOR_TYPE_ENUM;

  projectId!: string;

  memberId!: string;

  memberType!: PLATFORM_BEHAVIOR_TYPE_ENUM;

  constructor(
    private activatedRoute: ActivatedRoute,
    private libCommonService: LibCommonService,
    private DetailsService: DetailsService,
  ) {
    this.projectId = this.libCommonService.projectIdBehaviorSub.getValue();
    this.activatedRoute.parent?.params?.pipe(takeUntil(this.destroy$)).subscribe((params) => {
      this.memberId = params.id;
    });
    this.DetailsService.memberDetails$.pipe(takeUntil(this.destroy$)).subscribe(async (memberDetails) => {
      if (memberDetails?.memberType === MEMBER_TYPE_ENUM.PRIMARY) {
        this.memberType = PLATFORM_BEHAVIOR_TYPE_ENUM.PRIMARY_MEMBER;
      } else if (memberDetails?.memberType === MEMBER_TYPE_ENUM.ASSOCIATE) {
        this.memberType = PLATFORM_BEHAVIOR_TYPE_ENUM.ASSOCIATE_MEMBER;
      }
    });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

How can I resolve the NG0203: inject() error in the test environment? Any advice on how to properly configure the test environment for a standalone component using this service would be appreciated.

Angular Version: Angular 18


Solution

  • Your component code itself does not produce the error as there is no injectcall. The error must come from one of the injected services LibCommonService or DetailsService or from code you deleted for SO from the component.

    Sticking with the assumption it is caused by the services:

    As you want to unit test your component, you should mock those services.

    await TestBed.configureTestingModule({
      imports: [SomeComponent], 
      providers: [
        { provide: ActivatedRoute, useValue: mockRoute },
        { provide: LibCommonService, useValue: { projectIdBehaviorSub: new BehaviorSubject<string>('someProjectId') } },
        { provide: DetailsService, useValue: { memberDetails$: new BehaviorSubject<MemberDetails>({ memberDetails: MEMBER_TYPE_ENUM.PRIMARY }) } },
      ],
    }).compileComponents();
    

    The error should be eliminated by eliminating those dependencies