diff --git a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts index 2d589547bc..28aa6c4ef0 100644 --- a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts +++ b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts @@ -19,7 +19,10 @@ import {PaginationComponentOptions} from '../../../shared/pagination/pagination- import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service'; import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; - +/** + * Angular component representing the form for creating or editing LDN services. + * This component handles the creation, validation, and submission of LDN service data. + */ @Component({ selector: 'ds-ldn-service-form', templateUrl: './ldn-service-form.component.html', @@ -100,23 +103,43 @@ export class LdnServiceFormComponent implements OnInit { } + /** + * Sets up the item filters by fetching and observing the paginated list of item filters. + */ setItemfilters() { this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe( getFirstCompletedRemoteData()); } + /** + * Handles the form submission by opening the confirmation modal. + */ onSubmit() { this.openConfirmModal(this.confirmModal); } + /** + * Opens the confirmation modal. + * + * @param {any} content - The content of the modal. + */ openConfirmModal(content) { this.modalRef = this.modalService.open(content); } + /** + * Opens the reset form modal. + * + * @param {any} content - The content of the modal. + */ openResetFormModal(content) { this.modalRef = this.modalService.open(content); } + /** + * Handles the creation of an LDN service by validating form fields, + * and submitting the form data to the LDN services endpoint. + */ createService() { this.formModel.get('name').markAsTouched(); this.formModel.get('score').markAsTouched(); @@ -175,6 +198,12 @@ export class LdnServiceFormComponent implements OnInit { }); } + /** + * Checks if at least one pattern in the specified form array has a value. + * + * @param {FormArray} formArray - The form array containing patterns to check. + * @returns {boolean} - True if at least one pattern has a value, otherwise false. + */ checkPatterns(formArray: FormArray): boolean { for (let i = 0; i < formArray.length; i++) { const pattern = formArray.at(i).get('pattern').value; @@ -185,37 +214,65 @@ export class LdnServiceFormComponent implements OnInit { return false; } - + /** + * Closes the currently open modal and returns to the services directory.. + */ resetFormAndLeave() { this.sendBack(); this.closeModal(); } + /** + * Closes the currently open modal and triggers change detection. + */ closeModal() { this.modalRef.close(); this.cdRef.detectChanges(); } + /** + * Adds a new inbound pattern form group to the notifyServiceInboundPatterns form array. + */ addInboundPattern() { const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray; notifyServiceInboundPatternsArray.push(this.createInboundPatternFormGroup()); } + /** + * Removes the inbound pattern form group at the specified index from the notifyServiceInboundPatterns form array. + * + * @param {number} index - The index of the inbound pattern form group to remove. + * @memberof LdnServiceFormComponent + */ removeInboundPattern(index: number) { const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray; notifyServiceInboundPatternsArray.removeAt(index); } + /** + * Adds a new outbound pattern form group to the notifyServiceOutboundPatterns form array. + */ addOutboundPattern() { const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray; notifyServiceOutboundPatternsArray.push(this.createOutboundPatternFormGroup()); } + /** + * Removes the outbound pattern form group at the specified index from the notifyServiceOutboundPatterns form array. + * + * @param {number} index - The index of the outbound pattern form group to remove. + */ removeOutboundPattern(index: number) { const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray; notifyServiceOutboundPatternsArray.removeAt(index); } + /** + * Toggles the value of the 'automatic' control at the specified index in the notifyServiceInboundPatterns form array. + * + * @param {number} i - The index of the 'automatic' control to toggle. + * @memberof LdnServiceFormComponent + */ toggleAutomatic(i: number) { const automaticControl = this.formModel.get(`notifyServiceInboundPatterns.${i}.automatic`); if (automaticControl) { @@ -223,7 +280,12 @@ export class LdnServiceFormComponent implements OnInit { } } - + /** + * Selects an outbound pattern for a specific index in the notifyServiceOutboundPatterns form array. + * + * @param {string} patternValue - The selected pattern value. + * @param {number} index - The index of the outbound pattern in the form array. + */ selectOutboundPattern(patternValue: string, index: number): void { const patternArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray) patternArray.controls[index].patchValue({pattern: patternValue}) @@ -231,6 +293,12 @@ export class LdnServiceFormComponent implements OnInit { } + /** + * Selects an inbound pattern for a specific index in the form array. + * + * @param {string} patternValue - The selected pattern value. + * @param {number} index - The index of the inbound pattern in the form array. + */ selectInboundPattern(patternValue: string, index: number): void { const patternArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray) patternArray.controls[index].patchValue({pattern: patternValue}) @@ -238,21 +306,40 @@ export class LdnServiceFormComponent implements OnInit { } + /** + * Selects an inbound item filter for a specific index in the form array. + * + * @param {string} filterValue - The selected item filter value. + * @param {number} index - The index of the inbound item filter in the form array. + */ selectInboundItemFilter(filterValue: string, index: number): void { const filterArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray) filterArray.controls[index].patchValue({constraint: filterValue}) } + /** + * Selects an outbound item filter for a specific index in the form array. + * + * @param {string} filterValue - The selected item filter value. + * @param {number} index - The index of the outbound item filter in the form array. + */ selectOutboundItemFilter(filterValue: string, index: number) { const filterArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray) filterArray.controls[index].patchValue({constraint: filterValue}) } + /** + * Sends the user back to the LDN services list. + */ private sendBack() { this.router.navigateByUrl('admin/ldn/services'); } - - + /** + * Creates a form group for an outbound pattern in the notifyServiceOutboundPatterns form array. + * + * @private + * @returns {FormGroup} - The created form group. + */ private createOutboundPatternFormGroup(): FormGroup { return this.formBuilder.group({ pattern: [''], @@ -261,6 +348,12 @@ export class LdnServiceFormComponent implements OnInit { }); } + /** + * Creates a form group for an inbound pattern in the notifyServiceInboundPatterns form array. + * + * @private + * @returns {FormGroup} - The created form group. + */ private createInboundPatternFormGroup(): FormGroup { return this.formBuilder.group({ pattern: [''], diff --git a/src/app/admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service.ts b/src/app/admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service.ts index 7aa6231b4d..15a7bcccda 100644 --- a/src/app/admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service.ts +++ b/src/app/admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service.ts @@ -37,10 +37,24 @@ export class LdnItemfiltersService extends IdentifiableDataService i this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); } + /** + * Gets the endpoint URL for the itemfilters. + * + * @returns {string} - The endpoint URL. + */ getEndpoint() { return this.halService.getEndpoint(this.linkPath); } + /** + * Finds all itemfilters based on the provided options and link configurations. + * + * @param {FindListOptions} options - The options for finding a list of itemfilters. + * @param {boolean} useCachedVersionIfAvailable - Whether to use the cached version if available. + * @param {boolean} reRequestOnStale - Whether to re-request the data if it's stale. + * @param {...FollowLinkConfig[]} linksToFollow - Configurations for following specific links. + * @returns {Observable>>} - An observable of remote data containing a paginated list of itemfilters. + */ findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } diff --git a/src/app/admin/admin-ldn-services/ldn-services-directory/ldn-services-directory.component.spec.ts b/src/app/admin/admin-ldn-services/ldn-services-directory/ldn-services-directory.component.spec.ts index 8213e5bc53..c5ec66c757 100644 --- a/src/app/admin/admin-ldn-services/ldn-services-directory/ldn-services-directory.component.spec.ts +++ b/src/app/admin/admin-ldn-services/ldn-services-directory/ldn-services-directory.component.spec.ts @@ -12,137 +12,132 @@ import {LdnService} from "../ldn-services-model/ldn-services.model"; import {PaginatedList} from "../../../core/data/paginated-list.model"; import {RemoteData} from "../../../core/data/remote-data"; import {LdnServicesOverviewComponent} from './ldn-services-directory.component'; +import {createSuccessfulRemoteDataObject$} from "../../../shared/remote-data.utils"; +import {createPaginatedList} from "../../../shared/testing/utils.test"; -describe('LdnServicesOverviewComponent', () => { - let component: LdnServicesOverviewComponent; - let fixture: ComponentFixture; - let ldnServicesService: LdnServicesService; - let paginationService: PaginationService; - let modalService: NgbModal; - let notificationsService: NotificationsService; - let translateService: TranslateService; +describe('LdnServicesOverviewComponent', ( ) => { + let component: LdnServicesOverviewComponent; + let fixture: ComponentFixture; + let ldnServicesService; + let paginationService; + let modalService: NgbModal; + let notificationsService: NotificationsService; + let translateService: TranslateService; - const translateServiceStub = { - get: () => of('translated-text'), - onLangChange: new EventEmitter(), - onTranslationChange: new EventEmitter(), - onDefaultLangChange: new EventEmitter() - }; + const translateServiceStub = { + get: () => of('translated-text'), + onLangChange: new EventEmitter(), + onTranslationChange: new EventEmitter(), + onDefaultLangChange: new EventEmitter() + }; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - declarations: [LdnServicesOverviewComponent], - providers: [ - {provide: LdnServicesService, useValue: jasmine.createSpyObj('LdnServicesService', ['findAll', 'delete', 'patch'])}, - {provide: PaginationService, useValue: new PaginationServiceStub()}, - { - provide: NgbModal, useValue: { - open: () => { /*comment*/ - } - } - }, - {provide: ChangeDetectorRef, useValue: {}}, - {provide: NotificationsService, useValue: NotificationsServiceStub}, - {provide: TranslateService, useValue: translateServiceStub}, - ] - }).compileComponents(); + beforeEach(async () => { + paginationService = new PaginationServiceStub(); + ldnServicesService = jasmine.createSpyObj('LdnServicesService', ['findAll', 'delete', 'patch']) + await TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + declarations: [LdnServicesOverviewComponent], + providers: [ + { + provide: LdnServicesService, + useValue: ldnServicesService + }, + {provide: PaginationService, useValue: paginationService}, + { + provide: NgbModal, useValue: { + open: () => { /*comment*/} + } + }, + {provide: ChangeDetectorRef, useValue: {}}, + {provide: NotificationsService, useValue: NotificationsServiceStub}, + {provide: TranslateService, useValue: translateServiceStub}, + ] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LdnServicesOverviewComponent); + component = fixture.componentInstance; + ldnServicesService = TestBed.inject(LdnServicesService); + paginationService = TestBed.inject(PaginationService); + modalService = TestBed.inject(NgbModal); + notificationsService = TestBed.inject(NotificationsService); + translateService = TestBed.inject(TranslateService); + component.modalRef = jasmine.createSpyObj({close: null}); + component.isProcessingSub = jasmine.createSpyObj({unsubscribe: null}); + component.ldnServicesRD$ = of({} as RemoteData>); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should call setLdnServices', fakeAsync(() => { + spyOn(component, 'setLdnServices').and.callThrough(); + component.ngOnInit(); + tick(); + expect(component.setLdnServices).toHaveBeenCalled(); + })); + + it('should set ldnServicesRD$ with mock data', fakeAsync(() => { + spyOn(component, 'setLdnServices').and.callThrough(); + const testData: LdnService[] = Object.assign([new LdnService()], [ + {id: 1, name: 'Service 1', description: 'Description 1', enabled: true}, + {id: 2, name: 'Service 2', description: 'Description 2', enabled: false}, + {id: 3, name: 'Service 3', description: 'Description 3', enabled: true}]); + + const mockLdnServicesRD = createPaginatedList(testData) + component.ldnServicesRD$ = createSuccessfulRemoteDataObject$(mockLdnServicesRD); + fixture.detectChanges(); + + const tableRows = fixture.debugElement.nativeElement.querySelectorAll('tbody tr'); + expect(tableRows.length).toBe(testData.length); + const firstRowContent = tableRows[0].textContent; + expect(firstRowContent).toContain('Service 1'); + expect(firstRowContent).toContain('Description 1'); + })); + }); + + describe('ngOnDestroy', () => { + it('should call paginationService.clearPagination and unsubscribe', () => { + // spyOn(paginationService, 'clearPagination'); + // spyOn(component.isProcessingSub, 'unsubscribe'); + component.ngOnDestroy(); + expect(paginationService.clearPagination).toHaveBeenCalledWith(component.pageConfig.id); + expect(component.isProcessingSub.unsubscribe).toHaveBeenCalled(); }); + }); - beforeEach(() => { - fixture = TestBed.createComponent(LdnServicesOverviewComponent); - component = fixture.componentInstance; - ldnServicesService = TestBed.inject(LdnServicesService); - paginationService = TestBed.inject(PaginationService); - modalService = TestBed.inject(NgbModal); - notificationsService = TestBed.inject(NotificationsService); - translateService = TestBed.inject(TranslateService); - component.modalRef = jasmine.createSpyObj({close: null}); - component.isProcessingSub = jasmine.createSpyObj({unsubscribe: null}); - component.ldnServicesRD$ = of({} as RemoteData>); - fixture.detectChanges(); + describe('openDeleteModal', () => { + it('should open delete modal', () => { + spyOn(modalService, 'open'); + component.openDeleteModal(component.deleteModal); + expect(modalService.open).toHaveBeenCalledWith(component.deleteModal); }); + }); - it('should create', () => { - expect(component).toBeTruthy(); + describe('closeModal', () => { + it('should close modal and detect changes', () => { + // spyOn(component.modalRef, 'close'); + spyOn(component.cdRef, 'detectChanges'); + component.closeModal(); + expect(component.modalRef.close).toHaveBeenCalled(); + expect(component.cdRef.detectChanges).toHaveBeenCalled(); }); + }); - describe('ngOnInit', () => { - it('should call setLdnServices', fakeAsync(() => { - spyOn(component, 'setLdnServices').and.callThrough(); - component.ngOnInit(); - tick(); - expect(component.setLdnServices).toHaveBeenCalled(); - })); - - it('should set ldnServicesRD$ with mock data', fakeAsync(() => { - spyOn(component, 'setLdnServices').and.callThrough(); - const mockData = { - payload: { - page: [ - {id: 1, name: 'Service 1', description: 'Description 1', enabled: true}, - {id: 2, name: 'Service 2', description: 'Description 2', enabled: false}, - {id: 3, name: 'Service 3', description: 'Description 3', enabled: true}, - ], - totalElements: 3 - } - } as RemoteData>; - component.ldnServicesRD$ = of(mockData as RemoteData>); - component.ngOnInit(); - tick(); - expect(component.setLdnServices).toHaveBeenCalled(); - fixture.detectChanges(); - console.log(fixture.nativeElement.innerHTML); - console.log('Mock Data:', mockData); - const tableRows = fixture.nativeElement.querySelectorAll('tbody tr'); - console.log('Table Rows:', tableRows); - //TODO: check why the tbody tr length table rows is 0 when i sjhould be 3 accordingly to the mock - expect(tableRows.length).toBe(mockData.payload.page.length); - const firstRowContent = tableRows[0].textContent; - expect(firstRowContent).toContain('Service 1'); - expect(firstRowContent).toContain('Description 1'); - })); - }); - - describe('ngOnDestroy', () => { - it('should call paginationService.clearPagination and unsubscribe', () => { - spyOn(paginationService, 'clearPagination'); - spyOn(component.isProcessingSub, 'unsubscribe'); - component.ngOnDestroy(); - expect(paginationService.clearPagination).toHaveBeenCalledWith(component.pageConfig.id); - expect(component.isProcessingSub.unsubscribe).toHaveBeenCalled(); - }); - }); - - describe('openDeleteModal', () => { - it('should open delete modal', () => { - spyOn(modalService, 'open'); - component.openDeleteModal(component.deleteModal); - expect(modalService.open).toHaveBeenCalledWith(component.deleteModal); - }); - }); - - describe('closeModal', () => { - it('should close modal and detect changes', () => { - spyOn(component.modalRef, 'close'); - spyOn(component.cdRef, 'detectChanges'); - component.closeModal(); - expect(component.modalRef.close).toHaveBeenCalled(); - expect(component.cdRef.detectChanges).toHaveBeenCalled(); - }); - }); - - describe('deleteSelected', () => { - it('should delete selected service and update data', fakeAsync(() => { - const serviceId = '123'; - //TODO: finish up this test to use a mockdata containing something - const mockRemoteData = { /* insert mock data with service id 123 */}; - spyOn(component, 'setLdnServices').and.callThrough(); - const deleteSpy = spyOn(ldnServicesService, 'delete').and.returnValue(of(mockRemoteData as RemoteData>)); - component.selectedServiceId = serviceId; - component.deleteSelected(serviceId, ldnServicesService); - tick(); - expect(deleteSpy).toHaveBeenCalledWith(serviceId); - })); - }); + describe('deleteSelected', () => { + it('should delete selected service and update data', fakeAsync(() => { + const serviceId = '123'; + const mockRemoteData = { /* just an empty object to retrieve as as RemoteData> */}; + spyOn(component, 'setLdnServices').and.callThrough(); + const deleteSpy = ldnServicesService.delete.and.returnValue(of(mockRemoteData as RemoteData>)); + component.selectedServiceId = serviceId; + component.deleteSelected(serviceId, ldnServicesService); + tick(); + expect(deleteSpy).toHaveBeenCalledWith(serviceId); + })); + }); });