diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-dashboard.component.spec.ts b/src/app/admin/admin-notify-dashboard/admin-notify-dashboard.component.spec.ts index 51486024a9..74007055b4 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-dashboard.component.spec.ts +++ b/src/app/admin/admin-notify-dashboard/admin-notify-dashboard.component.spec.ts @@ -21,6 +21,11 @@ describe('AdminNotifyDashboardComponent', () => { let searchResult3; let results; + const mockBoxes = [ + { title: 'admin-notify-dashboard.received-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] }, + { title: 'admin-notify-dashboard.generated-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] } + ]; + beforeEach(async () => { item1 = Object.assign(new AdminNotifyMessage(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); item2 = Object.assign(new AdminNotifyMessage(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); @@ -42,7 +47,11 @@ describe('AdminNotifyDashboardComponent', () => { fixture.detectChanges(); }); - it('should create', () => { + it('should create', (done) => { + component.notifyMetricsRows$.subscribe(boxes => { + expect(boxes).toEqual(mockBoxes); + done(); + }); expect(component).toBeTruthy(); }); }); diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-detail-modal/admin-notify-detail-modal.component.spec.ts b/src/app/admin/admin-notify-dashboard/admin-notify-detail-modal/admin-notify-detail-modal.component.spec.ts index e4c701ea9d..0ddf449e5c 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-detail-modal/admin-notify-detail-modal.component.spec.ts +++ b/src/app/admin/admin-notify-dashboard/admin-notify-detail-modal/admin-notify-detail-modal.component.spec.ts @@ -7,12 +7,14 @@ import { TranslateModule } from '@ngx-translate/core'; describe('AdminNotifyDetailModalComponent', () => { let component: AdminNotifyDetailModalComponent; let fixture: ComponentFixture; + const modalStub = jasmine.createSpyObj('modalStub', ['close']); + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], declarations: [ AdminNotifyDetailModalComponent ], - providers: [NgbActiveModal] + providers: [{ provide: NgbActiveModal, useValue: modalStub }] }) .compileComponents(); @@ -24,4 +26,11 @@ describe('AdminNotifyDetailModalComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should close', () => { + spyOn(component.response, 'emit'); + component.closeModal(); + expect(modalStub.close).toHaveBeenCalled(); + expect(component.response.emit).toHaveBeenCalledWith(true); + }); }); diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-search-result/admin-notify-search-result.component.spec.ts b/src/app/admin/admin-notify-dashboard/admin-notify-search-result/admin-notify-search-result.component.spec.ts index 0c1eee81c3..0aa35dcb5e 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-search-result/admin-notify-search-result.component.spec.ts +++ b/src/app/admin/admin-notify-dashboard/admin-notify-search-result/admin-notify-search-result.component.spec.ts @@ -12,8 +12,76 @@ import { routeServiceStub } from '../../../shared/testing/route-service.stub'; import { ActivatedRoute } from '@angular/router'; import { RouterStub } from '../../../shared/testing/router.stub'; import { TranslateModule } from '@ngx-translate/core'; -import { EMPTY } from 'rxjs'; +import { of as observableOf, of } from 'rxjs'; +import { AdminNotifyMessage, QueueStatusMap } from '../models/admin-notify-message.model'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component'; +import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; + +export const mockAdminNotifyMessages = [ + { + 'type': 'message', + 'id': 'urn:uuid:5fb3af44-d4f8-4226-9475-2d09c2d8d9e0', + 'coarNotifyType': 'ReviewAction', + 'activityStreamType': 'TentativeReject', + 'inReplyTo': 'urn:uuid:f7289ad5-0955-4c86-834c-fb54a736778b', + 'object': null, + 'context': '24d50450-9ff0-485f-82d4-fba1be42f3f9', + 'queueAttempts': 1, + 'queueLastStartTime': '2023-11-24T14:44:00.064+00:00', + 'origin': 12, + 'target': null, + 'queueStatusLabel': 'notify-queue-status.processed', + 'queueTimeout': '2023-11-24T15:44:00.064+00:00', + 'queueStatus': 3, + '_links': { + 'self': { + 'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:5fb3af44-d4f8-4226-9475-2d09c2d8d9e0' + } + }, + 'thumbnail': 'test', + 'item': {}, + 'accessStatus': {}, + 'ldnService': 'NOTIFY inbox - Automatic service', + 'relatedItem': 'test coar 2 demo' + }, + { + 'type': 'message', + 'id': 'urn:uuid:544c8777-e826-4810-a625-3e394cc3660d', + 'coarNotifyType': 'IngestAction', + 'activityStreamType': 'Announce', + 'inReplyTo': 'urn:uuid:b2ad72d6-6ea9-464f-b385-29a78417f6b8', + 'object': null, + 'context': 'e657437a-0ee2-437d-916a-bba8c57bf40b', + 'queueAttempts': 1, + 'queueLastStartTime': null, + 'origin': 12, + 'target': null, + 'queueStatusLabel': 'notify-queue-status.unmapped_action', + 'queueTimeout': '2023-11-24T14:15:34.945+00:00', + 'queueStatus': 6, + '_links': { + 'self': { + 'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:544c8777-e826-4810-a625-3e394cc3660d' + } + }, + 'thumbnail': {}, + 'item': {}, + 'accessStatus': {}, + 'ldnService': 'NOTIFY inbox - Automatic service', + 'relatedItem': 'test coar demo' + } +] as unknown as AdminNotifyMessage[]; + +export const mockUnformattedAdminNotifyMessages = mockAdminNotifyMessages.map( + message => ({ + ...message, + coarNotifyType: 'coar:' + message.coarNotifyType, + queueStatusLabel: Object.keys(QueueStatusMap)[Object.values(QueueStatusMap).indexOf(message.queueStatusLabel as unknown as QueueStatusMap)] + }) +) as unknown as AdminNotifyMessage[]; describe('AdminNotifySearchResultComponent', () => { let component: AdminNotifySearchResultComponent; let fixture: ComponentFixture; @@ -22,6 +90,8 @@ describe('AdminNotifySearchResultComponent', () => { let halService: HALEndpointService; let rdbService: RemoteDataBuildService; let adminNotifyMessageService: AdminNotifyMessagesService; + let searchConfigService: SearchConfigurationService; + let modalService: NgbModal; const requestUUID = '34cfed7c-f597-49ef-9cbe-ea351f0023c2'; const testObject = { uuid: 'test-property', @@ -29,13 +99,13 @@ describe('AdminNotifySearchResultComponent', () => { values: ['value-1', 'value-2'] } as ConfigurationProperty; - beforeEach(async () => { halService = jasmine.createSpyObj('halService', { getEndpoint: cold('a', { a: '' }) }); adminNotifyMessageService = jasmine.createSpyObj('adminNotifyMessageService', { - getDetailedMessages: EMPTY + getDetailedMessages: of(mockAdminNotifyMessages), + reprocessMessage: of(mockAdminNotifyMessages), }); requestService = jasmine.createSpyObj('requestService', { generateRequestId: requestUUID, @@ -48,30 +118,66 @@ describe('AdminNotifySearchResultComponent', () => { } }) }); + + searchConfigService = jasmine.createSpyObj('searchConfigService', { + getCurrentConfiguration: of('NOTIFY.outgoing') + }); objectCache = {} as ObjectCacheService; await TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], - declarations: [ AdminNotifySearchResultComponent ], + declarations: [ AdminNotifySearchResultComponent, AdminNotifyDetailModalComponent ], providers: [ - {provide: AdminNotifyMessagesService, useValue: adminNotifyMessageService}, + { provide: AdminNotifyMessagesService, useValue: adminNotifyMessageService }, { provide: RouteService, useValue: routeServiceStub }, { provide: ActivatedRoute, useValue: new RouterStub() }, { provide: HALEndpointService, useValue: halService }, { provide: ObjectCacheService, useValue: objectCache }, { provide: RequestService, useValue: requestService }, { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: SEARCH_CONFIG_SERVICE, useValue: searchConfigService }, ] }) .compileComponents(); fixture = TestBed.createComponent(AdminNotifySearchResultComponent); component = fixture.componentInstance; + modalService = (component as any).modalService; + spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ response: observableOf(true) }) })); fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); + expect(component.isInbound).toBeFalsy(); + }); + + it('should open modal', () => { + component.openDetailModal(mockAdminNotifyMessages[0]); + expect(modalService.open).toHaveBeenCalledWith(AdminNotifyDetailModalComponent); + }); + + it('should map messages', (done) => { + component.messagesSubject$.subscribe((messages) => { + expect(messages).toEqual(mockAdminNotifyMessages); + done(); + }); + }); + + it('should reprocess message', (done) => { + component.reprocessMessage(mockAdminNotifyMessages[0]); + component.messagesSubject$.subscribe((messages) => { + expect(messages).toEqual(mockAdminNotifyMessages); + done(); + }); + }); + + it('should unsubscribe on destroy', () => { + (component as any).subs = [of(null).subscribe()]; + + spyOn((component as any).subs[0], 'unsubscribe'); + component.ngOnDestroy(); + expect((component as any).subs[0].unsubscribe).toHaveBeenCalled(); }); }); diff --git a/src/app/admin/admin-notify-dashboard/services/admin-notify-messages.service.spec.ts b/src/app/admin/admin-notify-dashboard/services/admin-notify-messages.service.spec.ts new file mode 100644 index 0000000000..1bda61be49 --- /dev/null +++ b/src/app/admin/admin-notify-dashboard/services/admin-notify-messages.service.spec.ts @@ -0,0 +1,125 @@ +import { TestScheduler } from 'rxjs/testing'; +import { cold, getTestScheduler } from 'jasmine-marbles'; +import { AdminNotifyMessagesService } from './admin-notify-messages.service'; +import { RequestService } from '../../../core/data/request.service'; +import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../core/cache/object-cache.service'; +import { HALEndpointService } from '../../../core/shared/hal-endpoint.service'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { LdnServicesService } from '../../admin-ldn-services/ldn-services-data/ldn-services-data.service'; +import { ItemDataService } from '../../../core/data/item-data.service'; +import { RequestEntry } from '../../../core/data/request-entry.model'; +import { RestResponse } from '../../../core/cache/response.models'; +import { BehaviorSubject, of } from 'rxjs'; +import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; +import { RemoteData } from '../../../core/data/remote-data'; +import { RequestEntryState } from '../../../core/data/request-entry-state.model'; +import { + mockAdminNotifyMessages, + mockUnformattedAdminNotifyMessages +} from '../admin-notify-search-result/admin-notify-search-result.component.spec'; +import { take } from 'rxjs/operators'; +import { deepClone } from 'fast-json-patch'; + +describe('AdminNotifyMessagesService test', () => { + let scheduler: TestScheduler; + let service: AdminNotifyMessagesService; + let requestService: RequestService; + let rdbService: RemoteDataBuildService; + let objectCache: ObjectCacheService; + let halService: HALEndpointService; + let notificationsService: NotificationsService; + let ldnServicesService: LdnServicesService; + let itemDataService: ItemDataService; + let responseCacheEntry: RequestEntry; + + const endpointURL = `https://rest.api/rest/api/messages`; + const requestUUID = '8b3c613a-5a4b-438b-9686-be1d5b4a1c5a'; + const remoteDataMocks = { + Success: new RemoteData(null, null, null, RequestEntryState.Success, null, null, 200), + }; + const testLdnServiceName = 'testLdnService'; + const testRelatedItemName = 'testRelatedItem'; + + function initTestService() { + return new AdminNotifyMessagesService( + requestService, + rdbService, + objectCache, + halService, + notificationsService, + ldnServicesService, + itemDataService + ); + } + + beforeEach(() => { + scheduler = getTestScheduler(); + + objectCache = {} as ObjectCacheService; + notificationsService = {} as NotificationsService; + responseCacheEntry = new RequestEntry(); + responseCacheEntry.request = { href: endpointURL } as any; + responseCacheEntry.response = new RestResponse(true, 200, 'Success'); + + + requestService = jasmine.createSpyObj('requestService', { + generateRequestId: requestUUID, + send: true, + removeByHrefSubstring: {}, + getByHref: of(responseCacheEntry), + getByUUID: of(responseCacheEntry), + }); + + halService = jasmine.createSpyObj('halService', { + getEndpoint: of(endpointURL) + }); + + rdbService = jasmine.createSpyObj('rdbService', { + buildSingle: createSuccessfulRemoteDataObject$({}, 500), + buildList: cold('a', { a: remoteDataMocks.Success }), + buildFromRequestUUID: createSuccessfulRemoteDataObject$(deepClone(mockUnformattedAdminNotifyMessages)) + }); + + ldnServicesService = jasmine.createSpyObj('ldnServicesService', { + findById: createSuccessfulRemoteDataObject$({name: testLdnServiceName}), + }); + + itemDataService = jasmine.createSpyObj('itemDataService', { + findById: createSuccessfulRemoteDataObject$({name: testRelatedItemName}), + }); + + + service = initTestService(); + + }); + + describe('Admin Notify service', () => { + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + it('should format message labels', () => { + const formattedMessage = service.formatMessageLabels(deepClone(mockUnformattedAdminNotifyMessages[0])); + expect(formattedMessage).toEqual(mockAdminNotifyMessages[0]); + }); + + it('should get details for messages', (done) => { + service.getDetailedMessages(deepClone(mockUnformattedAdminNotifyMessages)).pipe(take(1)).subscribe((detailedMessages) => { + expect(detailedMessages[0].ldnService).toEqual(testLdnServiceName); + expect(detailedMessages[0].relatedItem).toEqual(testRelatedItemName); + done(); + }); + }); + + it('should reprocess message', (done) => { + const messages = deepClone(mockUnformattedAdminNotifyMessages); + const behaviorSubject = new BehaviorSubject(messages); + service.reprocessMessage(messages[0], behaviorSubject).pipe(take(1)).subscribe((reprocessedMessages) => { + expect(reprocessedMessages.length).toEqual(2); + expect(reprocessedMessages).toEqual(messages); + done(); + }); + }); + }); +});