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