import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {ExecutionComponent} from './execution.component'; import {Component, ViewChild} from "@angular/core"; import {Job, JobExecution} from "../../model/job"; import {JobsService} from "../../services/jobs.service"; import {ProductsService} from "../../services/products.service"; import {ConfigurationService} from "../../env/configuration.service"; import {ReactiveFormsModule} from "@angular/forms"; import {By} from "@angular/platform-browser"; import {of} from "rxjs"; import {ContentEditableDirective} from "../../directives/content-editable.directive"; import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; @Component({ template: '<app-qa-job [job]="job" [queue]="queue"></app-qa-job>' }) class HostComponent { job: Job = { job_arch_status: "ARCHIVED", job_endtime: 1565212305634, job_endtime_formatted: "08/07/2019, 02:11:45 PM", job_id: 123, job_name: "jobName", job_starttime: 1564785856832, job_starttime_formatted: "08/02/2019, 03:44:16 PM", job_status: "QA_ACCEPTED", jobspec_creation_date: 1563346880361, jobspec_creation_date_formatted: "07/17/2019, 12:01:20 AM", jobspec_id: 321, jobspec_name: "JobSpecName", jobspec_sdm_id: "JobSpecNameSDMid", jobspec_status: "QA_ACCEPTED" }; queue: string = 'calibration'; @ViewChild(ExecutionComponent, /* TODO: add static flag */ {}) qaJobComponent: ExecutionComponent; } export class fakeConfigService { static get config() { return { url: "http://localhost:4200/VlassMngr", rootDataDirectory: '/lustre/aoc/cluster/pipeline/vlass_test/spool', weblogbaseurl: 'http://webtest.aoc.nrao.edu/' }; }; } describe('ExecutionComponent', () => { let component: HostComponent; let fixture: ComponentFixture<HostComponent>; let jobServiceSpy: { getJob: jasmine.Spy, getJobSpec: jasmine.Spy, updateJobStatus: jasmine.Spy, updateNotes: jasmine.Spy }; let productServiceSpy: { updateProductStatus: jasmine.Spy }; beforeEach(async(() => { jobServiceSpy = jasmine.createSpyObj('JobsService', ['getJob', 'getJobSpec', 'updateJobStatus', 'updateNotes']); productServiceSpy = jasmine.createSpyObj('ProductsService', ['updateProductStatus']); TestBed.configureTestingModule({ declarations: [HostComponent, ExecutionComponent, ContentEditableDirective], providers: [ {provide: JobsService, useValue: jobServiceSpy}, {provide: ProductsService, useValue: productServiceSpy}, {provide: ConfigurationService, useValue: fakeConfigService} ], imports: [ReactiveFormsModule, BrowserAnimationsModule] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; jobServiceSpy = TestBed.get(JobsService); productServiceSpy = TestBed.get(ProductsService); }); it('should create', () => { fixture.detectChanges(); expect(component).toBeTruthy(); }); it('should set the status form control to the job status on init', () => { component.qaJobComponent.detailsExposed = true; fixture.detectChanges(); //ngOnInit let statusEl: HTMLSelectElement = fixture.debugElement.query(By.css('select.status')).nativeElement; expect(statusEl.value).toEqual(component.job.job_status, 'job status control set from job') }); it('should set detailsExposed to true, get the job details from the service and update the noteForm controls', fakeAsync(() => { jobServiceSpy.getJob.and.returnValue(of({ analyst: null, archivalJob: null, archiveStatus: "UNARCHIVED", end: 1556444603753, endDate: "04/28/2019, 02:43:23 AM", id: 123, jobSpecId: 321, jsonResults: null, name: "JobExecution", notes: "These are notes", queueName: "quicklook", sdmId: "JobExectuionSDMid", start: 1556151603773, startDate: "04/24/2019, 05:20:03 PM", status: "QA_ACCEPTED", tasks: [] } as JobExecution)); expect(component.qaJobComponent.detailsExposed).toBeFalsy('detailsExposed starts false'); fixture.detectChanges(); //ngOnInit component.qaJobComponent.showDetails(); expect(jobServiceSpy.getJob).toHaveBeenCalledTimes(1); fixture.detectChanges(); tick(); expect(component.qaJobComponent.detailsExposed).toBeTruthy('detailsExposed set to true'); expect(component.qaJobComponent.noteFormGroup.get('notes').value).toEqual('These are notes', 'notes set from service value'); expect(component.qaJobComponent.noteFormGroup.get('id').value).toEqual(123, 'id set from service value'); })); it('should set detailsExposed to false when hideDetails() is called', () => { component.qaJobComponent.detailsExposed = true; fixture.detectChanges(); //ngOnInit component.qaJobComponent.hideDetails(); expect(component.qaJobComponent.detailsExposed).toBeFalsy('set detailsExposed to false'); }); it('getJobStatusClass() should return the right class based on job_spec status', () => { fixture.detectChanges(); //ngOnInit component.qaJobComponent.job.jobspec_status = 'ERROR'; expect(component.qaJobComponent.getJobStatusClass()).toEqual('badge-danger', 'badge-danger returned for ERROR'); component.qaJobComponent.job.jobspec_status = 'QA_REJECTED'; expect(component.qaJobComponent.getJobStatusClass()).toEqual('badge-warning', 'badge-warning returned for QA_REJECTED'); component.qaJobComponent.job.jobspec_status = 'PROCESSING'; expect(component.qaJobComponent.getJobStatusClass()).toEqual('badge-primary', 'badge-primary returned for PROCESSING'); component.qaJobComponent.job.jobspec_status = 'QA_ACCEPTED'; expect(component.qaJobComponent.getJobStatusClass()).toEqual('badge-info', 'badge-info returned for others'); }); it('getTaskStatusBgClass() should return the right class based on passed in status', () => { expect(component.qaJobComponent.getTaskStatusBgClass('ERROR')).toEqual('bg-danger', 'bg-danger returned for ERROR'); expect(component.qaJobComponent.getTaskStatusBgClass('SUCCESS')).toEqual('bg-success', 'bg-success returned for SUCCESS'); expect(component.qaJobComponent.getTaskStatusBgClass('OTHER')).toEqual('bg-info', 'bg-info returned for OTHER'); }); it('getTaskStatusBadgeClass() should return the right class based on passed in status', () => { expect(component.qaJobComponent.getTaskStatusBadgeClass('ERROR')).toEqual('badge-danger', 'badge-danger returned for ERROR'); expect(component.qaJobComponent.getTaskStatusBadgeClass('SUCCESS')).toEqual('badge-success', 'badge-success returned for SUCCESS'); expect(component.qaJobComponent.getTaskStatusBadgeClass('OTHER')).toEqual('badge-info', 'badge-info returned for OTHER'); }); it('canAcceptArchive() shoud return correct boolean based on passed in params', () => { expect(component.qaJobComponent.canAcceptArchive('QA_READY', 'ARCHIVED')).toBeTruthy('QA_READY returns true'); expect(component.qaJobComponent.canAcceptArchive('QA_MANUAL', 'ARCHIVED')).toBeTruthy('QA_MANUAL returns true'); expect(component.qaJobComponent.canAcceptArchive('QA_ON_HOLD', 'ARCHIVE_ERROR')).toBeTruthy('ARCHIVE_ERROR returns true'); expect(component.qaJobComponent.canAcceptArchive('QA_ON_HOLD', 'ARCHIVED')).toBeFalsy('other options return flase'); }); it('getConfigUrl() should return the url from the config service', () => { fixture.detectChanges(); //ngOnInit expect(component.qaJobComponent.getConfigUrl()).toEqual('http://localhost:4200/VlassMngr', 'returned url from config service'); }); it('getConfigRootDataDirectory() should return the url from the config service', () => { fixture.detectChanges(); //ngOnInit expect(component.qaJobComponent.getConfigRootDataDirectory()).toEqual('/lustre/aoc/cluster/pipeline/vlass_test/spool', 'returned url from config service'); }); it('getConfigWebLogBaseUrl() should return the url from the config service', () => { fixture.detectChanges(); //ngOnInit expect(component.qaJobComponent.getConfigWebLogBaseUrl()).toEqual('http://webtest.aoc.nrao.edu/', 'returned url from config service'); }); it('updateStatus() should call product service if the status has changed', fakeAsync(() => { productServiceSpy.updateProductStatus.and.returnValue(of('PROCESSING')); fixture.detectChanges(); //ngOnInit component.qaJobComponent.updateStatus(); expect(productServiceSpy.updateProductStatus).toHaveBeenCalledTimes(0); component.qaJobComponent.formGroup.get('status').setValue('PROCESSING'); component.qaJobComponent.updateStatus(); tick(); expect(productServiceSpy.updateProductStatus).toHaveBeenCalledTimes(1); expect(component.qaJobComponent.job.jobspec_status).toEqual('PROCESSING', 'Updated jobspec_status to service return value'); })); it('updateNotes() should call the job service and hide and call hideDetails()', fakeAsync(() => { jobServiceSpy.updateNotes.and.returnValue(of('')); let hideDetailsSpy = spyOn(component.qaJobComponent, "hideDetails"); component.qaJobComponent.detailsExposed = true; component.qaJobComponent.noteFormGroup.get('id').setValue(123); component.qaJobComponent.noteFormGroup.get('notes').setValue('These are notes'); fixture.detectChanges(); //ngOnInit component.qaJobComponent.updateNotes(); expect(jobServiceSpy.updateNotes).toHaveBeenCalledWith(123, 'These are notes'); tick(); expect(hideDetailsSpy.calls.count()).toEqual(1, 'called hideDetails'); })); it('acceptQa() should call performQa() with id and accept', () => { let performQaSpy = spyOn(component.qaJobComponent, 'performQa'); component.qaJobComponent.acceptQa(123); expect(performQaSpy).toHaveBeenCalledWith(123, 'accept'); }); it('rejectQa() should call performQa() with id and reject', () => { spyOn(window, 'confirm').and.returnValue(true); let performQaSpy = spyOn(component.qaJobComponent, 'performQa'); component.qaJobComponent.rejectQa(123); expect(performQaSpy).toHaveBeenCalledWith(123, 'reject'); }); it('performQa() should call the job service and hideDetails()', fakeAsync(() => { jobServiceSpy.updateJobStatus.and.returnValue(of('')); let hideDetailsSpy = spyOn(component.qaJobComponent, "hideDetails"); fixture.detectChanges(); //ngOnInit component.qaJobComponent.performQa(123, 'accept'); expect(jobServiceSpy.updateJobStatus).toHaveBeenCalledTimes(0); component.qaJobComponent.job.job_status = 'QA_READY'; component.qaJobComponent.performQa(123, 'accept'); expect(jobServiceSpy.updateJobStatus).toHaveBeenCalledWith(123, 'QA_ACCEPTED', 'calibration'); tick(); expect(hideDetailsSpy).toHaveBeenCalledTimes(1); })); });