From f73381e7f9eed9510a981924f7198774d8465f1a Mon Sep 17 00:00:00 2001 From: DominikIwanek Date: Fri, 31 Oct 2025 12:24:55 +0100 Subject: [PATCH 1/2] [MNT-25413] ADW - First login after a clear cache does not show the saved searches --- .../services/saved-searches.service.spec.ts | 28 ++++++++++++++++++ .../common/services/saved-searches.service.ts | 29 +++++++++++-------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts b/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts index fd6b85a46ca..d4299e9fab2 100644 --- a/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts +++ b/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts @@ -177,6 +177,34 @@ describe('SavedSearchesService', () => { }); }); + it('should fallback to preferences API if getting saved searches node ID fails', (done) => { + spyOn(authService, 'getUsername').and.returnValue(testUserName); + spyOn(localStorage, 'getItem').and.returnValue(''); + const error = new Error(JSON.stringify({ error: { statusCode: 500 } })); + (service.nodesApi.getNode as jasmine.Spy).and.returnValue(Promise.reject(error)); + + service.getSavedSearches().subscribe((searches) => { + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); + expect(searches.length).toBe(2); + done(); + }); + }); + + it('should handle 404 from getNode() by setting migration flag and falling back to preferences API', (done) => { + spyOn(authService, 'getUsername').and.returnValue(testUserName); + spyOn(localStorage, 'getItem').and.returnValue(''); + spyOn(localStorage, 'setItem'); + const notFoundError = new Error(JSON.stringify({ error: { statusCode: 404 } })); + (service.nodesApi.getNode as jasmine.Spy).and.returnValue(Promise.reject(notFoundError)); + + service.getSavedSearches().subscribe((searches) => { + expect(localStorage.setItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY, 'true'); + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); + expect(searches.length).toBe(2); + done(); + }); + }); + /** * Prepares default mocks for service */ diff --git a/lib/content-services/src/lib/common/services/saved-searches.service.ts b/lib/content-services/src/lib/common/services/saved-searches.service.ts index bf3b00ee0a0..10715f860d4 100644 --- a/lib/content-services/src/lib/common/services/saved-searches.service.ts +++ b/lib/content-services/src/lib/common/services/saved-searches.service.ts @@ -56,7 +56,10 @@ export class SavedSearchesService { readonly savedSearches$ = new ReplaySubject(1); - constructor(private readonly apiService: AlfrescoApiService, private readonly authService: AuthenticationService) {} + constructor( + private readonly apiService: AlfrescoApiService, + private readonly authService: AuthenticationService + ) {} init(): void { this.fetchSavedSearches(); @@ -70,10 +73,7 @@ export class SavedSearchesService { getSavedSearches(): Observable { const savedSearchesMigrated = localStorage.getItem(this.getLocalStorageKey()) ?? ''; if (savedSearchesMigrated === 'true') { - return from(this.preferencesApi.getPreference('-me-', 'saved-searches')).pipe( - map((preference) => JSON.parse(preference.entry.value)), - catchError(() => of([])) - ); + return this.getSavedSearchesFromPreferenceApi(); } else { return this.getSavedSearchesNodeId().pipe( take(1), @@ -81,11 +81,11 @@ export class SavedSearchesService { if (this.savedSearchFileNodeId !== '') { return this.migrateSavedSearches(); } else { - return from(this.preferencesApi.getPreference('-me-', 'saved-searches')).pipe( - map((preference) => JSON.parse(preference.entry.value)), - catchError(() => of([])) - ); + return this.getSavedSearchesFromPreferenceApi(); } + }), + catchError(() => { + return this.getSavedSearchesFromPreferenceApi(); }) ); } @@ -237,10 +237,8 @@ export class SavedSearchesService { const errorStatusCode = JSON.parse(error.message).error.statusCode; if (errorStatusCode === 404) { localStorage.setItem(this.getLocalStorageKey(), 'true'); - return ''; - } else { - return throwError(() => error); } + return throwError(() => error); }) ); } @@ -271,4 +269,11 @@ export class SavedSearchesService { }) ); } + + private getSavedSearchesFromPreferenceApi(): Observable { + return from(this.preferencesApi.getPreference('-me-', 'saved-searches')).pipe( + map((preference) => JSON.parse(preference.entry.value)), + catchError(() => of([])) + ); + } } From a6eaed3ee9093a705c912821e4d99e0e5a9b0497 Mon Sep 17 00:00:00 2001 From: DominikIwanek Date: Fri, 31 Oct 2025 15:00:22 +0100 Subject: [PATCH 2/2] [MNT-25413] ADW - First login after a clear cache does not show the saved searches --- .../services/saved-searches.service.spec.ts | 215 +++++++++--------- .../common/services/saved-searches.service.ts | 4 +- 2 files changed, 111 insertions(+), 108 deletions(-) diff --git a/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts b/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts index d4299e9fab2..9f025a94223 100644 --- a/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts +++ b/lib/content-services/src/lib/common/services/saved-searches.service.spec.ts @@ -57,7 +57,6 @@ describe('SavedSearchesService', () => { }); service = TestBed.inject(SavedSearchesService); authService = TestBed.inject(AuthenticationService); - spyOn(service.nodesApi, 'getNode').and.callFake(() => Promise.resolve({ entry: { id: testNodeId } } as NodeEntry)); spyOn(service.nodesApi, 'getNodeContent').and.callFake(() => createBlob()); spyOn(service.nodesApi, 'deleteNode').and.callFake(() => Promise.resolve()); spyOn(service.preferencesApi, 'getPreference').and.callFake(() => @@ -72,136 +71,142 @@ describe('SavedSearchesService', () => { localStorage.removeItem(LOCAL_STORAGE_KEY); }); - it('should retrieve saved searches from the preferences API', (done) => { - spyOn(authService, 'getUsername').and.callFake(() => testUserName); - spyOn(localStorage, 'getItem').and.callFake(() => 'true'); - service.init(); - - service.getSavedSearches().subscribe((searches) => { - expect(localStorage.getItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY); - expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); - expect(searches.length).toBe(2); - expect(searches[0].name).toBe('Search 1'); - expect(searches[1].name).toBe('Search 2'); - done(); + describe('Saved searches retrieval and migration', () => { + beforeEach(() => { + spyOn(service.nodesApi, 'getNode').and.callFake(() => Promise.resolve({ entry: { id: testNodeId } } as NodeEntry)); }); - }); - - it('should automatically migrate saved searches if config.json file exists', (done) => { - spyOn(localStorage, 'setItem'); - spyOn(authService, 'getUsername').and.callFake(() => testUserName); - - service.getSavedSearches().subscribe((searches) => { - expect(service.nodesApi.getNode).toHaveBeenCalledWith('-my-', { relativePath: 'config.json' }); - expect(service.nodesApi.getNodeContent).toHaveBeenCalledWith(testNodeId); - expect(localStorage.setItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY, 'true'); - expect(service.preferencesApi.updatePreference).toHaveBeenCalledWith('-me-', 'saved-searches', SAVED_SEARCHES_CONTENT); - expect(service.nodesApi.deleteNode).toHaveBeenCalledWith(testNodeId, { permanent: true }); - expect(searches.length).toBe(2); - done(); + it('should retrieve saved searches from the preferences API', (done) => { + spyOn(authService, 'getUsername').and.callFake(() => testUserName); + spyOn(localStorage, 'getItem').and.callFake(() => 'true'); + service.init(); + + service.getSavedSearches().subscribe((searches) => { + expect(localStorage.getItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY); + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); + expect(searches.length).toBe(2); + expect(searches[0].name).toBe('Search 1'); + expect(searches[1].name).toBe('Search 2'); + done(); + }); }); - }); - it('should save a new search', (done) => { - spyOn(authService, 'getUsername').and.callFake(() => testUserName); - spyOn(localStorage, 'getItem').and.callFake(() => 'true'); - const newSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3' }; - service.init(); + it('should automatically migrate saved searches if config.json file exists', (done) => { + spyOn(localStorage, 'setItem'); + spyOn(authService, 'getUsername').and.callFake(() => testUserName); - service.saveSearch(newSearch).subscribe(() => { - expect(service.preferencesApi.updatePreference).toHaveBeenCalledWith('-me-', 'saved-searches', jasmine.any(String)); - expect(service.savedSearches$).toBeDefined(); - done(); + service.getSavedSearches().subscribe((searches) => { + expect(service.nodesApi.getNode).toHaveBeenCalledWith('-my-', { relativePath: 'config.json' }); + expect(service.nodesApi.getNodeContent).toHaveBeenCalledWith(testNodeId); + expect(localStorage.setItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY, 'true'); + expect(service.preferencesApi.updatePreference).toHaveBeenCalledWith('-me-', 'saved-searches', SAVED_SEARCHES_CONTENT); + expect(service.nodesApi.deleteNode).toHaveBeenCalledWith(testNodeId, { permanent: true }); + expect(searches.length).toBe(2); + done(); + }); }); - }); - - it('should emit initial saved searches on subscription', (done) => { - spyOn(authService, 'getUsername').and.callFake(() => testUserName); - spyOn(localStorage, 'getItem').and.returnValue('true'); - service.init(); - service.savedSearches$.pipe().subscribe((searches) => { - expect(searches.length).toBe(2); - expect(searches[0].name).toBe('Search 1'); - expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); - done(); - }); + it('should save a new search', (done) => { + spyOn(authService, 'getUsername').and.callFake(() => testUserName); + spyOn(localStorage, 'getItem').and.callFake(() => 'true'); + const newSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3' }; + service.init(); - service.getSavedSearches().subscribe(); - }); - - it('should emit updated saved searches after saving a new search', (done) => { - spyOn(authService, 'getUsername').and.callFake(() => testUserName); - spyOn(localStorage, 'getItem').and.callFake(() => 'true'); - const newSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3' }; - service.init(); - - service.saveSearch(newSearch).subscribe(() => { - service.savedSearches$.subscribe((searches) => { - expect(searches.length).toBe(3); - expect(searches[2].name).toBe('Search 2'); + service.saveSearch(newSearch).subscribe(() => { expect(service.preferencesApi.updatePreference).toHaveBeenCalledWith('-me-', 'saved-searches', jasmine.any(String)); + expect(service.savedSearches$).toBeDefined(); done(); }); }); - }); - it('should edit a search', (done) => { - const updatedSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3', order: 0 }; - prepareDefaultMock(); + it('should emit initial saved searches on subscription', (done) => { + spyOn(authService, 'getUsername').and.callFake(() => testUserName); + spyOn(localStorage, 'getItem').and.returnValue('true'); + service.init(); - service.editSavedSearch(updatedSearch).subscribe(() => { - service.savedSearches$.subscribe((searches) => { + service.savedSearches$.pipe().subscribe((searches) => { expect(searches.length).toBe(2); - expect(searches[0].name).toBe('Search 3'); - expect(searches[0].order).toBe(0); - - expect(searches[1].name).toBe('Search 2'); - expect(searches[1].order).toBe(1); + expect(searches[0].name).toBe('Search 1'); + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); done(); }); + + service.getSavedSearches().subscribe(); + }); + + it('should emit updated saved searches after saving a new search', (done) => { + spyOn(authService, 'getUsername').and.callFake(() => testUserName); + spyOn(localStorage, 'getItem').and.callFake(() => 'true'); + const newSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3' }; + service.init(); + + service.saveSearch(newSearch).subscribe(() => { + service.savedSearches$.subscribe((searches) => { + expect(searches.length).toBe(3); + expect(searches[2].name).toBe('Search 2'); + expect(service.preferencesApi.updatePreference).toHaveBeenCalledWith('-me-', 'saved-searches', jasmine.any(String)); + done(); + }); + }); }); - }); - it('should delete a search', (done) => { - const searchToDelete = { name: 'Search 1', description: 'Description 1', encodedUrl: 'url1', order: 0 }; - prepareDefaultMock(); + it('should edit a search', (done) => { + const updatedSearch = { name: 'Search 3', description: 'Description 3', encodedUrl: 'url3', order: 0 }; + prepareDefaultMock(); + + service.editSavedSearch(updatedSearch).subscribe(() => { + service.savedSearches$.subscribe((searches) => { + expect(searches.length).toBe(2); + expect(searches[0].name).toBe('Search 3'); + expect(searches[0].order).toBe(0); + expect(searches[1].name).toBe('Search 2'); + expect(searches[1].order).toBe(1); + done(); + }); + }); + }); - service.deleteSavedSearch(searchToDelete).subscribe(() => { - service.savedSearches$.subscribe((searches) => { - expect(searches.length).toBe(1); - expect(searches[0].name).toBe('Search 2'); - expect(searches[0].order).toBe(0); - done(); + it('should delete a search', (done) => { + const searchToDelete = { name: 'Search 1', description: 'Description 1', encodedUrl: 'url1', order: 0 }; + prepareDefaultMock(); + + service.deleteSavedSearch(searchToDelete).subscribe(() => { + service.savedSearches$.subscribe((searches) => { + expect(searches.length).toBe(1); + expect(searches[0].name).toBe('Search 2'); + expect(searches[0].order).toBe(0); + done(); + }); }); }); }); - it('should fallback to preferences API if getting saved searches node ID fails', (done) => { - spyOn(authService, 'getUsername').and.returnValue(testUserName); - spyOn(localStorage, 'getItem').and.returnValue(''); - const error = new Error(JSON.stringify({ error: { statusCode: 500 } })); - (service.nodesApi.getNode as jasmine.Spy).and.returnValue(Promise.reject(error)); + describe('Saved searches error handling', () => { + it('should fallback to preferences API if getting saved searches node ID fails', (done) => { + spyOn(authService, 'getUsername').and.returnValue(testUserName); + spyOn(localStorage, 'getItem').and.returnValue(''); + const error = new Error(JSON.stringify({ error: { statusCode: 500 } })); + spyOn(service.nodesApi, 'getNode').and.returnValue(Promise.reject(error)); - service.getSavedSearches().subscribe((searches) => { - expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); - expect(searches.length).toBe(2); - done(); + service.getSavedSearches().subscribe((searches) => { + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); + expect(searches.length).toBe(2); + done(); + }); }); - }); - it('should handle 404 from getNode() by setting migration flag and falling back to preferences API', (done) => { - spyOn(authService, 'getUsername').and.returnValue(testUserName); - spyOn(localStorage, 'getItem').and.returnValue(''); - spyOn(localStorage, 'setItem'); - const notFoundError = new Error(JSON.stringify({ error: { statusCode: 404 } })); - (service.nodesApi.getNode as jasmine.Spy).and.returnValue(Promise.reject(notFoundError)); - - service.getSavedSearches().subscribe((searches) => { - expect(localStorage.setItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY, 'true'); - expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); - expect(searches.length).toBe(2); - done(); + it('should handle 404 from getNode() by setting migration flag and falling back to preferences API', (done) => { + spyOn(authService, 'getUsername').and.returnValue(testUserName); + spyOn(localStorage, 'getItem').and.returnValue(''); + spyOn(localStorage, 'setItem'); + const notFoundError = new Error(JSON.stringify({ error: { statusCode: 404 } })); + spyOn(service.nodesApi, 'getNode').and.returnValue(Promise.reject(notFoundError)); + + service.getSavedSearches().subscribe((searches) => { + expect(localStorage.setItem).toHaveBeenCalledWith(LOCAL_STORAGE_KEY, 'true'); + expect(service.preferencesApi.getPreference).toHaveBeenCalledWith('-me-', 'saved-searches'); + expect(searches.length).toBe(2); + done(); + }); }); }); diff --git a/lib/content-services/src/lib/common/services/saved-searches.service.ts b/lib/content-services/src/lib/common/services/saved-searches.service.ts index 10715f860d4..4a30eff2499 100644 --- a/lib/content-services/src/lib/common/services/saved-searches.service.ts +++ b/lib/content-services/src/lib/common/services/saved-searches.service.ts @@ -84,9 +84,7 @@ export class SavedSearchesService { return this.getSavedSearchesFromPreferenceApi(); } }), - catchError(() => { - return this.getSavedSearchesFromPreferenceApi(); - }) + catchError(() => this.getSavedSearchesFromPreferenceApi()) ); } }