From 289d0c626196fa856ed7ad2034f87390447a5d6d Mon Sep 17 00:00:00 2001 From: OZGCloud <ozgcloud@mgm-tp.com> Date: Wed, 15 May 2024 15:23:11 +0200 Subject: [PATCH] OZG-5012 fix imports; split save/delete --- .../src/lib/bescheid.service.ts | 3 +- .../src/lib/+state/command.reducer.spec.ts | 10 +- .../src/lib/+state/command.selectors.ts | 2 +- .../src/lib/command-resource.service.spec.ts | 2 +- .../src/lib/command-resource.service.ts | 4 + .../lib/assistive-technologies.util.spec.ts | 2 +- .../catch-http-error.decorator.spec.ts | 2 +- .../skip-error-interceptor.decorator.ts | 2 +- .../lib/interceptor/http-xsrf.interceptor.ts | 4 +- .../lib/resource/api-resource.service.spec.ts | 107 +++++++++++++++++- .../src/lib/resource/api-resource.service.ts | 14 +++ .../src/lib/resource/resource.model.ts | 6 +- .../src/lib/resource/resource.util.spec.ts | 18 +-- 13 files changed, 143 insertions(+), 33 deletions(-) diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index 1f32f6c10e..9fcd500a1b 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -123,14 +123,13 @@ export class BescheidService { return { resource: this.vorgangService.getVorgangWithEingang(), getLinkRel: VorgangWithEingangLinkRel.BESCHEID_DRAFT, - editLinkRel: null, + delete: { linkRel: BescheidLinkRel.DELETE, order: CommandOrder.DELETE_BESCHEID }, }; } buildBescheidListServiceConfig(): ListResourceServiceConfig<VorgangWithEingangResource> { return { baseResource: this.vorgangService.getVorgangWithEingang(), - createLinkRel: null, listLinkRel: VorgangWithEingangLinkRel.BESCHEIDE, }; } diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts b/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts index be256c5e2d..0f1608566b 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts @@ -1,4 +1,3 @@ -import { CommandResource, CreateCommand } from '@alfa-client/command-shared'; import { ApiError, createEmptyStateResource, @@ -8,14 +7,15 @@ import { import { HttpErrorResponse } from '@angular/common/http'; import { Action } from '@ngrx/store'; import { Resource, ResourceUri } from '@ngxp/rest'; -import { createCommandResource, createCreateCommand } from 'libs/command-shared/test/command'; -import { createApiError, createHttpErrorResponse } from 'libs/tech-shared/test/error'; -import { createDummyResource } from 'libs/tech-shared/test/resource'; +import { createApiError, createHttpErrorResponse } from '../../../../tech-shared/test/error'; +import { createDummyResource } from '../../../../tech-shared/test/resource'; +import { createCommandResource, createCreateCommand } from '../../../test/command'; +import { CommandResource, CreateCommand } from '../command.model'; import { CommandState, initialState, reducer } from './command.reducer'; import faker from '@faker-js/faker'; -import * as CommandActions from '@alfa-client/command-shared'; +import * as CommandActions from '../+state/command.actions'; describe('Command Reducer', () => { describe('unknown action', () => { diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts b/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts index 65ab3989b7..fcfe5311cc 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts @@ -1,7 +1,7 @@ -import { CommandOrder } from '@alfa-client/command-shared'; import { createEmptyStateResource } from '@alfa-client/tech-shared'; import { MemoizedSelector, createFeatureSelector, createSelector } from '@ngrx/store'; import { isUndefined } from 'lodash-es'; +import { CommandOrder } from '../command.model'; import { COMMAND_FEATURE_KEY, CommandState } from './command.reducer'; const getCommandState: MemoizedSelector<object, CommandState> = diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts index 89623c8f67..73c60da704 100644 --- a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts @@ -36,7 +36,7 @@ describe('CommandResourceService', () => { config = { resource: configStateResource$, getLinkRel, - editLinkRel, + edit: { linkRel: editLinkRel }, delete: { order: deleteOrder, linkRel: deleteLinkRel }, }; repository = mock(ResourceRepository); diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts index 1c9adb7ba7..0eb9f03aa4 100644 --- a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts +++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts @@ -27,6 +27,10 @@ export class CommandResourceService<B extends Resource, T extends Resource> exte super(config, repository); } + doSave(resource: T, toSave: unknown): Observable<T> { + throw new Error('Method not implemented.'); + } + public delete(): Observable<StateResource<CommandResource>> { this.verifyDeleteLinkRel(); return this.commandService.createCommandByProps(this.buildDeleteCommandProps()); diff --git a/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts index 85677d8969..8d4f98c231 100644 --- a/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts @@ -1,5 +1,5 @@ +import { EMPTY_STRING } from '../lib/tech.util'; import { createAriaLabelForIconButton } from './assistive-technologies.util'; -import { EMPTY_STRING } from '@alfa-client/tech-shared'; describe('createAriaLabelForIconButton', () => { const tooltip = 'Tooltip text'; diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts b/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts index 10b94e399d..b28c779d60 100644 --- a/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CatchHttpError } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { CatchHttpError } from '../decorator/catch-http-error.decorator'; import { HttpErrorHandler } from '../error/error.handler'; import { catchHttpErrorHandleErrorResponse, diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts index 3b4e3082a7..b458fd3d70 100644 --- a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts +++ b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { HttpErrorHandler } from '@alfa-client/tech-shared'; import { finalize } from 'rxjs/operators'; +import { HttpErrorHandler } from '../error/error.handler'; import { disableInterceptorDefaultHandling, enableInterceptorDefaultHandling, diff --git a/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts b/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts index a7dcd4c44c..b7bc5aa087 100644 --- a/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts +++ b/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts @@ -29,9 +29,9 @@ import { HttpXsrfTokenExtractor, } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { addRequestHeader, isNotNull } from '@alfa-client/tech-shared'; import { Observable } from 'rxjs'; -import { existRequestHeader, isChangingDataRequest } from '../http.util'; +import { addRequestHeader, existRequestHeader, isChangingDataRequest } from '../http.util'; +import { isNotNull } from '../tech.util'; @Injectable() export class HttpXsrfInterceptor implements HttpInterceptor { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts index 81dbaf1226..4776a77377 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts @@ -1,9 +1,13 @@ import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; -import { Observable, of } from 'rxjs'; +import { fakeAsync, tick } from '@angular/core/testing'; import { Resource } from '@ngxp/rest'; -import { createDummyResource } from 'libs/tech-shared/test/resource'; +import { createProblemDetail } from 'libs/tech-shared/test/error'; +import { Observable, of, throwError } from 'rxjs'; +import { singleCold, singleHot } from '../../../test//marbles'; +import { createDummyResource } from '../../../test/resource'; +import { HttpError, ProblemDetail } from '../tech.model'; import { ApiResourceService } from './api-resource.service'; -import { LinkRelationName, ResourceServiceConfig } from './resource.model'; +import { LinkRelationName, ResourceServiceConfig, SaveResourceData } from './resource.model'; import { ResourceRepository } from './resource.repository'; import { StateResource, createStateResource } from './resource.util'; @@ -18,12 +22,14 @@ describe('ApiResourceService', () => { const editLinkRel: string = 'dummyEditLinkRel'; const getLinkRel: LinkRelationName = 'dummyGetLinkRel'; + const deleteLinkRel: LinkRelationName = 'dummyDeleteLinkRel'; beforeEach(() => { config = { resource: configStateResource$, getLinkRel, - editLinkRel, + edit: { linkRel: editLinkRel }, + delete: { linkRel: deleteLinkRel }, }; repository = mock(ResourceRepository); @@ -33,4 +39,97 @@ describe('ApiResourceService', () => { it('should be created', () => { expect(service).toBeTruthy(); }); + + describe('save', () => { + const dummyToSave: unknown = {}; + const loadedResource: Resource = createDummyResource(); + + const resourceWithEditLinkRel: Resource = createDummyResource([editLinkRel]); + + it('should throw error if edit link not exists', () => { + service.stateResource.next(createStateResource(createDummyResource())); + + expect(() => service.save(dummyToSave)).toThrowError( + 'No edit link exists on current stateresource.', + ); + }); + + it('should call repository', fakeAsync(() => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(of(loadedResource)); + + service.save(dummyToSave).subscribe(); + tick(); + + const expectedSaveResourceData: SaveResourceData<Resource> = { + resource: resourceWithEditLinkRel, + linkRel: editLinkRel, + toSave: dummyToSave, + }; + expect(repository.save).toHaveBeenCalledWith(expectedSaveResourceData); + })); + + it('should return saved object', () => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(singleHot(loadedResource)); + + const saved: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave); + + expect(saved).toBeObservable(singleCold(createStateResource(loadedResource))); + }); + + it('should call handleError', () => { + service.stateResource.next(createStateResource(createDummyResource([config.edit.linkRel]))); + const errorResponse: ProblemDetail = createProblemDetail(); + repository.save.mockReturnValue(throwError(() => errorResponse)); + service.handleError = jest.fn(); + + service.save(<any>{}).subscribe(); + + expect(service.handleError).toHaveBeenCalledWith(errorResponse); + }); + + it('should update state resource subject', fakeAsync(() => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(of(loadedResource)); + + service.save(dummyToSave).subscribe(); + tick(); + + expect(service.stateResource.value).toEqual(createStateResource(loadedResource)); + })); + }); + + describe('delete', () => { + const resourceWithDeleteLinkRel: Resource = createDummyResource([deleteLinkRel]); + const stateResourceWithDeleteLink: StateResource<Resource> = + createStateResource(resourceWithDeleteLinkRel); + + beforeEach(() => { + service.stateResource.next(stateResourceWithDeleteLink); + }); + + it('should throw error if delete linkRel not exists on current stateresource', () => { + service.stateResource.next(createStateResource(createDummyResource())); + + expect(() => service.delete()).toThrowError( + 'No delete link exists on current stateresource.', + ); + }); + + it('should call repository', () => { + service.delete(); + + expect(repository.delete).toHaveBeenCalledWith(resourceWithDeleteLinkRel, deleteLinkRel); + }); + + it('should return value', () => { + const deleteResource: Resource = createDummyResource(); + repository.delete.mockReturnValue(singleHot(deleteResource)); + + const deletedResource: Observable<Resource> = service.delete(); + + expect(deletedResource).toBeObservable(singleCold(deleteResource)); + }); + }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts index e744c170f1..2f328bcfd4 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts @@ -1,4 +1,5 @@ import { Resource } from '@ngxp/rest'; +import { Observable } from 'rxjs'; import { ResourceServiceConfig } from './resource.model'; import { ResourceRepository } from './resource.repository'; import { ResourceService } from './resource.service'; @@ -13,4 +14,17 @@ export class ApiResourceService<B extends Resource, T extends Resource> extends ) { super(config, repository); } + + doSave(resource: T, toSave: unknown): Observable<T> { + return <Observable<T>>this.repository.save({ + resource, + linkRel: this.config.edit.linkRel, + toSave, + }); + } + + public delete(): Observable<Resource> { + this.verifyDeleteLinkRel(); + return this.repository.delete(this.getResource(), this.config.delete.linkRel); + } } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts index 3617275710..e7e4b3264d 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts @@ -5,7 +5,7 @@ import { StateResource } from './resource.util'; export interface ListResourceServiceConfig<B> { baseResource: Observable<StateResource<B>>; listLinkRel: LinkRelationName; - createLinkRel: LinkRelationName; + createLinkRel?: LinkRelationName; } export interface CreateResourceData<T> { @@ -26,6 +26,6 @@ export declare type LinkRelationName = string; export interface ResourceServiceConfig<B> { resource: Observable<StateResource<B>>; getLinkRel: LinkRelationName; - editLinkRel: LinkRelationName; - delete?: { order: string; linkRel: string }; + delete?: { linkRel: LinkRelationName; order?: string }; + edit?: { linkRel: LinkRelationName; order?: string }; } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts index 2e6894ecb1..e5a9f28f28 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts @@ -22,25 +22,19 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - containsLoading, - createErrorStateResource, - EMPTY_ARRAY, - getSuccessfullyLoaded, - StateResource, -} from '@alfa-client/tech-shared'; import { Resource } from '@ngxp/rest'; -import { - createDummyListResource, - createDummyResource, - toResource, -} from 'libs/tech-shared/test/resource'; import { DummyListLinkRel } from '../../../test/dummy'; import { createApiError } from '../../../test/error'; +import { createDummyListResource, createDummyResource, toResource } from '../../../test/resource'; +import { EMPTY_ARRAY } from '../tech.util'; import { + StateResource, + containsLoading, createEmptyStateResource, + createErrorStateResource, createStateResource, getEmbeddedResources, + getSuccessfullyLoaded, isInvalidResourceCombination, isLoaded, isLoadingRequired, -- GitLab