Skip to content
Snippets Groups Projects
data.service.spec.ts 7.16 KiB
Newer Older
import { DataService } from './data.service';
import { NormalizedObject } from '../cache/models/normalized-object.model';
import { RequestService } from './request.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { CoreState } from '../core.reducers';
import { Store } from '@ngrx/store';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { Observable, of as observableOf } from 'rxjs';
import { FindAllOptions } from './request.models';
import { SortDirection, SortOptions } from '../cache/models/sort-options.model';
lotte's avatar
lotte committed
import { ObjectCacheService } from '../cache/object-cache.service';
Giuseppe Digilio's avatar
Giuseppe Digilio committed
import { compare, Operation } from 'fast-json-patch';
lotte's avatar
lotte committed
import { DSpaceObject } from '../shared/dspace-object.model';
import { ChangeAnalyzer } from './change-analyzer';
lotte's avatar
lotte committed
import { HttpClient } from '@angular/common/http';
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
lotte's avatar
lotte committed
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { Item } from '../shared/item.model';
lotte's avatar
lotte committed
import * as uuidv4 from 'uuid/v4';
lotte's avatar
lotte committed
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
lotte's avatar
lotte committed
const endpoint = 'https://rest.api/core';

// tslint:disable:max-classes-per-file
class NormalizedTestObject extends NormalizedObject<Item> {
class TestService extends DataService<any> {
lotte's avatar
lotte committed
  constructor(
    protected requestService: RequestService,
    protected rdbService: RemoteDataBuildService,
    protected dataBuildService: NormalizedObjectBuildService,
lotte's avatar
lotte committed
    protected store: Store<CoreState>,
    protected linkPath: string,
lotte's avatar
lotte committed
    protected halService: HALEndpointService,
lotte's avatar
lotte committed
    protected objectCache: ObjectCacheService,
    protected notificationsService: NotificationsService,
    protected http: HttpClient,
    protected comparator: ChangeAnalyzer<NormalizedTestObject>
lotte's avatar
lotte committed
  ) {
    super();
  }

lotte's avatar
lotte committed
  public getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable<string> {
lotte's avatar
lotte committed
    return observableOf(endpoint);
  }
class DummyChangeAnalyzer implements ChangeAnalyzer<NormalizedTestObject> {
  diff(object1: NormalizedTestObject, object2: NormalizedTestObject): Operation[] {
    return compare((object1 as any).metadata, (object2 as any).metadata);
  }

}
lotte's avatar
lotte committed

describe('DataService', () => {
lotte's avatar
lotte committed
  let service: TestService;
  let options: FindAllOptions;
lotte's avatar
lotte committed
  const requestService = {generateRequestId: () => uuidv4()} as RequestService;
lotte's avatar
lotte committed
  const halService = {} as HALEndpointService;
  const rdbService = {} as RemoteDataBuildService;
lotte's avatar
lotte committed
  const notificationsService = {} as NotificationsService;
  const http = {} as HttpClient;
  const comparator = new DummyChangeAnalyzer() as any;
  const dataBuildService = {
    normalize: (object) => object
  } as NormalizedObjectBuildService;
lotte's avatar
lotte committed
  const objectCache = {
    addPatch: () => {
      /* empty */
    },
    getObjectBySelfLink: () => {
lotte's avatar
lotte committed
      /* empty */
    }
  } as any;
lotte's avatar
lotte committed
  const store = {} as Store<CoreState>;

  function initTestService(): TestService {
    return new TestService(
      requestService,
      rdbService,
lotte's avatar
lotte committed
      dataBuildService,
lotte's avatar
lotte committed
      store,
      endpoint,
lotte's avatar
lotte committed
      halService,
lotte's avatar
lotte committed
      objectCache,
      notificationsService,
      http,
      comparator,
lotte's avatar
lotte committed
    );
  }
lotte's avatar
lotte committed

lotte's avatar
lotte committed
  service = initTestService();

  describe('getFindAllHref', () => {

    it('should return an observable with the endpoint', () => {
      options = {};

      (service as any).getFindAllHref(options).subscribe((value) => {
          expect(value).toBe(endpoint);
        }
      );
lotte's avatar
lotte committed
    it('should include page in href if currentPage provided in options', () => {
      options = { currentPage: 2 };
      const expected = `${endpoint}?page=${options.currentPage - 1}`;

      (service as any).getFindAllHref(options).subscribe((value) => {
        expect(value).toBe(expected);
      });
    });

    it('should include size in href if elementsPerPage provided in options', () => {
      options = { elementsPerPage: 5 };
      const expected = `${endpoint}?size=${options.elementsPerPage}`;

      (service as any).getFindAllHref(options).subscribe((value) => {
        expect(value).toBe(expected);
      });
    });

    it('should include sort href if SortOptions provided in options', () => {
      const sortOptions = new SortOptions('field1', SortDirection.ASC);
      options = { sort: sortOptions };
      const expected = `${endpoint}?sort=${sortOptions.field},${sortOptions.direction}`;

      (service as any).getFindAllHref(options).subscribe((value) => {
        expect(value).toBe(expected);
      });
    });

    it('should include startsWith in href if startsWith provided in options', () => {
      options = { startsWith: 'ab' };
      const expected = `${endpoint}?startsWith=${options.startsWith}`;

      (service as any).getFindAllHref(options).subscribe((value) => {
        expect(value).toBe(expected);
      });
    });

    it('should include all provided options in href', () => {
      const sortOptions = new SortOptions('field1', SortDirection.DESC)
      options = {
        currentPage: 6,
        elementsPerPage: 10,
        sort: sortOptions,
        startsWith: 'ab'
lotte's avatar
lotte committed
      const expected = `${endpoint}?page=${options.currentPage - 1}&size=${options.elementsPerPage}` +
        `&sort=${sortOptions.field},${sortOptions.direction}&startsWith=${options.startsWith}`;

      (service as any).getFindAllHref(options).subscribe((value) => {
        expect(value).toBe(expected);
      });
    })
  });
lotte's avatar
lotte committed
  describe('patch', () => {
    let operations;
    let selfLink;

    beforeEach(() => {
lotte's avatar
lotte committed
      operations = [{ op: 'replace', path: '/metadata/dc.title', value: 'random string' } as Operation];
lotte's avatar
lotte committed
      selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';
      spyOn(objectCache, 'addPatch');
    });

    it('should call addPatch on the object cache with the right parameters', () => {
      service.patch(selfLink, operations);
      expect(objectCache.addPatch).toHaveBeenCalledWith(selfLink, operations);
    });
  });

  describe('update', () => {
    let operations;
    let selfLink;
    let dso;
    let dso2;
    const name1 = 'random string';
    const name2 = 'another random string';
    beforeEach(() => {
      operations = [{ op: 'replace', path: '/0/value', value: name2 } as Operation];
lotte's avatar
lotte committed
      selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';

      dso = new DSpaceObject();
      dso.self = selfLink;
lotte's avatar
lotte committed
      dso.metadata = [{ key: 'dc.title', value: name1 }];
lotte's avatar
lotte committed

      dso2 = new DSpaceObject();
      dso2.self = selfLink;
lotte's avatar
lotte committed
      dso2.metadata = [{ key: 'dc.title', value: name2 }];
lotte's avatar
lotte committed

lotte's avatar
lotte committed
      spyOn(service, 'findByHref').and.returnValues(createSuccessfulRemoteDataObject$(dso));
lotte's avatar
lotte committed
      spyOn(objectCache, 'addPatch');
    });
lotte's avatar
lotte committed

lotte's avatar
lotte committed
    it('should call addPatch on the object cache with the right parameters when there are differences', () => {
      service.update(dso2).subscribe();
lotte's avatar
lotte committed
      expect(objectCache.addPatch).toHaveBeenCalledWith(selfLink, operations);
    });
lotte's avatar
lotte committed
    it('should not call addPatch on the object cache with the right parameters when there are no differences', () => {
      service.update(dso).subscribe();
lotte's avatar
lotte committed
      expect(objectCache.addPatch).not.toHaveBeenCalled();
    });
  });