Created
December 11, 2020 16:55
-
-
Save tkaczenko/b8dfcf404b85405a1775ca5f24289107 to your computer and use it in GitHub Desktop.
How to make Angular component testing? (Mocking, Observable, Emitters)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | |
import { CurrentSubscriptionsComponent } from './current-subscriptions.component'; | |
import { BaseReportConfig, CoverageConfig, QbePoliciesReportPeriod, ReportType, ResidentType } from '../../../models/report-config'; | |
import { | |
DayOfWeek, | |
MomentOfMonth, | |
Periodicity, | |
ReportSubscriptionBasePeriodicity, | |
ReportSubscriptionConfig, | |
ReportSubscriptionLevel, | |
ReportSubscriptionsResponse | |
} from '../../../models/report-subscription-config'; | |
import { SessionInfo } from '../../../models/session-info'; | |
import { ReportSubscriptionsService } from '../../../services/report-subscriptions/report-subscriptions.service'; | |
import { createStub } from '../../../../test/helpers/create-stub'; | |
import { BsModalRef, BsModalService } from 'ngx-bootstrap'; | |
import { EventEmitterService } from '../../../services/event-emitter/event-emitter.service'; | |
import { ToasterService } from '../../../services/toaster-service/toaster.service'; | |
import { of, throwError } from 'rxjs'; | |
import { EventEmitter } from '@angular/core'; | |
import createSpy = jasmine.createSpy; | |
describe('CurrentSubscriptionsComponent', () => { | |
const mockSessionInfo = createStub(SessionInfo); | |
const mockReportSubscriptionsService = createStub(ReportSubscriptionsService); | |
const mockBsModalService = createStub(BsModalService); | |
const mockBsModalRef = createStub(BsModalRef); | |
const mockEventEmitterService = createStub(EventEmitterService); | |
const mockToasterService = createStub(ToasterService); | |
const mockRefreshEmitter = new EventEmitter(); | |
const mockDeleteEmitter = new EventEmitter<number>(); | |
const reportSubscriptionId = 0; | |
const propertyId = 1; | |
const reportSubscription = <ReportSubscriptionConfig>{ | |
id: reportSubscriptionId, | |
name: 'Test subscription', | |
emails: ['atkachenko@corelogic.com', 'asadovnychyi@corelogic.com'], | |
level: ReportSubscriptionLevel.PROPERTY, | |
emailingFrequency: new ReportSubscriptionBasePeriodicity(), | |
reportConfig: new CoverageConfig(), | |
createdDate: new Date() | |
}; | |
const reportSubscriptionsResponse: ReportSubscriptionsResponse = <ReportSubscriptionsResponse>{ | |
propertyId: propertyId, | |
reportSubscriptions: [reportSubscription] | |
}; | |
let component: CurrentSubscriptionsComponent; | |
let fixture: ComponentFixture<CurrentSubscriptionsComponent>; | |
beforeEach(async(() => { | |
TestBed.configureTestingModule({ | |
declarations: [CurrentSubscriptionsComponent], | |
providers: [ | |
{ | |
provide: SessionInfo, | |
useValue: mockSessionInfo | |
}, | |
{ | |
provide: ReportSubscriptionsService, | |
useValue: mockReportSubscriptionsService | |
}, | |
{ | |
provide: BsModalService, | |
useValue: mockBsModalService | |
}, | |
{ | |
provide: BsModalRef, | |
useValue: mockBsModalRef | |
}, | |
{ | |
provide: EventEmitterService, | |
useValue: mockEventEmitterService | |
}, | |
{ | |
provide: ToasterService, | |
useValue: mockToasterService | |
} | |
] | |
}) | |
.compileComponents(); | |
})); | |
beforeEach(() => { | |
spyOn(mockSessionInfo, 'getCurrentClPropertyId').and.returnValue(propertyId); | |
spyOn(mockReportSubscriptionsService, 'getSubscriptions').and.returnValue(of([])); | |
spyOn(mockReportSubscriptionsService, 'deleteSubscription').and.returnValue(of({})); | |
spyOn(mockEventEmitterService, 'getRefreshReportSubscriptionTableEmitter').and.returnValue(mockRefreshEmitter); | |
spyOn(mockEventEmitterService, 'getDeleteReportSubscriptionEmitter').and.returnValue(mockDeleteEmitter); | |
fixture = TestBed.createComponent(CurrentSubscriptionsComponent); | |
component = fixture.componentInstance; | |
fixture.detectChanges(); | |
}); | |
it('should create', () => { | |
expect(component).toBeTruthy(); | |
}); | |
describe('ngOnInit', () => { | |
it('should refresh subscriptions when init component', () => { | |
mockReportSubscriptionsService.getSubscriptions = createSpy().and.returnValue(of([reportSubscriptionsResponse])); | |
component.ngOnInit(); | |
expect(component.currentSubscriptions).toContain(reportSubscription); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledTimes(1); | |
}); | |
it('should show toast with error message when cannot refresh subscriptions', () => { | |
mockReportSubscriptionsService.getSubscriptions = createSpy().and.returnValue(throwError({status: 500})); | |
spyOn(mockToasterService, 'showError'); | |
component.ngOnInit(); | |
expect(mockToasterService.showError).toHaveBeenCalledWith('Subscriptions cannot be loaded. Please try again later', null); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledTimes(1); | |
}); | |
}); | |
it('should refresh current subscriptions when refresh emit is come', () => { | |
mockRefreshEmitter.emit(); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledWith([propertyId]); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledTimes(2); | |
}); | |
describe('delete subscription', () => { | |
it('should delete subscription and refresh subscriptions when delete emit is come', () => { | |
spyOn(mockEventEmitterService, 'fireRefreshReportSubscriptionTableEmitter').and.callFake(() => { | |
mockRefreshEmitter.emit(); | |
}); | |
mockDeleteEmitter.emit(reportSubscriptionId); | |
expect(mockReportSubscriptionsService.deleteSubscription).toHaveBeenCalledWith(reportSubscriptionId); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledWith([propertyId]); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledTimes(2); | |
}); | |
it('should show toast with error message when cannot delete subscription', () => { | |
mockReportSubscriptionsService.deleteSubscription = createSpy().and.returnValue(throwError({status: 500})); | |
spyOn(mockToasterService, 'showError'); | |
mockDeleteEmitter.emit(reportSubscriptionId); | |
expect(mockToasterService.showError).toHaveBeenCalledWith('Subscription was NOT deleted. Please try again later', null); | |
expect(mockReportSubscriptionsService.getSubscriptions).toHaveBeenCalledTimes(1); | |
}); | |
}); | |
describe('getTypeOrPeriod', () => { | |
let reportConfig: BaseReportConfig; | |
beforeEach(() => { | |
reportConfig = new BaseReportConfig(); | |
}); | |
it('should return period when reportConfig is instance of QbePoliciesReportConfig', () => { | |
const types = [ReportType.QBE_POLICIES]; | |
reportConfig['period'] = QbePoliciesReportPeriod.CURRENT_MONTH; | |
for (const type of types) { | |
reportConfig.type = type; | |
expect(component.getTypeOrPeriod(reportConfig)).toEqual(QbePoliciesReportPeriod.CURRENT_MONTH); | |
} | |
}); | |
it('should return days when reportConfig is instance of ReportPeriodConfig', () => { | |
const types = [ReportType.NON_DELIVERED, ReportType.TRACKER_POLICIES, ReportType.NON_COMPLIANCE_DELIVERY]; | |
reportConfig['days'] = 7; | |
for (const type of types) { | |
reportConfig.type = type; | |
expect(component.getTypeOrPeriod(reportConfig)).toEqual('7'); | |
} | |
}); | |
it('should return residentType when reportConfig is instance of CoverageConfig', () => { | |
const types = [ReportType.COVERAGE]; | |
reportConfig['residentType'] = ResidentType.ALL; | |
for (const type of types) { | |
reportConfig.type = type; | |
expect(component.getTypeOrPeriod(reportConfig)).toEqual(ResidentType.ALL); | |
} | |
}); | |
it('should return default value when reportConfig is instance of BaseReportConfig', () => { | |
const types = [ReportType.NON_COMPLIANCE_CHARGE_FAILURE, ReportType.RESIDENTS_WITHOUT_EMAILS, ReportType.POLICY_STATUS]; | |
const defaultValue = '-'; | |
for (const type of types) { | |
reportConfig.type = type; | |
expect(component.getTypeOrPeriod(reportConfig)).toEqual(defaultValue); | |
} | |
}); | |
}); | |
describe('getFrequency', () => { | |
let emailingFrequency: ReportSubscriptionBasePeriodicity; | |
beforeEach(() => { | |
emailingFrequency = new ReportSubscriptionBasePeriodicity(); | |
emailingFrequency.emailSendTime.hours = 8; | |
emailingFrequency.emailSendTime.minutes = 0; | |
}); | |
it('should return periodicity and time when periodicity is DAILY', () => { | |
emailingFrequency.periodicity = Periodicity.DAILY; | |
expect(component.getFrequency(emailingFrequency)).toEqual('Daily at 8:0'); | |
}); | |
it('should return periodicity, dayOfWeek and time when periodicity is WEEKLY', () => { | |
emailingFrequency.periodicity = Periodicity.WEEKLY; | |
emailingFrequency['dayOfWeek'] = DayOfWeek.SUNDAY; | |
expect(component.getFrequency(emailingFrequency)).toEqual('Weekly on Sunday at 8:0'); | |
}); | |
it('should return periodicity, dayOfWeek and time when periodicity is MONTHLY', () => { | |
emailingFrequency.periodicity = Periodicity.MONTHLY; | |
emailingFrequency['momentOfMonth'] = MomentOfMonth.START_OF_MONTH; | |
expect(component.getFrequency(emailingFrequency)).toEqual('Monthly on startOfMonth at 8:0'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component, OnDestroy, OnInit } from '@angular/core'; | |
import { | |
Periodicity, | |
ReportSubscriptionBasePeriodicity, | |
ReportSubscriptionConfig, | |
ReportSubscriptionsResponse, | |
} from '../../../models/report-subscription-config'; | |
import { BsModalRef, BsModalService } from 'ngx-bootstrap'; | |
import { EventEmitterService } from '../../../services/event-emitter/event-emitter.service'; | |
import { CurrentSubscriptionDeleteModalComponent } from '../current-subscription-delete-modal/current-subscription-delete-modal.component'; | |
import { ReportSubscriptionsService } from '../../../services/report-subscriptions/report-subscriptions.service'; | |
import { SessionInfo } from '../../../models/session-info'; | |
import { | |
BaseReportConfig, | |
CoverageConfig, | |
QbePoliciesReportConfig, | |
ReportConfigTypesMapping, | |
ReportPeriodConfig | |
} from '../../../models/report-config'; | |
import { Subject } from 'rxjs'; | |
import { catchError, take, takeUntil } from 'rxjs/operators'; | |
import { ToasterService } from '../../../services/toaster-service/toaster.service'; | |
@Component({ | |
selector: 'app-current-subscriptions', | |
templateUrl: './current-subscriptions.component.html', | |
styleUrls: ['./current-subscriptions.component.scss'] | |
}) | |
export class CurrentSubscriptionsComponent implements OnInit, OnDestroy { | |
currentSubscriptions: ReportSubscriptionConfig[] = []; | |
private unsubscribe: Subject<void> = new Subject(); | |
constructor(private sessionInfo: SessionInfo, | |
private reportSubscriptionsService: ReportSubscriptionsService, | |
private modalService: BsModalService, | |
private bsModalRef: BsModalRef, | |
private eventEmitterService: EventEmitterService, | |
private toasterService: ToasterService) { | |
} | |
ngOnInit() { | |
this.refresh(); | |
this.eventEmitterService.getRefreshReportSubscriptionTableEmitter() | |
.pipe( | |
takeUntil(this.unsubscribe) | |
) | |
.subscribe(() => this.refresh()); | |
this.eventEmitterService.getDeleteReportSubscriptionEmitter() | |
.pipe( | |
takeUntil(this.unsubscribe), | |
) | |
.subscribe(reportSubscriptionId => { | |
this.reportSubscriptionsService.deleteSubscription(reportSubscriptionId) | |
.pipe( | |
take(1), | |
takeUntil(this.unsubscribe), | |
catchError(() => this.toasterService.showError('Subscription was NOT deleted. Please try again later', null)) | |
) | |
.subscribe(() => this.eventEmitterService.fireRefreshReportSubscriptionTableEmitter()); | |
}); | |
} | |
ngOnDestroy() { | |
this.unsubscribe.next(); | |
this.unsubscribe.complete(); | |
} | |
showConfirmDelete(reportSubscriptionId: number) { | |
this.bsModalRef = this.modalService.show(CurrentSubscriptionDeleteModalComponent, { | |
initialState: reportSubscriptionId | |
}); | |
} | |
getTypeOrPeriod(reportConfig: BaseReportConfig): string { | |
const specificReportConfig = new ReportConfigTypesMapping[reportConfig.type](); | |
if (specificReportConfig instanceof QbePoliciesReportConfig) { | |
return specificReportConfig.period; | |
} else if (specificReportConfig instanceof ReportPeriodConfig) { | |
return specificReportConfig.days.toString(); | |
} else if (specificReportConfig instanceof CoverageConfig) { | |
return specificReportConfig.residentType; | |
} | |
return '-'; | |
} | |
getFrequency(emailingFrequency: ReportSubscriptionBasePeriodicity) { | |
const periodicity = emailingFrequency.periodicity; | |
const sendTime = `${emailingFrequency.emailSendTime.hours}:${emailingFrequency.emailSendTime.minutes}`; | |
if (Periodicity.DAILY === periodicity) { | |
return `${periodicity} at ${sendTime}`; | |
} else if (Periodicity.WEEKLY === periodicity) { | |
return `${periodicity} on ${emailingFrequency['dayOfWeek']} at ${sendTime}`; | |
} else if (Periodicity.MONTHLY === periodicity) { | |
return `${periodicity} on ${emailingFrequency['momentOfMonth']} at ${sendTime}`; | |
} | |
return ''; | |
} | |
private refresh() { | |
const currentClPropertyId = this.sessionInfo.getCurrentClPropertyId(); | |
this.reportSubscriptionsService.getSubscriptions([currentClPropertyId]) | |
.pipe( | |
take(1), | |
takeUntil(this.unsubscribe), | |
catchError(() => this.toasterService.showError('Subscriptions cannot be loaded. Please try again later', null)) | |
) | |
.subscribe((reportSubscriptionsResponse: ReportSubscriptionsResponse[]) => { | |
const subscriptionsByProperty = reportSubscriptionsResponse.find(s => s.propertyId === currentClPropertyId); | |
this.currentSubscriptions = subscriptionsByProperty != null ? subscriptionsByProperty.reportSubscriptions : []; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment