Published on

# Angular Unit Tests with Jest - This constructor is not compatible with Angular Dependency Injection

Authors

In this short article, you'll learn how to fix this annyoing issue in Angular when you're starting to implement component unit tests with Jest that have dependencies. Or you might be just migrating away from Jasmine and Karma.

## What the error?

If you have an Angular component that depends on a service, and you've just migrated to Jest from Jasmine and Karma, you might see something as follows if you've missed one critical step:

This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.

Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors.

at ɵɵinvalidFactoryDep (../packages/core/src/di/injector_compatibility.ts:112:9)


## Example:

Let's suppose we have a component named WatchComponent as follows:

import { Component, OnInit } from '@angular/core'
import { WatchService } from 'src/app/services/watch.service'

@Component({
selector: 'app-watch',
templateUrl: './watch.component.html',
styleUrls: ['./watch.component.scss'],
})
export class WatchComponent implements OnInit {
time: string

constructor(private watchService: WatchService) {}

ngOnInit(): void {
this.time = this.watchService.getTime()
}

startTimer() {
this.watchService.startTimer()
}

stopTimer() {
this.watchService.stopTimer()
}

resetTimer() {
this.watchService.resetTimer()
}
}


And we have the WatchService as follows:

import { Injectable } from '@angular/core'

@Injectable({
providedIn: 'root',
})
export class WatchService {
constructor() {}

getTime() {
return new Date()
}

startTimer() {
//some code
}

stopTimer() {
//some code
}

resetTimer() {
//some code
}
}


If you write the tests as follows, you'll still see the error we've mentioned above:

import { ComponentFixture, TestBed } from '@angular/core/testing'
import { WatchService } from 'src/app/services/watch.service'

import { WatchComponent } from './watch.component'

describe('WatchComponent', () => {
let component: WatchComponent
let fixture: ComponentFixture<WatchComponent>
let watchServiceStub: Partial<WatchService>
let watchService

beforeEach(async () => {
watchServiceStub = {
startTimer: () => {},
stopTimer: () => {},
resetTimer: () => {},
}
await TestBed.configureTestingModule({
declarations: [WatchComponent],
providers: [{ provide: WatchService, useValue: watchServiceStub }],
}).compileComponents()
})

beforeEach(() => {
fixture = TestBed.createComponent(CounterComponent)
component = fixture.componentInstance
fixture.detectChanges()
watchService = TestBed.inject(WatchService)
})

it('should get the inital value of time from the service on component init', () => {
component.ngOnInit()
expect(watchService.getTime).toBeCalled()
})
})


## Solution?

The reason why the tests work with Karma and Jasmine, and not with Jests is just one tiny thing missing from one of the tsconfig files that some of the articles online have missed. For example, while working on the #ngBook I'm writing as of today, I followed this article and ended up with the mentioned issue.

If you've faced the same, just make sure that you have set both the esModuleInterop and emitDecoratorMetadata properties to true inside your tsconfig.spec.json file. It should ideally look something as follows:

{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jest", "node"],
"esModuleInterop": true,

The esModuleInterop property makes sure you don't get any weird warnings from Jest while running the tests. And the emitDecoratorMetadata makes sure that the decorator metadata information is compatible and available beween Angular's Dependency Injection and Jest.