From 835ce735cbdf44a83ff7f760f650275afbf6633a Mon Sep 17 00:00:00 2001 From: lotte <lotte_hofstede@hotmail.com> Date: Mon, 25 Nov 2019 18:04:05 +0100 Subject: [PATCH] added some tests --- .../data/relationship-type.service.spec.ts | 83 +++++++ .../relationship.effects.spec.ts | 234 ++++++++++++++++++ .../relationship.effects.ts | 4 +- 3 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 src/app/core/data/relationship-type.service.spec.ts create mode 100644 src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts diff --git a/src/app/core/data/relationship-type.service.spec.ts b/src/app/core/data/relationship-type.service.spec.ts new file mode 100644 index 0000000000..8a4d31bd6c --- /dev/null +++ b/src/app/core/data/relationship-type.service.spec.ts @@ -0,0 +1,83 @@ +import { RequestService } from './request.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service'; +import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { PaginatedList } from './paginated-list'; +import { PageInfo } from '../shared/page-info.model'; +import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; +import { RelationshipTypeService } from './relationship-type.service'; +import { of as observableOf } from 'rxjs'; +import { ItemType } from '../shared/item-relationships/item-type.model'; + +fdescribe('RelationshipTypeService', () => { + let service: RelationshipTypeService; + let requestService: RequestService; + + const restEndpointURL = 'https://rest.api/relationshiptypes'; + const halService: any = new HALEndpointServiceStub(restEndpointURL); + const publicationTypeString = 'Publication'; + const personTypeString = 'Person'; + const orgUnitTypeString = 'OrgUnit'; + const publicationType = Object.assign(new ItemType(), {label: publicationTypeString}); + const personType = Object.assign(new ItemType(), {label: personTypeString}); + const orgUnitType = Object.assign(new ItemType(), {label: orgUnitTypeString}); + + const relationshipType1 = Object.assign(new RelationshipType(), { + id: '1', + uuid: '1', + leftwardType: 'isAuthorOfPublication', + rightwardType: 'isPublicationOfAuthor', + leftType: createSuccessfulRemoteDataObject$(publicationType), + rightType: createSuccessfulRemoteDataObject$(personType) + }); + + + const relationshipType2 = Object.assign(new RelationshipType(), { + id: '2', + uuid: '2', + leftwardType: 'isOrgUnitOfPublication', + rightwardType: 'isPublicationOfOrgUnit', + leftType: createSuccessfulRemoteDataObject$(publicationType), + rightType: createSuccessfulRemoteDataObject$(orgUnitType) + }); + + const buildList = createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [relationshipType1, relationshipType2])); + const rdbService = getMockRemoteDataBuildService(undefined, observableOf(buildList)); + + function initTestService() { + return new RelationshipTypeService( + requestService, + halService, + rdbService + ); + } + + beforeEach(() => { + requestService = getMockRequestService(); + service = initTestService(); + }); + + describe('getAllRelationshipTypes', () => { + + it('should return all relationshipTypes', (done) => { + const expected = service.getAllRelationshipTypes({}); + expected.subscribe((e) => { + expect(e).toBe(buildList); + done(); + }) + }); + }); + + describe('getRelationshipTypeByLabelAndTypes', () => { + + it('should return the type filtered by label and type strings', (done) => { + const expected = service.getRelationshipTypeByLabelAndTypes(relationshipType1.leftwardType, publicationTypeString, personTypeString); + expected.subscribe((e) => { + expect(e).toBe(relationshipType1); + done(); + }) + }); + }); + +}); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts new file mode 100644 index 0000000000..bb5e61d32d --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts @@ -0,0 +1,234 @@ +import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; +import { RelationshipEffects } from './relationship.effects'; +import { async, TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { AddRelationshipAction, RelationshipActionTypes, RemoveRelationshipAction } from './relationship.actions'; +import { Item } from '../../../../../core/shared/item.model'; +import { MetadataValue } from '../../../../../core/shared/metadata.models'; +import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; +import { createSuccessfulRemoteDataObject$, spyOnOperator } from '../../../../testing/utils'; +import { RelationshipType } from '../../../../../core/shared/item-relationships/relationship-type.model'; +import { cold, hot } from 'jasmine-marbles'; +import * as operators from 'rxjs/operators'; +import { last } from 'rxjs/operators'; +import { ItemType } from '../../../../../core/shared/item-relationships/item-type.model'; + +describe('RelationshipEffects', () => { + let relationEffects: RelationshipEffects; + let actions: Observable<any>; + + const testUUID1 = '20e24c2f-a00a-467c-bdee-c929e79bf08d'; + const testUUID2 = '7f66a4d0-8557-4e77-8b1e-19930895f10a'; + const leftTypeString = 'Publication'; + const rightTypeString = 'Person'; + const leftType = Object.assign(new ItemType(), {label: leftTypeString}); + const rightType = Object.assign(new ItemType(), {label: rightTypeString}); + const leftTypeMD = Object.assign(new MetadataValue(), { value: leftTypeString }); + const rightTypeMD = Object.assign(new MetadataValue(), { value: rightTypeString }); + const relationshipID = '1234'; + let identifier; + + let leftItem = Object.assign(new Item(), { + uuid: testUUID1, + metadata: { 'relationship.type': [leftTypeMD] } + }); + + let rightItem = Object.assign(new Item(), { + uuid: testUUID2, + metadata: { 'relationship.type': [rightTypeMD] } + }); + + let relationshipType: RelationshipType = Object.assign(new RelationshipType(), { + leftwardType: 'isAuthorOfPublication', + rightwardType: 'isPublicationOfAuthor', + leftType: createSuccessfulRemoteDataObject$(leftType), + rightType: createSuccessfulRemoteDataObject$(rightType) + }); + + let relationship = Object.assign(new Relationship(), + { + uuid: relationshipID, + leftItem: createSuccessfulRemoteDataObject$(leftItem), + rightItem: createSuccessfulRemoteDataObject$(rightItem), + relationshipType: createSuccessfulRemoteDataObject$(relationshipType) + }); + const mockRelationshipService = { + getRelationshipByItemsAndLabel: + () => observableOf(relationship), + deleteRelationship: () => { + /* Do nothing */ + }, + addRelationship: () => { + /* Do nothing */ + } + }; + const mockRelationshipTypeService = { + getRelationshipTypeByLabelAndTypes: + () => observableOf(relationshipType) + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + providers: [ + RelationshipEffects, + provideMockActions(() => actions), + { provide: RelationshipTypeService, useValue: mockRelationshipTypeService }, + { provide: RelationshipService, useValue: mockRelationshipService } + ], + }); + })); + + beforeEach(() => { + relationEffects = TestBed.get(RelationshipEffects); + identifier = (relationEffects as any).createIdentifier(leftItem, rightItem, relationshipType.leftwardType); + }); + + describe('mapLastActions$', () => { + describe('When an ADD_RELATIONSHIP action is triggered', () => { + describe('When it\'s the first time for this identifier', () => { + let action; + it('should set the current value debounceMap and the value of the initialActionMap to ADD_RELATIONSHIP', () => { + action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + + expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type); + expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type); + }); + }); + + describe('When it\'s not the first time for this identifier', () => { + let action; + let testActionType = "TEST_TYPE"; + beforeEach(() => { + (relationEffects as any).initialActionMap[identifier] = testActionType; + (relationEffects as any).debounceMap[identifier] = new BehaviorSubject<string>(testActionType); + }); + + it('should set the current value debounceMap to ADD_RELATIONSHIP but not change the value of the initialActionMap', () => { + action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + + expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType); + expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type); + }); + }); + + describe('When the initialActionMap contains an ADD_RELATIONSHIP action', () => { + let action; + describe('When the last value in the debounceMap is also an ADD_RELATIONSHIP action', () => { + beforeEach(() => { + (relationEffects as any).initialActionMap[identifier] = RelationshipActionTypes.ADD_RELATIONSHIP; + spyOnOperator(operators, 'debounceTime').and.returnValue((v) => v); + spyOn((relationEffects as any), 'addRelationship'); + }); + it('should call addRelationship on the effect', () => { + action = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + expect((relationEffects as any).addRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType, undefined) + }); + }); + + describe('When the last value in the debounceMap is instead a REMOVE_RELATIONSHIP action', () => { + beforeEach(() => { + /** + * Change debounceTime to last so there's no need to fire a certain amount of actions in the debounce time frame + */ + spyOnOperator(operators, 'debounceTime').and.returnValue((v) => v.pipe(last())); + spyOn((relationEffects as any), 'addRelationship'); + spyOn((relationEffects as any), 'removeRelationship'); + }); + it('should <b>not</b> call removeRelationship or addRelationship on the effect', () => { + const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--ab-', { a: actiona, b: actionb }); + const expected = cold('--bb-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + expect((relationEffects as any).addRelationship).not.toHaveBeenCalled(); + expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled(); + }); + }); + }); + }); + + describe('When an REMOVE_RELATIONSHIP action is triggered', () => { + describe('When it\'s the first time for this identifier', () => { + let action; + it('should set the current value debounceMap and the value of the initialActionMap to REMOVE_RELATIONSHIP', () => { + action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + + expect((relationEffects as any).initialActionMap[identifier]).toBe(action.type); + expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type); + }); + }); + + describe('When it\'s not the first time for this identifier', () => { + let action; + let testActionType = "TEST_TYPE"; + beforeEach(() => { + (relationEffects as any).initialActionMap[identifier] = testActionType; + (relationEffects as any).debounceMap[identifier] = new BehaviorSubject<string>(testActionType); + }); + + it('should set the current value debounceMap to REMOVE_RELATIONSHIP but not change the value of the initialActionMap', () => { + action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + + expect((relationEffects as any).initialActionMap[identifier]).toBe(testActionType); + expect((relationEffects as any).debounceMap[identifier].value).toBe(action.type); + }); + }); + + describe('When the initialActionMap contains an REMOVE_RELATIONSHIP action', () => { + let action; + describe('When the last value in the debounceMap is also an REMOVE_RELATIONSHIP action', () => { + beforeEach(() => { + (relationEffects as any).initialActionMap[identifier] = RelationshipActionTypes.REMOVE_RELATIONSHIP; + spyOnOperator(operators, 'debounceTime').and.returnValue((v) => v); + spyOn((relationEffects as any), 'removeRelationship'); + }); + + it('should call removeRelationship on the effect', () => { + action = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--a-', { a: action }); + const expected = cold('--b-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + expect((relationEffects as any).removeRelationship).toHaveBeenCalledWith(leftItem, rightItem, relationshipType.leftwardType) + }); + }); + + describe('When the last value in the debounceMap is instead a ADD_RELATIONSHIP action', () => { + beforeEach(() => { + /** + * Change debounceTime to last so there's no need to fire a certain amount of actions in the debounce time frame + */ + spyOnOperator(operators, 'debounceTime').and.returnValue((v) => v.pipe(last())); + spyOn((relationEffects as any), 'addRelationship'); + spyOn((relationEffects as any), 'removeRelationship'); + }); + it('should <b>not</b> call addRelationship or removeRelationship on the effect', () => { + const actionb = new RemoveRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + const actiona = new AddRelationshipAction(leftItem, rightItem, relationshipType.leftwardType); + actions = hot('--ab-', { a: actiona, b: actionb }); + const expected = cold('--bb-', { b: undefined }); + expect(relationEffects.mapLastActions$).toBeObservable(expected); + expect((relationEffects as any).addRelationship).not.toHaveBeenCalled(); + expect((relationEffects as any).removeRelationship).not.toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts index c0e2c9c1a6..174945dd06 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts @@ -9,7 +9,6 @@ import { hasNoValue, hasValue, hasValueOperator } from '../../../../empty.util'; import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; import { RelationshipType } from '../../../../../core/shared/item-relationships/relationship-type.model'; import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service'; -import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../../core/shared/operators'; const DEBOUNCE_TIME = 5000; @@ -36,7 +35,7 @@ export class RelationshipEffects { /** - * Effect that makes sure all last fired ObjectUpdatesActions are stored in the map of this service, with the url as their key + * Effect that makes sure all last fired RelationshipActions' types are stored in the map of this service, with the object uuid as their key */ @Effect({ dispatch: false }) mapLastActions$ = this.actions$ .pipe( @@ -52,6 +51,7 @@ export class RelationshipEffects { take(1) ).subscribe( (type) => { + debugger; if (this.initialActionMap[identifier] === type) { if (type === RelationshipActionTypes.ADD_RELATIONSHIP) { let nameVariant = (action as AddRelationshipAction).payload.nameVariant; -- GitLab