diff --git a/src/app/core/data/base/base-data.service.spec.ts b/src/app/core/data/base/base-data.service.spec.ts index bfd148e90a..c10f52d8a5 100644 --- a/src/app/core/data/base/base-data.service.spec.ts +++ b/src/app/core/data/base/base-data.service.spec.ts @@ -23,6 +23,8 @@ import { BaseDataService } from './base-data.service'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { ObjectCacheServiceStub } from '../../../shared/testing/object-cache-service.stub'; import { ObjectCacheEntry } from '../../cache/object-cache.reducer'; +import { HALLink } from '../../shared/hal-link.model'; +import { createPaginatedList } from '../../../shared/testing/utils.test'; const endpoint = 'https://rest.api/core'; @@ -52,7 +54,8 @@ describe('BaseDataService', () => { let selfLink; let linksToFollow; let testScheduler; - let remoteDataMocks; + let remoteDataMocks: { [responseType: string]: RemoteData }; + let remoteDataPageMocks: { [responseType: string]: RemoteData }; function initTestService(): TestService { requestService = getMockRequestService(); @@ -73,7 +76,25 @@ describe('BaseDataService', () => { const timeStamp = new Date().getTime(); const msToLive = 15 * 60 * 1000; - const payload = { foo: 'bar' }; + const payload = { + foo: 'bar', + _links: { + self: Object.assign(new HALLink(), { + href: 'self-test-link', + }), + followLink1: Object.assign(new HALLink(), { + href: 'follow-link-1', + }), + followLink2: [ + Object.assign(new HALLink(), { + href: 'follow-link-2-1', + }), + Object.assign(new HALLink(), { + href: 'follow-link-2-2', + }), + ], + } + }; const statusCodeSuccess = 200; const statusCodeError = 404; const errorMessage = 'not found'; @@ -85,6 +106,14 @@ describe('BaseDataService', () => { Error: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Error, errorMessage, undefined, statusCodeError), ErrorStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.ErrorStale, errorMessage, undefined, statusCodeError), }; + remoteDataPageMocks = { + RequestPending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.RequestPending, undefined, undefined, undefined), + ResponsePending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.ResponsePending, undefined, undefined, undefined), + Success: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Success, undefined, createPaginatedList([payload]), statusCodeSuccess), + SuccessStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.SuccessStale, undefined, createPaginatedList([payload]), statusCodeSuccess), + Error: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Error, errorMessage, undefined, statusCodeError), + ErrorStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.ErrorStale, errorMessage, undefined, statusCodeError), + }; return new TestService( requestService, @@ -360,6 +389,27 @@ describe('BaseDataService', () => { }); + it('should link all the followLinks of a cached object by calling addDependency', () => { + spyOn(objectCache, 'addDependency').and.callThrough(); + testScheduler.run(({ cold, expectObservable, flush }) => { + spyOn(rdbService, 'buildSingle').and.returnValue(cold('a-b-c-d', { + a: remoteDataMocks.Success, + b: remoteDataMocks.RequestPending, + c: remoteDataMocks.ResponsePending, + d: remoteDataMocks.Success, + })); + const expected = '--b-c-d'; + const values = { + b: remoteDataMocks.RequestPending, + c: remoteDataMocks.ResponsePending, + d: remoteDataMocks.Success, + }; + + expectObservable(service.findByHref(selfLink, false, false, ...linksToFollow)).toBe(expected, values); + flush(); + expect(objectCache.addDependency).toHaveBeenCalledTimes(4); + }); + }); }); describe(`findListByHref`, () => { @@ -372,8 +422,8 @@ describe('BaseDataService', () => { it(`should call buildHrefFromFindOptions with href and linksToFollow`, () => { testScheduler.run(({ cold }) => { spyOn(service, 'buildHrefFromFindOptions').and.returnValue(selfLink); - spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataMocks.Success })); - spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataMocks.Success })); + spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataPageMocks.Success })); + spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataPageMocks.Success })); service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow); expect(service.buildHrefFromFindOptions).toHaveBeenCalledWith(selfLink, findListOptions, [], ...linksToFollow); @@ -383,8 +433,8 @@ describe('BaseDataService', () => { it(`should call createAndSendGetRequest with the result from buildHrefFromFindOptions and useCachedVersionIfAvailable`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(service, 'buildHrefFromFindOptions').and.returnValue('bingo!'); - spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataMocks.Success })); - spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataMocks.Success })); + spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataPageMocks.Success })); + spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataPageMocks.Success })); service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow); expect((service as any).createAndSendGetRequest).toHaveBeenCalledWith(jasmine.anything(), true); @@ -399,8 +449,8 @@ describe('BaseDataService', () => { it(`should call rdbService.buildList with the result from buildHrefFromFindOptions and linksToFollow`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(service, 'buildHrefFromFindOptions').and.returnValue('bingo!'); - spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataMocks.Success })); - spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataMocks.Success })); + spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataPageMocks.Success })); + spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataPageMocks.Success })); service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow); expect(rdbService.buildList).toHaveBeenCalledWith(jasmine.anything() as any, ...linksToFollow); @@ -411,12 +461,12 @@ describe('BaseDataService', () => { it(`should call reRequestStaleRemoteData with reRequestOnStale and the exact same findListByHref call as a callback`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(service, 'buildHrefFromFindOptions').and.returnValue('bingo!'); - spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataMocks.SuccessStale })); - spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataMocks.SuccessStale })); + spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataPageMocks.SuccessStale })); + spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: remoteDataPageMocks.SuccessStale })); service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow); expect((service as any).reRequestStaleRemoteData.calls.argsFor(0)[0]).toBeTrue(); - spyOn(service, 'findListByHref').and.returnValue(cold('a', { a: remoteDataMocks.SuccessStale })); + spyOn(service, 'findListByHref').and.returnValue(cold('a', { a: remoteDataPageMocks.SuccessStale })); // prove that the spy we just added hasn't been called yet expect(service.findListByHref).not.toHaveBeenCalled(); // call the callback passed to reRequestStaleRemoteData @@ -431,7 +481,7 @@ describe('BaseDataService', () => { it(`should return a the output from reRequestStaleRemoteData`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(service, 'buildHrefFromFindOptions').and.returnValue(selfLink); - spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataMocks.Success })); + spyOn(rdbService, 'buildList').and.returnValue(cold('a', { a: remoteDataPageMocks.Success })); spyOn(service as any, 'reRequestStaleRemoteData').and.returnValue(() => cold('a', { a: 'bingo!' })); const expected = 'a'; const values = { @@ -451,19 +501,19 @@ describe('BaseDataService', () => { it(`should emit a cached completed RemoteData immediately, and keep emitting if it gets rerequested`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.Success, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + a: remoteDataPageMocks.Success, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, })); const expected = 'a-b-c-d-e'; const values = { - a: remoteDataMocks.Success, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + a: remoteDataPageMocks.Success, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, }; expectObservable(service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow)).toBe(expected, values); @@ -473,18 +523,18 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + a: remoteDataPageMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, })); const expected = '--b-c-d-e'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, }; expectObservable(service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow)).toBe(expected, values); @@ -503,18 +553,18 @@ describe('BaseDataService', () => { it(`should not emit a cached completed RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.Success, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + a: remoteDataPageMocks.Success, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, })); const expected = '--b-c-d-e'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, }; expectObservable(service.findListByHref(selfLink, findListOptions, false, true, ...linksToFollow)).toBe(expected, values); @@ -524,24 +574,45 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + a: remoteDataPageMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, })); const expected = '--b-c-d-e'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + e: remoteDataPageMocks.SuccessStale, }; expectObservable(service.findListByHref(selfLink, findListOptions, false, true, ...linksToFollow)).toBe(expected, values); }); }); + it('should link all the followLinks of the cached objects by calling addDependency', () => { + spyOn(objectCache, 'addDependency').and.callThrough(); + testScheduler.run(({ cold, expectObservable, flush }) => { + spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d', { + a: remoteDataPageMocks.SuccessStale, + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + })); + const expected = '--b-c-d'; + const values = { + b: remoteDataPageMocks.RequestPending, + c: remoteDataPageMocks.ResponsePending, + d: remoteDataPageMocks.Success, + }; + + expectObservable(service.findListByHref(selfLink, findListOptions, false, false, ...linksToFollow)).toBe(expected, values); + flush(); + expect(objectCache.addDependency).toHaveBeenCalledTimes(4); + }); + }); }); });