Skip to content

Commit 62120c2

Browse files
committed
feat: Add unit tests for authoritySourceService, covering getSourceMap functionality and edge cases
1 parent 8231fdc commit 62120c2

2 files changed

Lines changed: 108 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
* Refactor imports and add import boundary rules. Refs [UILD-816].
1010
* Fix regression issues that appeared after refactoring. Refs [UILD-816], [UILD-827].
1111
* Add Authority edit page. Refs [UILD-826].
12+
* Extend Search page with Authority search and create options. Refs [UILD-825].
1213

1314
[UILD-744]:https://folio-org.atlassian.net/browse/UILD-744
1415
[UILD-816]:https://folio-org.atlassian.net/browse/UILD-816
1516
[UILD-821]:https://folio-org.atlassian.net/browse/UILD-821
1617
[UILD-827]:https://folio-org.atlassian.net/browse/UILD-827
1718
[UILD-826]:https://folio-org.atlassian.net/browse/UILD-826
19+
[UILD-825]:https://folio-org.atlassian.net/browse/UILD-825
1820

1921
## 2.0.4 (2026-06-03)
2022
* Fix default profile type persistence across edit form and profile settings. Fixes [UILD-820].
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { SOURCE_API_ENDPOINT } from '@/common/constants/api.constants';
2+
3+
jest.mock('@/common/api/base.api');
4+
5+
// Re-import the service inside an isolated module scope on each test so that
6+
// the module-level `cachedSourcesPromise` is reset to `undefined`.
7+
type AuthoritySourceService = (typeof import('./authoritySource.service'))['authoritySourceService'];
8+
9+
let authoritySourceService: AuthoritySourceService;
10+
let mockGetJson: jest.Mock;
11+
12+
beforeEach(async () => {
13+
await jest.isolateModulesAsync(async () => {
14+
const { authoritySourceService: importedAuthoritySourceService } = await import('./authoritySource.service');
15+
const { default: baseApi } = await import('@/common/api/base.api');
16+
17+
authoritySourceService = importedAuthoritySourceService;
18+
mockGetJson = baseApi.getJson as jest.Mock;
19+
mockGetJson.mockReset();
20+
});
21+
});
22+
23+
describe('authoritySourceService', () => {
24+
describe('getSourceMap', () => {
25+
it('returns a map of id → name from the API response', async () => {
26+
mockGetJson.mockResolvedValue({
27+
authoritySourceFiles: [
28+
{ id: 'src-1', name: 'LC Name Authority File' },
29+
{ id: 'src-2', name: 'MeSH' },
30+
],
31+
});
32+
33+
const result = await authoritySourceService.getSourceMap();
34+
35+
expect(result).toEqual(
36+
new Map([
37+
['src-1', 'LC Name Authority File'],
38+
['src-2', 'MeSH'],
39+
]),
40+
);
41+
expect(mockGetJson).toHaveBeenCalledWith(
42+
expect.objectContaining({ url: SOURCE_API_ENDPOINT.AUTHORITY, sameOrigin: true }),
43+
);
44+
});
45+
46+
it('returns an empty map when the response has no sources', async () => {
47+
mockGetJson.mockResolvedValue({ authoritySourceFiles: [] });
48+
49+
const result = await authoritySourceService.getSourceMap();
50+
51+
expect(result).toEqual(new Map());
52+
});
53+
54+
it('filters out entries without an id', async () => {
55+
mockGetJson.mockResolvedValue({
56+
authoritySourceFiles: [
57+
{ id: 'src-1', name: 'Valid Source' },
58+
{ name: 'No Id Source' },
59+
{ id: '', name: 'Empty Id Source' },
60+
],
61+
});
62+
63+
const result = await authoritySourceService.getSourceMap();
64+
65+
expect(result).toEqual(new Map([['src-1', 'Valid Source']]));
66+
});
67+
68+
it('uses empty string for name when name is absent', async () => {
69+
mockGetJson.mockResolvedValue({ authoritySourceFiles: [{ id: 'src-1' }] });
70+
71+
const result = await authoritySourceService.getSourceMap();
72+
73+
expect(result.get('src-1')).toBe('');
74+
});
75+
76+
it('handles a null/undefined response gracefully', async () => {
77+
mockGetJson.mockResolvedValue(null);
78+
79+
const result = await authoritySourceService.getSourceMap();
80+
81+
expect(result).toEqual(new Map());
82+
});
83+
84+
it('caches the result and only calls the API once for repeated calls', async () => {
85+
mockGetJson.mockResolvedValue({ authoritySourceFiles: [{ id: 'src-1', name: 'Source 1' }] });
86+
87+
await authoritySourceService.getSourceMap();
88+
await authoritySourceService.getSourceMap();
89+
90+
expect(mockGetJson).toHaveBeenCalledTimes(1);
91+
});
92+
93+
it('clears the cache and retries after a failed request', async () => {
94+
mockGetJson
95+
.mockRejectedValueOnce(new Error('network error'))
96+
.mockResolvedValue({ authoritySourceFiles: [{ id: 'src-1', name: 'Source 1' }] });
97+
98+
await expect(authoritySourceService.getSourceMap()).rejects.toThrow('network error');
99+
100+
const result = await authoritySourceService.getSourceMap();
101+
102+
expect(mockGetJson).toHaveBeenCalledTimes(2);
103+
expect(result.get('src-1')).toBe('Source 1');
104+
});
105+
});
106+
});

0 commit comments

Comments
 (0)