I am writing unit test for a angular component using karma-jasmine. I have used providers in my ProfileComponent and injected ProfileService.
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss'],
providers: [ProfileService]
})
export class ProfileComponent implements OnInit {
public data;
constructor(private profileService: ProfileService) {}
ngOnInit() {
await this.profileService.login();
this.profileService.getData('A').subscribe((result) => {
this.data = result;
});
}
}
profile.service.ts
@Injectable()
export class ProfileService {
private baseUrl: string;
constructor(private http: HttpClient) {
this.baseUrl = 'https://localhost:4002';
}
public async login() {
const loginUrl = `${this.baseUrl}/api/Login`;
return this.http.post(loginUrl, {}, { headers }).toPromise();
}
getData(id: string) {
const url = `${this.baseUrl}/api/GetData/${id}`;
return this.http.get(url, { headers });
}
}
profile.component.spec.ts
const data = ['A', 'B', 'C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture < ProfileComponent > ;
let profileService: ProfileService;
let profileData;
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ProfileService],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(fakeAsync(() => {
profileData = new Subject();
profileService = TestBed.inject < ProfileService > (ProfileService);
spyOn(profileService, 'login').and.returnValue({});
spyOn(profileService, 'getData').and.returnValue(profileData);
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
profileData.next(data);
fixture.detectChanges();
expect(component).toBeDefined();
});
});
I added a debugger and checked that its failing in login. So, I have two questions:
Profile Component
, can I inject the ProfileService
in the profile.component.spec.ts
file as it will create two instance of the same service?spyOn(profileService, 'login').and.returnValue({});
Please help me on this.
Answer: You should create a Stub
for the service to replace dependency on actual ProfileService
using useClass
export class ProfileServiceStub {
getData(id: string) {
return of({some_obj: "value"})
}
}
and in spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ {provide: ProfileService , useClass: ProfileServiceStub } ], // <-- useclass here
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
Answer: Make the service public
in component constructor as below:
constructor(public profileService: ProfileService) { }
I would strongly recommend you to read my article on something similar where I have tested the component
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With