Reputation: 59
I`m trying to write unit tests to cover every line of my code. I have two lines of my code that are not covered.
I can`t understand where I make a mistake and how I can cover these lines of code?
Here is an image of not covered lines of code:
Product-item.spect.ts
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture,TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ProductService } from '../../services/product.service';
import { ProdItemComponent } from './product-item.component';
describe('ProdItemComponent', () => {
let component: ProdItemComponent;
let fixture: ComponentFixture<ProdItemComponent>;
let productService: ProductService;
let mockProductItem: any;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProductItemComponent],
imports: [HttpClientTestingModule, RouterTestingModule],
providers: [ProductService],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
mockProductItem= {
id: "c7336f01-5219-4631-a865-af1fa9837766",
title:"Carpet",
description:"A soft Carpet"
}
fixture = TestBed.createComponent(ProductItemComponent);
component = fixture.componentInstance;
productService = TestBed.inject(ProductService);
fixture.detectChanges();
component.productItem = mockProductItem;
component.selectedItemId = component.mockProductItem.id;
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call delete method', () => {
component.onDelete();
fixture.detectChanges();
productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
expect(selectedItemId).toBeTruthy();
const spy = spyOn(component.fetchDataEventEmitter, 'emit');
expect(spy).toHaveBeenCalled();
})
});
expect(component.displayConfirmDialog).toBe(false);
});
Product-service.ts
deleteProduct(productId: string) {
return this.httpClient.delete(
this.BASE_URL +
this.DELETE_ITEM_URL(
productId
)
)
}
Product-component.ts
onDelete(): void {
if (this.selectedItemId) {
this.productService.deleteProduct(this.selectedItemId).subscribe(res => {
this.fetchDataEventEmitter.emit();
});
}
this.displayConfirmDialog = false;
}
Upvotes: 2
Views: 8719
Reputation: 18809
The last expect
here is out of place, it should be moved one line up.
it('should call delete method', () => {
component.onDelete();
fixture.detectChanges();
productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
expect(selectedItemId).toBeTruthy();
const spy = spyOn(component.fetchDataEventEmitter, 'emit');
expect(spy).toHaveBeenCalled();
});
// should go here
expect(component.displayConfirmDialog).toBe(false);
});
// expect(component.displayConfirmDialog).toBe(false);
You need to mock ProductService
using a spyObject because you don't want to be doing actual http
calls in your unit tests.
let component: ProdItemComponent;
let fixture: ComponentFixture<ProdItemComponent>;
let productService: ProductService;
let mockProductItem: any;
// add this line
let mockProductService: jasmine.SpyObj<ProductService>;
beforeEach(async(() => {
// create a spy object
// the first string is an identifier and is optional. The array of strings
// are the public methods that you would like to mock.
mockProductService = jasmine.createSpyObj<ProductService>('ProductService', ['deleteProduct']);
TestBed.configureTestingModule({
declarations: [ProductItemComponent],
// get rid of HttpClientTestingModule since we are mocking
// ProductService now
imports: [/*HttpClientTestingModule*/, RouterTestingModule],
// when the component asks for ProductService, give the mocked one
providers: [{ provide: ProductService, useValue: mockProductService }],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
...
it('should call delete method', () => {
// make the deleteProduct method return an observable of empty string
mockProductService.deleteProduct.and.returnValue(of(''));
// spy on the emission
const emitSpy = spyOn(component.fetchDataEventEmitter, 'emit');
component.onDelete();
fixture.detectChanges();
expect(emitSpy).toHaveBeenCalled();
expect(component.displayConfirmDialog).toBeFalse();
});
Upvotes: 3
Reputation: 742
Try to assign a simple observable to your fetchDataEventEmitter
property and move it to the top of the case:
it('should call delete method', () => {
component.fetchDataEventEmitter = of({})
component.onDelete();
fixture.detectChanges();
productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
expect(selectedItemId).toBeTruthy();
})
});
Upvotes: 0
Reputation: 214
It looks like you are creating the spy object too late in the execution. If you create the spy object before calling productService.delete but leave the expect assertion where it is, that should solve the issue.
Upvotes: 0