Skip to content

Instantly share code, notes, and snippets.

@tkaczenko
Created December 11, 2020 16:55
Show Gist options
  • Save tkaczenko/b8dfcf404b85405a1775ca5f24289107 to your computer and use it in GitHub Desktop.
Save tkaczenko/b8dfcf404b85405a1775ca5f24289107 to your computer and use it in GitHub Desktop.
How to make Angular component testing? (Mocking, Observable, Emitters)
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');
});
});
});
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