Skip to content
Snippets Groups Projects
Commit 766a51b9 authored by Albert Bruns's avatar Albert Bruns
Browse files

OZG-7712 fix refresh bug

parent ca41aec5
Branches
Tags
1 merge request!101OZG-7712 Fix reloading bug
...@@ -40,6 +40,9 @@ describe('KeycloakResourceService', () => { ...@@ -40,6 +40,9 @@ describe('KeycloakResourceService', () => {
const dummyObject: Dummy = createDummy(); const dummyObject: Dummy = createDummy();
const dummyAction: Observable<Dummy> = of(dummyObject); const dummyAction: Observable<Dummy> = of(dummyObject);
const dummyError: Error = new Error('Test error');
const dummyErrorAction: Observable<Error> = new Observable((observer) => observer.error(dummyError));
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [TestResourceService], providers: [TestResourceService],
...@@ -52,7 +55,7 @@ describe('KeycloakResourceService', () => { ...@@ -52,7 +55,7 @@ describe('KeycloakResourceService', () => {
const stateResource: StateResource<unknown> = createStateResource([]); const stateResource: StateResource<unknown> = createStateResource([]);
beforeEach(() => { beforeEach(() => {
service.handleChanges = jest.fn().mockReturnValue(singleCold(stateResource)); service._handleChanges = jest.fn().mockReturnValue(singleCold(stateResource));
}); });
it('should return stateResource', () => { it('should return stateResource', () => {
...@@ -64,7 +67,7 @@ describe('KeycloakResourceService', () => { ...@@ -64,7 +67,7 @@ describe('KeycloakResourceService', () => {
it('should call handleChanges ', fakeAsync(() => { it('should call handleChanges ', fakeAsync(() => {
service.getAll().subscribe(); service.getAll().subscribe();
expect(service.handleChanges).toHaveBeenCalled(); expect(service._handleChanges).toHaveBeenCalled();
})); }));
}); });
...@@ -76,7 +79,7 @@ describe('KeycloakResourceService', () => { ...@@ -76,7 +79,7 @@ describe('KeycloakResourceService', () => {
}); });
it('should call doIfLoadingRequired', () => { it('should call doIfLoadingRequired', () => {
service.handleChanges(emptyStateResource); service._handleChanges(emptyStateResource);
expect(doIfLoadingRequiredSpy).toHaveBeenCalled(); expect(doIfLoadingRequiredSpy).toHaveBeenCalled();
}); });
...@@ -84,7 +87,7 @@ describe('KeycloakResourceService', () => { ...@@ -84,7 +87,7 @@ describe('KeycloakResourceService', () => {
it('should return stateResource', (done) => { it('should return stateResource', (done) => {
service.stateResource.next(createStateResource([])); service.stateResource.next(createStateResource([]));
service.handleChanges(emptyStateResource).subscribe((stateResource: StateResource<[]>) => { service._handleChanges(emptyStateResource).subscribe((stateResource: StateResource<[]>) => {
expect(stateResource).toEqual(createStateResource([])); expect(stateResource).toEqual(createStateResource([]));
done(); done();
}); });
...@@ -93,18 +96,18 @@ describe('KeycloakResourceService', () => { ...@@ -93,18 +96,18 @@ describe('KeycloakResourceService', () => {
describe('loadResource', () => { describe('loadResource', () => {
it('should call set loading', () => { it('should call set loading', () => {
service.setLoading = jest.fn(); service._setLoading = jest.fn();
service.loadResource(); service._loadResource();
expect(service.setLoading).toHaveBeenCalled(); expect(service._setLoading).toHaveBeenCalled();
}); });
it('should update Resource', fakeAsync(() => { it('should update Resource', fakeAsync(() => {
const dummyItems = [createDummy(), createDummy()]; const dummyItems = [createDummy(), createDummy()];
jest.spyOn(service, '_getItemsFromKeycloak' as any).mockReturnValue(of(dummyItems)); jest.spyOn(service, '_getItemsFromKeycloak' as any).mockReturnValue(of(dummyItems));
service.loadResource(); service._loadResource();
tick(); tick();
expect(service.stateResource.value.resource).toEqual(dummyItems); expect(service.stateResource.value.resource).toEqual(dummyItems);
...@@ -115,11 +118,11 @@ describe('KeycloakResourceService', () => { ...@@ -115,11 +118,11 @@ describe('KeycloakResourceService', () => {
const saveObject: Dummy = createDummy(); const saveObject: Dummy = createDummy();
it('should call handleLoading', () => { it('should call handleLoading', () => {
service.handleLoading = jest.fn(); service._handleLoading = jest.fn();
service.create(saveObject); service.create(saveObject);
expect(service.handleLoading).toHaveBeenCalled(); expect(service._handleLoading).toHaveBeenCalled();
}); });
it('should call createInKeycloak', () => { it('should call createInKeycloak', () => {
...@@ -133,11 +136,11 @@ describe('KeycloakResourceService', () => { ...@@ -133,11 +136,11 @@ describe('KeycloakResourceService', () => {
describe('save', () => { describe('save', () => {
it('should call handleLoading', () => { it('should call handleLoading', () => {
service.handleLoading = jest.fn(); service._handleLoading = jest.fn();
service.save(dummyObject); service.save(dummyObject);
expect(service.handleLoading).toHaveBeenCalled(); expect(service._handleLoading).toHaveBeenCalled();
}); });
it('should call createInKeycloak', () => { it('should call createInKeycloak', () => {
...@@ -151,11 +154,11 @@ describe('KeycloakResourceService', () => { ...@@ -151,11 +154,11 @@ describe('KeycloakResourceService', () => {
describe('delete', () => { describe('delete', () => {
it('should call handleLoading', () => { it('should call handleLoading', () => {
service.handleLoading = jest.fn(); service._handleLoading = jest.fn();
service.delete(id); service.delete(id);
expect(service.handleLoading).toHaveBeenCalled(); expect(service._handleLoading).toHaveBeenCalled();
}); });
it('should call createInKeycloak', () => { it('should call createInKeycloak', () => {
...@@ -168,37 +171,58 @@ describe('KeycloakResourceService', () => { ...@@ -168,37 +171,58 @@ describe('KeycloakResourceService', () => {
}); });
describe('handleLoading', () => { describe('handleLoading', () => {
it('should set loading', () => {
service._handleLoading(dummyAction);
expect(service.stateResource.value.loading).toBe(true);
});
it('should call refreshAfterFirstEmit', () => { it('should call refreshAfterFirstEmit', () => {
service.refreshAfterFirstEmit = jest.fn().mockReturnValue(dummyAction); service._refreshAfterEmit = jest.fn().mockReturnValue(dummyAction);
service.handleLoading(dummyAction); service._handleLoading(dummyAction);
expect(service.refreshAfterFirstEmit).toHaveBeenCalled(); expect(service._refreshAfterEmit).toHaveBeenCalled();
}); });
it('should call progress', () => { it('should call progress', () => {
service.setLoadingInStateResource = jest.fn().mockReturnValue(dummyAction); service._setLoadingInStateResource = jest.fn().mockReturnValue(dummyAction);
service.handleLoading(dummyAction); service._handleLoading(dummyAction);
expect(service.setLoadingInStateResource).toHaveBeenCalled(); expect(service._setLoadingInStateResource).toHaveBeenCalled();
}); });
}); });
describe('refreshAfterFirstEmit', () => { describe('refreshAfterEmit', () => {
it('should call refresh after first emit', fakeAsync(() => { it('should call refresh after first emit', () => {
service.refresh = jest.fn(); service.refresh = jest.fn();
service.refreshAfterFirstEmit(dummyAction).subscribe(); service._refreshAfterEmit(dummyAction).subscribe();
tick();
expect(service.refresh).toHaveBeenCalled(); expect(service.refresh).toHaveBeenCalled();
})); });
it('should call refresh on error', () => {
service.refresh = jest.fn();
service._refreshAfterEmit(dummyErrorAction).subscribe();
expect(service.refresh).toHaveBeenCalled();
});
it('should throw error refresh on error', () => {
service.refresh = jest.fn();
const result: Observable<unknown> = service._refreshAfterEmit(dummyErrorAction);
expect(result).toBeObservable(cold('#', null, dummyError));
});
}); });
describe('setLoadingInStateResource', () => { describe('setLoadingInStateResource', () => {
it('should emit emptyState first with loading and then state without loading', () => { it('should emit emptyState first with loading and then state without loading', () => {
const result: Observable<StateResource<Dummy>> = service.setLoadingInStateResource<Dummy>(cold('--x', { x: dummyObject })); const result: Observable<StateResource<Dummy>> = service._setLoadingInStateResource<Dummy>(cold('--x', { x: dummyObject }));
expect(result).toBeObservable(cold('a-b', { a: createEmptyStateResource(true), b: createStateResource(dummyObject) })); expect(result).toBeObservable(cold('a-b', { a: createEmptyStateResource(true), b: createStateResource(dummyObject) }));
}); });
...@@ -208,7 +232,7 @@ describe('KeycloakResourceService', () => { ...@@ -208,7 +232,7 @@ describe('KeycloakResourceService', () => {
it('should set loading in state to true without parameter', () => { it('should set loading in state to true without parameter', () => {
service.stateResource.value.loading = false; service.stateResource.value.loading = false;
service.setLoading(); service._setLoading();
expect(service.stateResource.value.loading).toEqual(true); expect(service.stateResource.value.loading).toEqual(true);
}); });
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { createEmptyStateResource, createStateResource, doIfLoadingRequired, StateResource } from '@alfa-client/tech-shared'; import { createEmptyStateResource, createStateResource, doIfLoadingRequired, StateResource } from '@alfa-client/tech-shared';
import { BehaviorSubject, first, map, Observable, startWith, switchMap, tap } from 'rxjs'; import { BehaviorSubject, catchError, first, map, Observable, startWith, switchMap, tap } from 'rxjs';
export abstract class KeycloakResourceService<T> { export abstract class KeycloakResourceService<T> {
readonly stateResource: BehaviorSubject<StateResource<T[]>> = new BehaviorSubject(createEmptyStateResource()); readonly stateResource: BehaviorSubject<StateResource<T[]>> = new BehaviorSubject(createEmptyStateResource());
...@@ -30,16 +30,16 @@ export abstract class KeycloakResourceService<T> { ...@@ -30,16 +30,16 @@ export abstract class KeycloakResourceService<T> {
public getAll(): Observable<StateResource<T[]>> { public getAll(): Observable<StateResource<T[]>> {
return this.stateResource return this.stateResource
.asObservable() .asObservable()
.pipe(switchMap((stateResource: StateResource<T[]>) => this.handleChanges(stateResource))); .pipe(switchMap((stateResource: StateResource<T[]>) => this._handleChanges(stateResource)));
} }
handleChanges(stateResource: StateResource<T[]>): Observable<StateResource<T[]>> { _handleChanges(stateResource: StateResource<T[]>): Observable<StateResource<T[]>> {
doIfLoadingRequired(stateResource, (): void => this.loadResource()); doIfLoadingRequired(stateResource, (): void => this._loadResource());
return this.stateResource.asObservable(); return this.stateResource.asObservable();
} }
loadResource(): void { _loadResource(): void {
this.setLoading(); this._setLoading();
this._getItemsFromKeycloak() this._getItemsFromKeycloak()
.pipe(first()) .pipe(first())
.subscribe((items: T[]): void => this.updateResource(items)); .subscribe((items: T[]): void => this.updateResource(items));
...@@ -52,42 +52,49 @@ export abstract class KeycloakResourceService<T> { ...@@ -52,42 +52,49 @@ export abstract class KeycloakResourceService<T> {
} }
public create(item: Partial<T>): Observable<StateResource<T>> { public create(item: Partial<T>): Observable<StateResource<T>> {
return this.handleLoading<T>(this._createInKeycloak(item)); return this._handleLoading<T>(this._createInKeycloak(item));
} }
protected abstract _createInKeycloak(item: Partial<T>): Observable<T>; protected abstract _createInKeycloak(item: Partial<T>): Observable<T>;
public save(item: T): Observable<StateResource<T>> { public save(item: T): Observable<StateResource<T>> {
return this.handleLoading<T>(this._saveInKeycloak(item)); return this._handleLoading<T>(this._saveInKeycloak(item));
} }
protected abstract _saveInKeycloak(item: T): Observable<T>; protected abstract _saveInKeycloak(item: T): Observable<T>;
public delete(id: string): Observable<StateResource<void>> { public delete(id: string): Observable<StateResource<void>> {
return this.handleLoading(this._deleteInKeycloak(id)); return this._handleLoading(this._deleteInKeycloak(id));
} }
protected abstract _deleteInKeycloak(id: string): Observable<void>; protected abstract _deleteInKeycloak(id: string): Observable<void>;
handleLoading<D>(action: Observable<D>): Observable<StateResource<D>> { _handleLoading<D>(action: Observable<D>): Observable<StateResource<D>> {
return this.setLoadingInStateResource<D>(this.refreshAfterFirstEmit<D>(action)); this._setLoading();
return this._setLoadingInStateResource<D>(this._refreshAfterEmit<D>(action));
} }
refreshAfterFirstEmit<D>(action: Observable<D>): Observable<D> { _refreshAfterEmit<D>(action: Observable<D>): Observable<D> {
return action.pipe( return action.pipe(
first(), first(),
tap((): void => this.refresh()), tap((): void => this.refresh()),
catchError((err: Error) => this.handleError(err)),
); );
} }
setLoadingInStateResource<D>(action: Observable<D>): Observable<StateResource<D>> { handleError(err: Error): never {
this.refresh();
throw err;
}
_setLoadingInStateResource<D>(action: Observable<D>): Observable<StateResource<D>> {
return action.pipe( return action.pipe(
map((value: D): StateResource<D> => createStateResource<D>(value)), map((value: D): StateResource<D> => createStateResource<D>(value)),
startWith(createEmptyStateResource<D>(true)), startWith(createEmptyStateResource<D>(true)),
); );
} }
setLoading(): void { _setLoading(): void {
this.stateResource.next({ ...this.stateResource.value, loading: true }); this.stateResource.next({ ...this.stateResource.value, loading: true });
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment