93219: Add (more) reusable functions to test DataService composition

Data services that implement *Data interfaces should include the appropriate test functions in their specs.
These go over all methods in the interface & check that they're "wired up" correctly.

See e.g. the change in ExternalSourceDataService for an issue that is easy to miss but was highlighted by these new tests
This commit is contained in:
Yury Bondarenko
2022-09-12 17:37:54 +02:00
parent 8b4dbbad55
commit 147c7180d0
34 changed files with 442 additions and 75 deletions

View File

@@ -11,7 +11,7 @@ import { ObjectCacheService } from '../../cache/object-cache.service';
import { HALEndpointService } from '../../shared/hal-endpoint.service';
import { FindListOptions } from '../find-list-options.model';
import { Observable, of as observableOf } from 'rxjs';
import { CreateDataImpl } from './create-data';
import { CreateData, CreateDataImpl } from './create-data';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { getMockRequestService } from '../../../shared/mocks/request.service.mock';
import { HALEndpointServiceStub } from '../../../shared/testing/hal-endpoint-service.stub';
@@ -21,6 +21,38 @@ import { RequestEntryState } from '../request-entry-state.model';
import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { RequestParam } from '../../cache/models/request-param.model';
import { RestRequestMethod } from '../rest-request-method';
import { DSpaceObject } from '../../shared/dspace-object.model';
/**
* Tests whether calls to `CreateData` methods are correctly patched through in a concrete data service that implements it
*/
export function testCreateDataImplementation(serviceFactory: () => CreateData<any>) {
let service;
describe('CreateData implementation', () => {
const OBJ = Object.assign(new DSpaceObject(), {
uuid: '08eec68f-45e4-47a3-80c5-f0beb5627079',
});
const PARAMS = [
new RequestParam('abc', 123), new RequestParam('def', 456),
];
beforeAll(() => {
service = serviceFactory();
(service as any).createData = jasmine.createSpyObj('createData', {
create: 'TEST create',
});
});
it('should handle calls to create', () => {
const out: any = service.create(OBJ, ...PARAMS);
expect((service as any).createData.create).toHaveBeenCalledWith(OBJ, ...PARAMS);
expect(out).toBe('TEST create');
});
});
}
const endpoint = 'https://rest.api/core';

View File

@@ -19,11 +19,48 @@ import { followLink } from '../../../shared/utils/follow-link-config.model';
import { TestScheduler } from 'rxjs/testing';
import { RemoteData } from '../remote-data';
import { RequestEntryState } from '../request-entry-state.model';
import { DeleteDataImpl } from './delete-data';
import { DeleteData, DeleteDataImpl } from './delete-data';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { fakeAsync, tick } from '@angular/core/testing';
/**
* Tests whether calls to `DeleteData` methods are correctly patched through in a concrete data service that implements it
*/
export function testDeleteDataImplementation(serviceFactory: () => DeleteData<any>) {
let service;
describe('DeleteData implementation', () => {
const ID = '2ce78f3a-791b-4d70-b5eb-753d587bbadd';
const HREF = 'https://rest.api/core/items/' + ID;
const COPY_VIRTUAL_METADATA = [
'a', 'b', 'c'
];
beforeAll(() => {
service = serviceFactory();
(service as any).deleteData = jasmine.createSpyObj('deleteData', {
delete: 'TEST delete',
deleteByHref: 'TEST deleteByHref',
});
});
it('should handle calls to delete', () => {
const out: any = service.delete(ID, COPY_VIRTUAL_METADATA);
expect((service as any).deleteData.delete).toHaveBeenCalledWith(ID, COPY_VIRTUAL_METADATA);
expect(out).toBe('TEST delete');
});
it('should handle calls to deleteByHref', () => {
const out: any = service.deleteByHref(HREF, COPY_VIRTUAL_METADATA);
expect((service as any).deleteData.deleteByHref).toHaveBeenCalledWith(HREF, COPY_VIRTUAL_METADATA);
expect(out).toBe('TEST deleteByHref');
});
});
}
const endpoint = 'https://rest.api/core';
const BOOLEAN = { f: false, t: true };

View File

@@ -6,7 +6,6 @@
* http://www.dspace.org/license/
*/
import { FindAllData, FindAllDataImpl } from './find-all-data';
import createSpyObj = jasmine.createSpyObj;
import { FindListOptions } from '../find-list-options.model';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { getMockRequestService } from '../../../shared/mocks/request.service.mock';
@@ -27,7 +26,9 @@ import { Observable, of as observableOf } from 'rxjs';
/**
* Tests whether calls to `FindAllData` methods are correctly patched through in a concrete data service that implements it
*/
export function testFindAllDataImplementation(service: FindAllData<any>, methods = ['findAll', 'getFindAllHref']) {
export function testFindAllDataImplementation(serviceFactory: () => FindAllData<any>) {
let service;
describe('FindAllData implementation', () => {
const OPTIONS = Object.assign(new FindListOptions(), { elementsPerPage: 10, currentPage: 3 });
const FOLLOWLINKS = [
@@ -35,30 +36,19 @@ export function testFindAllDataImplementation(service: FindAllData<any>, methods
followLink('something'),
];
beforeEach(() => {
(service as any).findAllData = createSpyObj('findAllData', {
beforeAll(() => {
service = serviceFactory();
(service as any).findAllData = jasmine.createSpyObj('findAllData', {
findAll: 'TEST findAll',
getFindAllHref: 'TEST getFindAllHref',
});
});
if ('findAll' in methods) {
it('should handle calls to findAll', () => {
const out: any = service.findAll(OPTIONS, false, true, ...FOLLOWLINKS);
expect((service as any).findAllData.findAll).toHaveBeenCalledWith(OPTIONS, false, true, ...FOLLOWLINKS);
expect(out).toBe('TEST findAll');
});
}
if ('getFindAllHref' in methods) {
it('should handle calls to getFindAllHref', () => {
const out: any = service.getFindAllHref(OPTIONS, 'linkPath', ...FOLLOWLINKS);
expect((service as any).findAllData.getFindAllHref).toHaveBeenCalledWith(OPTIONS, 'linkPath', ...FOLLOWLINKS);
expect(out).toBe('TEST getFindAllHref');
});
}
});
}

View File

@@ -19,7 +19,7 @@ import { followLink } from '../../../shared/utils/follow-link-config.model';
import { TestScheduler } from 'rxjs/testing';
import { RemoteData } from '../remote-data';
import { RequestEntryState } from '../request-entry-state.model';
import { PatchDataImpl } from './patch-data';
import { PatchData, PatchDataImpl } from './patch-data';
import { ChangeAnalyzer } from '../change-analyzer';
import { Item } from '../../shared/item.model';
import { compare, Operation } from 'fast-json-patch';
@@ -27,6 +27,61 @@ import { PatchRequest } from '../request.models';
import { DSpaceObject } from '../../shared/dspace-object.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { constructIdEndpointDefault } from './identifiable-data.service';
import { RestRequestMethod } from '../rest-request-method';
/**
* Tests whether calls to `PatchData` methods are correctly patched through in a concrete data service that implements it
*/
export function testPatchDataImplementation(serviceFactory: () => PatchData<any>) {
let service;
describe('PatchData implementation', () => {
const OBJ = Object.assign(new DSpaceObject(), {
uuid: '08eec68f-45e4-47a3-80c5-f0beb5627079',
});
const OPERATIONS = [
{ op: 'replace', path: '/0/value', value: 'test' },
{ op: 'add', path: '/2/value', value: 'test2' },
] as Operation[];
const METHOD = RestRequestMethod.POST;
beforeAll(() => {
service = serviceFactory();
(service as any).patchData = jasmine.createSpyObj('patchData', {
patch: 'TEST patch',
update: 'TEST update',
commitUpdates: undefined,
createPatchFromCache: 'TEST createPatchFromCache',
});
});
it('should handle calls to patch', () => {
const out: any = service.patch(OBJ, OPERATIONS);
expect((service as any).patchData.patch).toHaveBeenCalledWith(OBJ, OPERATIONS);
expect(out).toBe('TEST patch');
});
it('should handle calls to update', () => {
const out: any = service.update(OBJ);
expect((service as any).patchData.update).toHaveBeenCalledWith(OBJ);
expect(out).toBe('TEST update');
});
it('should handle calls to commitUpdates', () => {
service.commitUpdates(METHOD);
expect((service as any).patchData.commitUpdates).toHaveBeenCalledWith(METHOD);
});
it('should handle calls to createPatchFromCache', () => {
const out: any = service.createPatchFromCache(OBJ);
expect((service as any).patchData.createPatchFromCache).toHaveBeenCalledWith(OBJ);
expect(out).toBe('TEST createPatchFromCache');
});
});
}
const endpoint = 'https://rest.api/core';

View File

@@ -17,10 +17,38 @@ import { HALEndpointServiceStub } from '../../../shared/testing/hal-endpoint-ser
import { getMockRemoteDataBuildService } from '../../../shared/mocks/remote-data-build.service.mock';
import { RemoteData } from '../remote-data';
import { RequestEntryState } from '../request-entry-state.model';
import { PutDataImpl } from './put-data';
import { PutData, PutDataImpl } from './put-data';
import { RestRequestMethod } from '../rest-request-method';
import { DSpaceObject } from '../../shared/dspace-object.model';
/**
* Tests whether calls to `PutData` methods are correctly patched through in a concrete data service that implements it
*/
export function testPutDataImplementation(serviceFactory: () => PutData<any>) {
let service;
describe('PutData implementation', () => {
const OBJ = Object.assign(new DSpaceObject(), {
uuid: '08eec68f-45e4-47a3-80c5-f0beb5627079',
});
beforeAll(() => {
service = serviceFactory();
(service as any).putData = jasmine.createSpyObj('putData', {
put: 'TEST put',
});
});
it('should handle calls to put', () => {
const out: any = service.put(OBJ);
expect((service as any).putData.put).toHaveBeenCalledWith(OBJ);
expect(out).toBe('TEST put');
});
});
}
const endpoint = 'https://rest.api/core';
class TestService extends PutDataImpl<any> {

View File

@@ -11,12 +11,13 @@ import { followLink } from '../../../shared/utils/follow-link-config.model';
import { of as observableOf } from 'rxjs';
import { getMockRequestService } from '../../../shared/mocks/request.service.mock';
import { getMockRemoteDataBuildService } from '../../../shared/mocks/remote-data-build.service.mock';
import createSpyObj = jasmine.createSpyObj;
/**
* Tests whether calls to `SearchData` methods are correctly patched through in a concrete data service that implements it
*/
export function testSearchDataImplementation(service: SearchData<any>, methods = ['searchBy', 'getSearchByHref']) {
export function testSearchDataImplementation(serviceFactory: () => SearchData<any>) {
let service;
describe('SearchData implementation', () => {
const OPTIONS = Object.assign(new FindListOptions(), { elementsPerPage: 10, currentPage: 3 });
const FOLLOWLINKS = [
@@ -24,30 +25,19 @@ export function testSearchDataImplementation(service: SearchData<any>, methods =
followLink('something'),
];
beforeEach(() => {
(service as any).searchData = createSpyObj('searchData', {
beforeAll(() => {
service = serviceFactory();
(service as any).searchData = jasmine.createSpyObj('searchData', {
searchBy: 'TEST searchBy',
getSearchByHref: 'TEST getSearchByHref',
});
});
if ('searchBy' in methods) {
it('should handle calls to searchBy', () => {
const out: any = service.searchBy('searchMethod', OPTIONS, false, true, ...FOLLOWLINKS);
expect((service as any).searchData.searchBy).toHaveBeenCalledWith('searchMethod', OPTIONS, false, true, ...FOLLOWLINKS);
expect(out).toBe('TEST searchBy');
});
}
if ('getSearchByHref' in methods) {
it('should handle calls to getSearchByHref', () => {
const out: any = service.getSearchByHref('searchMethod', OPTIONS, ...FOLLOWLINKS);
expect((service as any).searchData.getSearchByHref).toHaveBeenCalledWith('searchMethod', OPTIONS, ...FOLLOWLINKS);
expect(out).toBe('TEST getSearchByHref');
});
}
});
}

View File

@@ -12,6 +12,9 @@ import { getMockRequestService } from '../../shared/mocks/request.service.mock';
import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service.stub';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { testSearchDataImplementation } from './base/search-data.spec';
import { testPatchDataImplementation } from './base/patch-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
describe('BitstreamDataService', () => {
let service: BitstreamDataService;
@@ -50,6 +53,13 @@ describe('BitstreamDataService', () => {
service = new BitstreamDataService(requestService, rdbService, objectCache, halService, null, bitstreamFormatService, null, null);
});
describe('composition', () => {
const initService = () => new BitstreamDataService(null, null, null, null, null, null, null, null);
testSearchDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('when updating the bitstream\'s format', () => {
beforeEach(() => {
service.updateFormat(bitstream, format);

View File

@@ -6,19 +6,16 @@ import { ObjectCacheService } from '../cache/object-cache.service';
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { HttpClient } from '@angular/common/http';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { BitstreamFormat } from '../shared/bitstream-format.model';
import { waitForAsync } from '@angular/core/testing';
import {
BitstreamFormatsRegistryDeselectAction,
BitstreamFormatsRegistryDeselectAllAction,
BitstreamFormatsRegistrySelectAction
} from '../../admin/admin-registries/bitstream-formats/bitstream-format.actions';
import { BitstreamFormatsRegistryDeselectAction, BitstreamFormatsRegistryDeselectAllAction, BitstreamFormatsRegistrySelectAction } from '../../admin/admin-registries/bitstream-formats/bitstream-format.actions';
import { TestScheduler } from 'rxjs/testing';
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { CoreState } from '../core-state.model';
import { RequestEntry } from './request-entry.model';
import { testFindAllDataImplementation } from './base/find-all-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
describe('BitstreamFormatDataService', () => {
let service: BitstreamFormatDataService;
@@ -70,6 +67,12 @@ describe('BitstreamFormatDataService', () => {
);
}
describe('composition', () => {
const initService = () => new BitstreamFormatDataService(null, null, null, null, null, null);
testFindAllDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('getBrowseEndpoint', () => {
beforeEach(waitForAsync(() => {
scheduler = getTestScheduler();

View File

@@ -13,6 +13,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.util
import { createPaginatedList } from '../../shared/testing/utils.test';
import { Bundle } from '../shared/bundle.model';
import { CoreState } from '../core-state.model';
import { testPatchDataImplementation } from './base/patch-data.spec';
class DummyChangeAnalyzer implements ChangeAnalyzer<Item> {
diff(object1: Item, object2: Item): Operation[] {
@@ -71,6 +72,12 @@ describe('BundleDataService', () => {
service = initTestService();
});
describe('composition', () => {
const initService = () => new BundleDataService(null, null, null, null, null);
testPatchDataImplementation(initService);
});
describe('findAllByItem', () => {
beforeEach(() => {
spyOn(service, 'findListByHref');

View File

@@ -13,16 +13,17 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
import { Collection } from '../shared/collection.model';
import { PageInfo } from '../shared/page-info.model';
import { buildPaginatedList } from './paginated-list.model';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing';
import { Observable } from 'rxjs';
import { RemoteData } from './remote-data';
import { hasNoValue } from '../../shared/empty.util';
import { testCreateDataImplementation } from './base/create-data.spec';
import { testFindAllDataImplementation } from './base/find-all-data.spec';
import { testSearchDataImplementation } from './base/search-data.spec';
import { testPatchDataImplementation } from './base/patch-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
const url = 'fake-url';
const collectionId = 'fake-collection-id';
@@ -75,6 +76,16 @@ describe('CollectionDataService', () => {
const paginatedList = buildPaginatedList(pageInfo, array);
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
describe('composition', () => {
const initService = () => new CollectionDataService(null, null, null, null, null, null, null, null, null);
testCreateDataImplementation(initService);
testFindAllDataImplementation(initService);
testSearchDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('when the requests are successful', () => {
beforeEach(() => {
createService();

View File

@@ -13,16 +13,16 @@ import { ComColDataService } from './comcol-data.service';
import { CommunityDataService } from './community-data.service';
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
import { RequestService } from './request.service';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$,
createFailedRemoteDataObject,
createSuccessfulRemoteDataObject
} from '../../shared/remote-data.utils';
import { createFailedRemoteDataObject, createFailedRemoteDataObject$, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { BitstreamDataService } from './bitstream-data.service';
import { CoreState } from '../core-state.model';
import { FindListOptions } from './find-list-options.model';
import { Bitstream } from '../shared/bitstream.model';
import { testCreateDataImplementation } from './base/create-data.spec';
import { testFindAllDataImplementation } from './base/find-all-data.spec';
import { testSearchDataImplementation } from './base/search-data.spec';
import { testPatchDataImplementation } from './base/patch-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
const LINK_NAME = 'test';
@@ -154,6 +154,15 @@ describe('ComColDataService', () => {
service = initTestService();
});
describe('composition', () => {
const initService = () => new TestService(null, null, null, null, null, null, null, null, null, null, null);
testCreateDataImplementation(initService);
testFindAllDataImplementation(initService);
testSearchDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('getBrowseEndpoint', () => {
it(`should call createAndSendGetRequest with the scope Community's self link`, () => {
testScheduler.run(({ cold, flush, expectObservable }) => {

View File

@@ -0,0 +1,19 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import { testFindAllDataImplementation } from './base/find-all-data.spec';
import { testSearchDataImplementation } from './base/search-data.spec';
import { EntityTypeDataService } from './entity-type-data.service';
describe('EntityTypeDataService', () => {
describe('composition', () => {
const initService = () => new EntityTypeDataService(null, null, null, null, null);
testFindAllDataImplementation(initService);
testSearchDataImplementation(initService);
});
});

View File

@@ -4,6 +4,7 @@ import { createPaginatedList } from '../../shared/testing/utils.test';
import { ExternalSourceEntry } from '../shared/external-source-entry.model';
import { of as observableOf } from 'rxjs';
import { GetRequest } from './request.models';
import { testSearchDataImplementation } from './base/search-data.spec';
describe('ExternalSourceService', () => {
let service: ExternalSourceDataService;
@@ -57,6 +58,11 @@ describe('ExternalSourceService', () => {
init();
});
describe('composition', () => {
const initService = () => new ExternalSourceDataService(null, null, null, null);
testSearchDataImplementation(initService);
});
describe('getExternalSourceEntries', () => {
let result;

View File

@@ -92,6 +92,6 @@ export class ExternalSourceDataService extends IdentifiableDataService<ExternalS
* Return an observable that emits response from the server
*/
public searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<ExternalSource>[]): Observable<RemoteData<PaginatedList<ExternalSource>>> {
return undefined;
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
}
}

View File

@@ -11,6 +11,7 @@ import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { Feature } from '../../shared/feature.model';
import { FindListOptions } from '../find-list-options.model';
import { testSearchDataImplementation } from '../base/search-data.spec';
describe('AuthorizationDataService', () => {
let service: AuthorizationDataService;
@@ -45,6 +46,11 @@ describe('AuthorizationDataService', () => {
spyOn(service, 'searchBy').and.returnValue(observableOf(undefined));
});
describe('composition', () => {
const initService = () => new AuthorizationDataService(null, null, null, null, null);
testSearchDataImplementation(initService);
});
it('should call setStaleByHrefSubstring method', () => {
service.invalidateAuthorizationsRequestCache();
expect((service as any).requestService.setStaleByHrefSubstring).toHaveBeenCalledWith((service as any).linkPath);

View File

@@ -10,13 +10,16 @@ import { ObjectCacheService } from '../cache/object-cache.service';
import { RestResponse } from '../cache/response.models';
import { ExternalSourceEntry } from '../shared/external-source-entry.model';
import { ItemDataService } from './item-data.service';
import { DeleteRequest, GetRequest, PostRequest } from './request.models';
import { DeleteRequest, PostRequest } from './request.models';
import { RequestService } from './request.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { CoreState } from '../core-state.model';
import { RequestEntry } from './request-entry.model';
import { FindListOptions } from './find-list-options.model';
import { HALEndpointServiceStub } from 'src/app/shared/testing/hal-endpoint-service.stub';
import { testCreateDataImplementation } from './base/create-data.spec';
import { testPatchDataImplementation } from './base/patch-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
describe('ItemDataService', () => {
let scheduler: TestScheduler;
@@ -87,6 +90,13 @@ describe('ItemDataService', () => {
);
}
describe('composition', () => {
const initService = () => new ItemDataService(null, null, null, null, null, null, null, null);
testCreateDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('getBrowseEndpoint', () => {
beforeEach(() => {
scheduler = getTestScheduler();

View File

@@ -14,6 +14,9 @@ import { Item } from '../shared/item.model';
import { RestRequest } from './rest-request.model';
import { CoreState } from '../core-state.model';
import { RequestEntry } from './request-entry.model';
import { testCreateDataImplementation } from './base/create-data.spec';
import { testPatchDataImplementation } from './base/patch-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
import createSpyObj = jasmine.createSpyObj;
describe('ItemTemplateDataService', () => {
@@ -92,6 +95,13 @@ describe('ItemTemplateDataService', () => {
initTestService();
});
describe('composition', () => {
const initService = () => new ItemTemplateDataService(null, null, null, null, null, null, null, null, null);
testCreateDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('findByCollectionID', () => {
it('should call findByCollectionID on the collection-based data service', () => {
spyOn(byCollection, 'findById');

View File

@@ -11,6 +11,10 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.util
import { RequestParam } from '../cache/models/request-param.model';
import { FindListOptions } from './find-list-options.model';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { testCreateDataImplementation } from './base/create-data.spec';
import { testSearchDataImplementation } from './base/search-data.spec';
import { testPutDataImplementation } from './base/put-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
describe('MetadataFieldDataService', () => {
let metadataFieldService: MetadataFieldDataService;
@@ -53,6 +57,14 @@ describe('MetadataFieldDataService', () => {
init();
});
describe('composition', () => {
const initService = () => new MetadataFieldDataService(null, null, null, null, null);
testCreateDataImplementation(initService);
testSearchDataImplementation(initService);
testPutDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('findBySchema', () => {
beforeEach(() => {
spyOn(metadataFieldService, 'searchBy');

View File

@@ -9,6 +9,8 @@ import { MetadataSchema } from '../metadata/metadata-schema.model';
import { CreateRequest, PutRequest } from './request.models';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { testFindAllDataImplementation } from './base/find-all-data.spec';
import { testDeleteDataImplementation } from './base/delete-data.spec';
describe('MetadataSchemaDataService', () => {
let metadataSchemaService: MetadataSchemaDataService;
@@ -44,6 +46,13 @@ describe('MetadataSchemaDataService', () => {
init();
});
describe('composition', () => {
const initService = () => new MetadataSchemaDataService(null, null, null, null, null);
testFindAllDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('createOrUpdateMetadataSchema', () => {
let schema: MetadataSchema;

View File

@@ -0,0 +1,17 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import { testFindAllDataImplementation } from '../base/find-all-data.spec';
import { ProcessDataService } from './process-data.service';
describe('ProcessDataService', () => {
describe('composition', () => {
const initService = () => new ProcessDataService(null, null, null, null, null);
testFindAllDataImplementation(initService);
});
});

View File

@@ -0,0 +1,17 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import { testFindAllDataImplementation } from '../base/find-all-data.spec';
import { ScriptDataService } from './script-data.service';
describe('ScriptDataService', () => {
describe('composition', () => {
const initService = () => new ScriptDataService(null, null, null, null);
testFindAllDataImplementation(initService);
});
});

View File

@@ -16,6 +16,7 @@ import { getMockRequestService } from '../../shared/mocks/request.service.mock';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { RequestEntry } from './request-entry.model';
import { FindListOptions } from './find-list-options.model';
import { testSearchDataImplementation } from './base/search-data.spec';
describe('RelationshipDataService', () => {
let service: RelationshipDataService;
@@ -144,6 +145,12 @@ describe('RelationshipDataService', () => {
service = initTestService();
});
describe('composition', () => {
const initService = () => new RelationshipDataService(null, null, null, null, null, null, null);
testSearchDataImplementation(initService);
});
describe('deleteRelationship', () => {
beforeEach(() => {
spyOn(service, 'findById').and.returnValue(createSuccessfulRemoteDataObject$(relationship1));

View File

@@ -9,6 +9,7 @@ import { TestScheduler } from 'rxjs/testing';
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { FindListOptions } from './find-list-options.model';
import { testFindAllDataImplementation } from './base/find-all-data.spec';
describe('SiteDataService', () => {
let scheduler: TestScheduler;
@@ -53,6 +54,12 @@ describe('SiteDataService', () => {
);
});
describe('composition', () => {
const initService = () => new SiteDataService(null, null, null, null);
testFindAllDataImplementation(initService);
});
describe('getBrowseEndpoint', () => {
it('should return the Static Page endpoint', () => {

View File

@@ -15,6 +15,7 @@ import { Version } from '../shared/version.model';
import { VersionHistory } from '../shared/version-history.model';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { RequestEntry } from './request-entry.model';
import { testPatchDataImplementation } from './base/patch-data.spec';
describe('VersionDataService test', () => {
let scheduler: TestScheduler;
@@ -87,6 +88,11 @@ describe('VersionDataService test', () => {
);
}
describe('composition', () => {
const initService = () => new VersionDataService(null, null, null, null, null);
testPatchDataImplementation(initService);
});
describe('', () => {
beforeEach(() => {

View File

@@ -49,7 +49,7 @@ const editGroupSelector = createSelector(groupRegistryStateSelector, (groupRegis
*/
@Injectable()
@dataService(GROUP)
export class GroupDataService extends IdentifiableDataService<Group> {
export class GroupDataService extends IdentifiableDataService<Group> implements CreateData<Group>, SearchData<Group>, PatchData<Group>, DeleteData<Group> {
protected browseEndpoint = '';
public ePersonsEndpoint = 'epersons';
public subgroupsEndpoint = 'subgroups';

View File

@@ -8,6 +8,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { Store } from '@ngrx/store';
import { Feedback } from './models/feedback.model';
import { CoreState } from '../core-state.model';
import { testCreateDataImplementation } from '../data/base/create-data.spec';
describe('FeedbackDataService', () => {
let service: FeedbackDataService;
@@ -65,6 +66,10 @@ describe('FeedbackDataService', () => {
service = initTestService();
});
describe('composition', () => {
const initService = () => new FeedbackDataService(null, null, null, null, null, null);
testCreateDataImplementation(initService);
});
describe('getFeedback', () => {
beforeEach(() => {

View File

@@ -11,11 +11,7 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
import { RequestService } from '../data/request.service';
import { PageInfo } from '../shared/page-info.model';
import { buildPaginatedList } from '../data/paginated-list.model';
import {
createNoContentRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { createNoContentRemoteDataObject$, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { RestResponse } from '../cache/response.models';
import { RequestEntry } from '../data/request-entry.model';
import { ResearcherProfileDataService } from './researcher-profile-data.service';
@@ -28,6 +24,10 @@ import { PostRequest } from '../data/request.models';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { ConfigurationProperty } from '../shared/configuration-property.model';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { testCreateDataImplementation } from '../data/base/create-data.spec';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
import { testPatchDataImplementation } from '../data/base/patch-data.spec';
import { testDeleteDataImplementation } from '../data/base/delete-data.spec';
describe('ResearcherProfileService', () => {
let scheduler: TestScheduler;
@@ -268,6 +268,14 @@ describe('ResearcherProfileService', () => {
spyOn((service as any).deleteData, 'delete').and.callThrough();
});
describe('composition', () => {
const initService = () => new ResearcherProfileDataService(null, null, null, null, null, null, null, null);
testCreateDataImplementation(initService);
testSearchDataImplementation(initService);
testPatchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('create', () => {
it('should proxy the call to createData.create with eperson UUID', () => {
scheduler.schedule(() => service.create());

View File

@@ -0,0 +1,17 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import { testSearchDataImplementation } from '../data/base/search-data.spec';
import { UsageReportDataService } from './usage-report-data.service';
describe('UsageReportDataService', () => {
describe('composition', () => {
const initService = () => new UsageReportDataService(null, null, null, null);
testSearchDataImplementation(initService);
});
});

View File

@@ -11,6 +11,13 @@ import { VocabularyEntryDetailsDataService } from './vocabulary-entry-details.da
import { testSearchDataImplementation } from '../../data/base/search-data.spec';
describe('VocabularyEntryDetailsDataService', () => {
testFindAllDataImplementation(new VocabularyEntryDetailsDataService(null, null, null, null));
testSearchDataImplementation(new VocabularyEntryDetailsDataService(null, null, null, null));
function initTestService() {
return new VocabularyEntryDetailsDataService(null, null, null, null);
}
describe('composition', () => {
const initService = () => new VocabularyEntryDetailsDataService(null, null, null, null);
testFindAllDataImplementation(initService);
testSearchDataImplementation(initService);
});
});

View File

@@ -8,7 +8,13 @@
import { VocabularyDataService } from './vocabulary.data.service';
import { testFindAllDataImplementation } from '../../data/base/find-all-data.spec';
describe('VocabularyDataService', () => {
testFindAllDataImplementation(new VocabularyDataService(null, null, null, null));
function initTestService() {
return new VocabularyDataService(null, null, null, null);
}
describe('composition', () => {
const initService = () => new VocabularyDataService(null, null, null, null);
testFindAllDataImplementation(initService);
});
});

View File

@@ -19,6 +19,8 @@ import { Item } from '../shared/item.model';
import { WorkspaceItem } from './models/workspaceitem.model';
import { RequestEntry } from '../data/request-entry.model';
import { CoreState } from '../core-state.model';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
import { testDeleteDataImplementation } from '../data/base/delete-data.spec';
describe('WorkspaceitemDataService test', () => {
let scheduler: TestScheduler;
@@ -90,6 +92,12 @@ describe('WorkspaceitemDataService test', () => {
);
}
describe('composition', () => {
const initService = () => new WorkspaceitemDataService(null, null, null, null, null);
testSearchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
describe('', () => {
beforeEach(() => {

View File

@@ -11,6 +11,7 @@ import { TestScheduler } from 'rxjs/testing';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { FindListOptions } from '../data/find-list-options.model';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
describe('ClaimedTaskDataService', () => {
let scheduler: TestScheduler;
@@ -48,6 +49,11 @@ describe('ClaimedTaskDataService', () => {
options.headers = headers;
});
describe('composition', () => {
const initService = () => new ClaimedTaskDataService(null, null, null, null);
testSearchDataImplementation(initService);
});
describe('submitTask', () => {
it('should call postToEndpoint method', () => {
const scopeId = '1234';

View File

@@ -11,6 +11,7 @@ import { RequestParam } from '../cache/models/request-param.model';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { FindListOptions } from '../data/find-list-options.model';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
describe('PoolTaskDataService', () => {
let scheduler: TestScheduler;
@@ -47,6 +48,11 @@ describe('PoolTaskDataService', () => {
options.headers = headers;
});
describe('composition', () => {
const initService = () => new PoolTaskDataService(null, null, null, null);
testSearchDataImplementation(initService);
});
describe('findByItem', () => {
it('should call searchTask method', () => {

View File

@@ -20,6 +20,7 @@ import { HttpOptions } from '../dspace-rest/dspace-rest.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
import { CoreState } from '../core-state.model';
import { FindListOptions } from '../data/find-list-options.model';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
const LINK_NAME = 'test';
@@ -84,6 +85,11 @@ describe('TasksService', () => {
});
describe('composition', () => {
const initService = () => new TestService(null, null, null, null);
testSearchDataImplementation(initService);
});
describe('postToEndpoint', () => {
it('should send a new TaskPostRequest', () => {