angulardependency-injectionjasmineangular-servicesangular-standalone-components

Mocking injected provided service in standalone angular component AND NOT IN ROOT for karma jasmine tests


FYI: I am using angular 19.1.0 with karma

Let's assume we have this service and component

// NOT PROVIDED IN ROOT!
@Injectable()
export class TestService {
  getData(): string {
    return 'this is real data'
  }
}
// Standalone component!
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
  providers: [TestService]
})
export class AppComponent {
  service = inject(TestService)
}

As you noticed, the service is not provided in root but is provided in the component and injected as well. I noticed with this setting that i am not able to mock this service in the karma unit tests. I can see it has to do with the service being provided in the component, but i am not sure how i can fix it. Here is a snippet of the test.

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [AppComponent],
      providers: [{
        provide: TestService,
        useValue: {
          getData: () => ('mocked data'),
        }
      }]
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;

    expect(app).toBeTruthy();

    console.log(app.service.getData())
  });
});

I should expect here that app.service.getData() should log out "mocked data", however, i get "this is real data".

enter image description here


Solution

  • The component is not having the mocked service( might be because it was not provided in the root of the application ). So try the overrideProvider method to configure the mock service, this method works.

    describe('AppComponent', () => {
      beforeEach(async () => {
        await TestBed.configureTestingModule({
          imports: [AppComponent],
          providers: [
            {
              provide: TestService,
              useValue: {
                getData: () => 'mocked data',
              },
            },
          ],
        })
        .overrideProvider(TestService, {          // <- changed here!
            useValue: {                           // <- changed here!
              getData: () => 'mocked data',       // <- changed here!
            },                                    // <- changed here!
        })                                        // <- changed here!
        .compileComponents();
      });
    
      it('should create the app', () => {
        const fixture = TestBed.createComponent(AppComponent);
        const app = fixture.componentInstance;
    
        expect(app).toBeTruthy();
    
        console.log(app.service.getData());
      });
    });