From c2b9198cbd5077c917386e55dd98e498e641c82d Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Fri, 6 Feb 2026 15:18:16 +0100 Subject: [PATCH 1/7] Fixes #5003: suppress toast on error via option to axios request config (boolean or function) --- spring-boot-admin-server-ui/package-lock.json | 52 ++++++- spring-boot-admin-server-ui/package.json | 1 + .../@stekoe/vue-toast-notificationcenter.js | 15 ++ .../main/frontend/services/instance.spec.ts | 145 ++++++++++++++++++ .../src/main/frontend/services/instance.ts | 20 ++- .../src/main/frontend/tests/setup.ts | 11 ++ .../src/main/frontend/utils/axios.spec.ts | 85 +++++++++- .../src/main/frontend/utils/axios.ts | 35 +++-- .../instances/details/details-cache.spec.ts | 2 +- .../views/instances/details/details-cache.vue | 34 ++-- 10 files changed, 367 insertions(+), 33 deletions(-) create mode 100644 spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js diff --git a/spring-boot-admin-server-ui/package-lock.json b/spring-boot-admin-server-ui/package-lock.json index a983171144c..6e82aa99b4f 100644 --- a/spring-boot-admin-server-ui/package-lock.json +++ b/spring-boot-admin-server-ui/package-lock.json @@ -78,6 +78,7 @@ "@vue/eslint-config-typescript": "^14.0.0", "@vue/test-utils": "2.4.6", "autoprefixer": "10.4.24", + "axios-mock-adapter": "^2.1.0", "babel-loader": "10.0.0", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", @@ -4645,6 +4646,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-mock-adapter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-2.1.0.tgz", + "integrity": "sha512-AZUe4OjECGCNNssH8SOdtneiQELsqTsat3SQQCWLPjN436/H+L9AjWfV7bF+Zg/YL9cgbhrz5671hoh+Tbn98w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, "node_modules/babel-loader": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", @@ -5872,9 +5887,9 @@ "license": "Apache-2.0" }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -7077,9 +7092,10 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -7591,6 +7607,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", diff --git a/spring-boot-admin-server-ui/package.json b/spring-boot-admin-server-ui/package.json index f6f1b631664..995b9ac314c 100644 --- a/spring-boot-admin-server-ui/package.json +++ b/spring-boot-admin-server-ui/package.json @@ -89,6 +89,7 @@ "@vue/eslint-config-typescript": "^14.0.0", "@vue/test-utils": "2.4.6", "autoprefixer": "10.4.24", + "axios-mock-adapter": "^2.1.0", "babel-loader": "10.0.0", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", diff --git a/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js b/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js new file mode 100644 index 00000000000..6a39169d5dd --- /dev/null +++ b/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js @@ -0,0 +1,15 @@ +// __mocks__/@stekoe/vue-toast-notificationcenter.js +import { vi } from 'vitest'; + +// Ensure errorSpy is available +if (!globalThis.errorSpy) { + globalThis.errorSpy = vi.fn(); +} + +export const useNotificationCenter = () => ({ error: globalThis.errorSpy }); + +export default { + install(app) { + app.config.globalProperties.$nc = { error: globalThis.errorSpy }; + }, +}; diff --git a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts index efdfeb958b7..b3547d52e19 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts @@ -1,3 +1,4 @@ +import { AxiosError } from 'axios'; import { describe, expect, test, vi } from 'vitest'; import Instance from '@/services/instance'; @@ -40,4 +41,148 @@ describe('Instance', () => { expect(instance.showUrl()).toEqual(expectUrlToBeShownOnUI); }, ); + + describe('fetchMetric', () => { + test('should pass suppressToast option to axios config', async () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + }); + + // Spy on axios.get + const axiosGetSpy = vi.spyOn(instance.axios, 'get'); + + // Mock the axios request + axiosGetSpy.mockResolvedValue({ + data: { + measurements: [{ value: 42 }], + }, + }); + + await instance.fetchMetric( + 'test.metric', + { tag: 'value' }, + { + suppressToast: true, + }, + ); + + // Verify suppressToast was passed in config + expect(axiosGetSpy).toHaveBeenCalledWith( + expect.stringContaining('actuator/metrics/test.metric'), + expect.objectContaining({ + suppressToast: true, + }), + ); + }); + + test('should work without options parameter for backward compatibility', async () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + }); + + const axiosGetSpy = vi.spyOn(instance.axios, 'get'); + + axiosGetSpy.mockResolvedValue({ + data: { + measurements: [{ value: 42 }], + }, + }); + + await instance.fetchMetric('test.metric', { tag: 'value' }); + + // Verify it was called without suppressToast + expect(axiosGetSpy).toHaveBeenCalledWith( + expect.stringContaining('actuator/metrics/test.metric'), + expect.objectContaining({ + suppressToast: undefined, + }), + ); + }); + + test('should pass suppressToast=false when explicitly set to false', async () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + }); + + const axiosGetSpy = vi.spyOn(instance.axios, 'get'); + + axiosGetSpy.mockResolvedValue({ + data: { + measurements: [{ value: 42 }], + }, + }); + + await instance.fetchMetric( + 'test.metric', + { tag: 'value' }, + { + suppressToast: false, + }, + ); + + expect(axiosGetSpy).toHaveBeenCalledWith( + expect.stringContaining('actuator/metrics/test.metric'), + expect.objectContaining({ + suppressToast: false, + }), + ); + }); + + test('should include tags in request parameters', async () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + }); + + const axiosGetSpy = vi.spyOn(instance.axios, 'get'); + + axiosGetSpy.mockResolvedValue({ + data: { + measurements: [{ value: 42 }], + }, + }); + + await instance.fetchMetric('cache.gets', { + name: 'my-cache', + result: 'hit', + }); + + const callArgs = axiosGetSpy.mock.calls[0]; + const params = callArgs[1]?.params as URLSearchParams; + + expect(params).toBeInstanceOf(URLSearchParams); + expect(params.getAll('tag')).toContain('name:my-cache'); + expect(params.getAll('tag')).toContain('result:hit'); + }); + + test('should pass suppressToast function to axios config', async () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + }); + + const axiosGetSpy = vi.spyOn(instance.axios, 'get'); + + axiosGetSpy.mockResolvedValue({ + data: { + measurements: [{ value: 42 }], + }, + }); + + const suppressFn = (err: AxiosError) => err.response?.status === 404; + await instance.fetchMetric( + 'cache.size', + {}, + { suppressToast: suppressFn }, + ); + + expect(axiosGetSpy).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ suppressToast: suppressFn }), + ); + }); + }); }); diff --git a/spring-boot-admin-server-ui/src/main/frontend/services/instance.ts b/spring-boot-admin-server-ui/src/main/frontend/services/instance.ts index c25b1fba306..62f5841979f 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/services/instance.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/services/instance.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AxiosInstance } from 'axios'; +import { AxiosError, AxiosInstance } from 'axios'; import saveAs from 'file-saver'; import { Observable, concat, from, ignoreElements } from 'rxjs'; @@ -29,6 +29,17 @@ import { useSbaConfig } from '@/sba-config'; import { actuatorMimeTypes } from '@/services/spring-mime-types'; import { transformToJSON } from '@/utils/transformToJSON'; +// Extend AxiosRequestConfig to allow suppressToast +declare module 'axios' { + interface AxiosRequestConfig { + suppressToast?: boolean | ((error: AxiosError) => boolean); + } +} + +export type FetchMetricOptions = { + suppressToast?: boolean | ((error: AxiosError) => boolean); +}; + const isInstanceActuatorRequest = (url: string) => url.match(/^instances[/][^/]+[/]actuator([/].*)?$/); @@ -166,7 +177,11 @@ class Instance { return this.axios.get(uri`actuator/metrics`); } - async fetchMetric(metric, tags) { + async fetchMetric( + metric: string, + tags?: Record, + options?: FetchMetricOptions, + ) { const params = new URLSearchParams(); if (tags) { let firstElementDuplicated = false; @@ -187,6 +202,7 @@ class Instance { } return this.axios.get(uri`actuator/metrics/${metric}`, { params, + suppressToast: options?.suppressToast, }); } diff --git a/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts b/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts index 382a2af9a5a..e455d3e9f7e 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts @@ -31,6 +31,17 @@ global.EventSource = class { global.SBA = sbaConfig; +// Mock localStorage globally for all tests +Object.defineProperty(global, 'localStorage', { + value: { + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + clear: vi.fn(), + }, + writable: true, +}); + beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); afterAll(() => server.close()); afterEach(() => server.resetHandlers()); diff --git a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts index a69386c4de2..3fa6921c2d9 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts @@ -13,9 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import axios, { AxiosError } from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { redirectOn401 } from './axios'; +import { redirectOn401, registerErrorToastInterceptor } from './axios'; + +// Initialize errorSpy BEFORE any mocks or imports +globalThis.errorSpy = vi.fn(); + +// Mock sba-config to enable toasts +vi.mock('../sba-config', () => ({ + default: { + uiSettings: { + enableToasts: true, + }, + csrf: { + parameterName: '_csrf', + headerName: 'X-XSRF-TOKEN', + }, + }, +})); + +// Use manual mock for @stekoe/vue-toast-notificationcenter +vi.mock('@stekoe/vue-toast-notificationcenter'); describe('redirectOn401', () => { beforeEach(() => { @@ -78,3 +99,63 @@ describe('redirectOn401', () => { expect(window.location.assign).not.toBeCalled(); }); }); + +describe('registerErrorToastInterceptor', () => { + let axiosInstance; + let mock; + + beforeEach(() => { + globalThis.errorSpy.mockClear(); + axiosInstance = axios.create(); + // Pass a mock notification center directly + registerErrorToastInterceptor(axiosInstance, { + error: globalThis.errorSpy, + }); + mock = new MockAdapter(axiosInstance); + }); + + afterEach(() => { + if (mock) mock.restore(); + vi.restoreAllMocks(); + }); + + it('shows toast by default', async () => { + mock.onGet('/fail').reply(500); + await expect(axiosInstance.get('/fail')).rejects.toBeDefined(); + expect(globalThis.errorSpy).toHaveBeenCalled(); + }); + + it('suppresses toast if suppressToast is true', async () => { + mock.onGet('/fail').reply(500); + await expect( + axiosInstance.get('/fail', { suppressToast: true }), + ).rejects.toBeDefined(); + expect(globalThis.errorSpy).not.toHaveBeenCalled(); + }); + + it('shows toast if suppressToast is false', async () => { + mock.onGet('/fail').reply(500); + await expect( + axiosInstance.get('/fail', { suppressToast: false }), + ).rejects.toBeDefined(); + expect(globalThis.errorSpy).toHaveBeenCalled(); + }); + + it('suppresses toast if suppressToast function returns true', async () => { + mock.onGet('/fail').reply(404); + const suppressFn = (err: AxiosError) => err.response?.status === 404; + await expect( + axiosInstance.get('/fail', { suppressToast: suppressFn }), + ).rejects.toBeDefined(); + expect(globalThis.errorSpy).not.toHaveBeenCalled(); + }); + + it('shows toast if suppressToast function returns false', async () => { + mock.onGet('/fail').reply(500); + const suppressFn = (err: AxiosError) => err.response?.status === 404; + await expect( + axiosInstance.get('/fail', { suppressToast: suppressFn }), + ).rejects.toBeDefined(); + expect(globalThis.errorSpy).toHaveBeenCalled(); + }); +}); diff --git a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts index e78809aae09..919bfb92740 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts @@ -42,21 +42,34 @@ axios.interceptors.response.use((response) => response, redirectOn401()); export default axios; -export const registerErrorToastInterceptor = (axios) => { - if (sbaConfig.uiSettings.enableToasts === true) { +export const registerErrorToastInterceptor = ( + axios, + notificationCenter = nc, +) => { + if (sbaConfig.uiSettings.enableToasts) { axios.interceptors.response.use( (response) => response, (error) => { - const data = error.request; - const message = ` - Request failed: ${data.statusText}
- ${data.responseURL} + const suppress = error.config?.suppressToast; + let shouldSuppress = false; + if (typeof suppress === 'function') { + shouldSuppress = suppress(error); + } else { + shouldSuppress = !!suppress; + } + if (!shouldSuppress) { + const data = error.response; + const message = ` + Request failed: ${data?.statusText}
+ ${data?.config?.url || data?.request?.responseURL || ''} `; - nc.error(message, { - context: data.status ?? 'axios', - title: `Error ${data.status}`, - duration: 10000, - }); + notificationCenter.error(message, { + context: data?.status ?? 'axios', + title: `Error ${data?.status}`, + duration: 10000, + }); + } + return Promise.reject(error); }, ); } diff --git a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.spec.ts index 43c64902cc9..90252d3b9f7 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.spec.ts @@ -48,7 +48,7 @@ describe('DetailsCache', () => { const instance = application.instances[0]; return render(DetailsCache, { global: { - stubs, + stubs: { cacheChart: stubChart, ...stubs }, }, props: { instance, diff --git a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue index c069a3cc143..6bdfa9444de 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue +++ b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue @@ -166,10 +166,14 @@ export default { async fetchCacheHits() { if (this.shouldFetchCacheHits) { try { - const response = await this.instance.fetchMetric('cache.gets', { - name: this.cacheName, - result: 'hit', - }); + const response = await this.instance.fetchMetric( + 'cache.gets', + { + name: this.cacheName, + result: 'hit', + }, + { suppressToast: true }, + ); return response.data.measurements[0].value; } catch (error) { this.shouldFetchCacheHits = false; @@ -184,10 +188,14 @@ export default { async fetchCacheMisses() { if (this.shouldFetchCacheMisses) { try { - const response = await this.instance.fetchMetric('cache.gets', { - name: this.cacheName, - result: 'miss', - }); + const response = await this.instance.fetchMetric( + 'cache.gets', + { + name: this.cacheName, + result: 'miss', + }, + { suppressToast: true }, + ); return response.data.measurements[0].value; } catch (error) { this.shouldFetchCacheMisses = false; @@ -202,9 +210,13 @@ export default { async fetchCacheSize() { if (this.shouldFetchCacheSize) { try { - const response = await this.instance.fetchMetric('cache.size', { - name: this.cacheName, - }); + const response = await this.instance.fetchMetric( + 'cache.size', + { + name: this.cacheName, + }, + { suppressToast: true }, + ); return response.data.measurements[0].value; } catch (error) { this.shouldFetchCacheSize = false; From 51ea5a275d8a033d3351a1cd0754243915603675 Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Wed, 11 Feb 2026 08:52:43 +0100 Subject: [PATCH 2/7] #5003: Suppress toast on cache.size not found --- .../main/frontend/views/instances/details/details-cache.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue index 6bdfa9444de..4d23ab7f908 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue +++ b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue @@ -210,12 +210,13 @@ export default { async fetchCacheSize() { if (this.shouldFetchCacheSize) { try { + const suppressFn = (err) => err.response?.status === 404; const response = await this.instance.fetchMetric( 'cache.size', { name: this.cacheName, }, - { suppressToast: true }, + { suppressToast: suppressFn }, ); return response.data.measurements[0].value; } catch (error) { From b2efcdb43b4bf0107b37acc9dc706111c83b1eb9 Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Wed, 11 Feb 2026 15:10:44 +0100 Subject: [PATCH 3/7] #5003: Suppress toast only on cache.size not found --- .../views/instances/details/details-cache.vue | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue index 4d23ab7f908..377e21a4a9e 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue +++ b/spring-boot-admin-server-ui/src/main/frontend/views/instances/details/details-cache.vue @@ -166,14 +166,10 @@ export default { async fetchCacheHits() { if (this.shouldFetchCacheHits) { try { - const response = await this.instance.fetchMetric( - 'cache.gets', - { - name: this.cacheName, - result: 'hit', - }, - { suppressToast: true }, - ); + const response = await this.instance.fetchMetric('cache.gets', { + name: this.cacheName, + result: 'hit', + }); return response.data.measurements[0].value; } catch (error) { this.shouldFetchCacheHits = false; @@ -188,14 +184,10 @@ export default { async fetchCacheMisses() { if (this.shouldFetchCacheMisses) { try { - const response = await this.instance.fetchMetric( - 'cache.gets', - { - name: this.cacheName, - result: 'miss', - }, - { suppressToast: true }, - ); + const response = await this.instance.fetchMetric('cache.gets', { + name: this.cacheName, + result: 'miss', + }); return response.data.measurements[0].value; } catch (error) { this.shouldFetchCacheMisses = false; From aca0657fd061fa3f09102e78aead55967c452d55 Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Sun, 15 Feb 2026 22:25:48 +0100 Subject: [PATCH 4/7] Fixes #5003: address changes from default branch to tests --- .../main/frontend/services/instance.spec.ts | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts index b3547d52e19..c11d903b86d 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts @@ -43,12 +43,12 @@ describe('Instance', () => { ); describe('fetchMetric', () => { + const instance = new Instance({ + id: 'test-id', + registration: { name: 'test' }, + availableMetrics: ['test.metric', 'cache.size', 'cache.gets'], + }); test('should pass suppressToast option to axios config', async () => { - const instance = new Instance({ - id: 'test-id', - registration: { name: 'test' }, - }); - // Spy on axios.get const axiosGetSpy = vi.spyOn(instance.axios, 'get'); @@ -77,11 +77,6 @@ describe('Instance', () => { }); test('should work without options parameter for backward compatibility', async () => { - const instance = new Instance({ - id: 'test-id', - registration: { name: 'test' }, - }); - const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -102,11 +97,6 @@ describe('Instance', () => { }); test('should pass suppressToast=false when explicitly set to false', async () => { - const instance = new Instance({ - id: 'test-id', - registration: { name: 'test' }, - }); - const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -132,11 +122,6 @@ describe('Instance', () => { }); test('should include tags in request parameters', async () => { - const instance = new Instance({ - id: 'test-id', - registration: { name: 'test' }, - }); - const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -159,11 +144,6 @@ describe('Instance', () => { }); test('should pass suppressToast function to axios config', async () => { - const instance = new Instance({ - id: 'test-id', - registration: { name: 'test' }, - }); - const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ From 9cccc855d132634dfbdcce682a3a88aebcd046c3 Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Wed, 18 Feb 2026 15:09:32 +0100 Subject: [PATCH 5/7] Fix lint errors --- spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts index b0747df1ca6..4e5c13f307e 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { useNotificationCenter } from '@stekoe/vue-toast-notificationcenter'; -import axios, { type AxiosError, type AxiosInstance } from 'axios'; +import axios, { type AxiosError } from 'axios'; import sbaConfig from '../sba-config'; @@ -51,7 +51,7 @@ export const registerErrorToastInterceptor = ( (response) => response, (error: AxiosError) => { const suppress = error.config?.suppressToast; - let shouldSuppress = false; + let shouldSuppress: boolean; if (typeof suppress === 'function') { shouldSuppress = suppress(error); } else { From ad1b6ae886cd1d58c9d49210adb3a966dbb028df Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Fri, 6 Mar 2026 12:16:30 +0100 Subject: [PATCH 6/7] Fix npm audit --- spring-boot-admin-server-ui/package-lock.json | 361 +++++++++++------- 1 file changed, 224 insertions(+), 137 deletions(-) diff --git a/spring-boot-admin-server-ui/package-lock.json b/spring-boot-admin-server-ui/package-lock.json index 3c8be784251..a2626c2eafe 100644 --- a/spring-boot-admin-server-ui/package-lock.json +++ b/spring-boot-admin-server-ui/package-lock.json @@ -78,6 +78,7 @@ "@vue/eslint-config-typescript": "^14.0.0", "@vue/test-utils": "2.4.6", "autoprefixer": "10.4.27", + "axios-mock-adapter": "^2.1.0", "babel-loader": "10.0.0", "eslint": "^10.0.0", "eslint-config-prettier": "^10.0.0", @@ -2049,9 +2050,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz", - "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -2063,9 +2064,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz", - "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -2077,9 +2078,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", - "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -2091,9 +2092,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz", - "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -2105,9 +2106,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz", - "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -2119,9 +2120,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz", - "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -2133,9 +2134,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz", - "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -2147,9 +2148,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz", - "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -2161,9 +2162,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz", - "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -2175,9 +2176,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz", - "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -2189,9 +2190,23 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz", - "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -2203,9 +2218,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz", - "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -2217,9 +2246,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz", - "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -2231,9 +2260,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz", - "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -2245,9 +2274,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz", - "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -2259,9 +2288,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz", - "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -2273,9 +2302,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz", - "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -2286,10 +2315,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz", - "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -2301,9 +2344,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz", - "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -2315,9 +2358,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz", - "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -2328,10 +2371,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz", - "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -2731,13 +2788,13 @@ } }, "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -3934,37 +3991,24 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4425,13 +4469,13 @@ } }, "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4834,6 +4878,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-mock-adapter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-2.1.0.tgz", + "integrity": "sha512-AZUe4OjECGCNNssH8SOdtneiQELsqTsat3SQQCWLPjN436/H+L9AjWfV7bF+Zg/YL9cgbhrz5671hoh+Tbn98w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, "node_modules/babel-loader": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", @@ -6088,9 +6146,9 @@ "license": "Apache-2.0" }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6217,15 +6275,15 @@ "license": "MIT" }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -6256,13 +6314,13 @@ } }, "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7179,9 +7237,10 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -7230,13 +7289,13 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7518,9 +7577,9 @@ } }, "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, "license": "MIT" }, @@ -7692,6 +7751,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -9961,9 +10044,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", - "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -9977,27 +10060,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.2", - "@rollup/rollup-android-arm64": "4.50.2", - "@rollup/rollup-darwin-arm64": "4.50.2", - "@rollup/rollup-darwin-x64": "4.50.2", - "@rollup/rollup-freebsd-arm64": "4.50.2", - "@rollup/rollup-freebsd-x64": "4.50.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", - "@rollup/rollup-linux-arm-musleabihf": "4.50.2", - "@rollup/rollup-linux-arm64-gnu": "4.50.2", - "@rollup/rollup-linux-arm64-musl": "4.50.2", - "@rollup/rollup-linux-loong64-gnu": "4.50.2", - "@rollup/rollup-linux-ppc64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-musl": "4.50.2", - "@rollup/rollup-linux-s390x-gnu": "4.50.2", - "@rollup/rollup-linux-x64-gnu": "4.50.2", - "@rollup/rollup-linux-x64-musl": "4.50.2", - "@rollup/rollup-openharmony-arm64": "4.50.2", - "@rollup/rollup-win32-arm64-msvc": "4.50.2", - "@rollup/rollup-win32-ia32-msvc": "4.50.2", - "@rollup/rollup-win32-x64-msvc": "4.50.2", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, From 1d6592abc8bc3a25411ae89acf305cd81c02c737 Mon Sep 17 00:00:00 2001 From: ulrichschulte Date: Fri, 6 Mar 2026 14:07:24 +0100 Subject: [PATCH 7/7] #5003: Fix test setup --- .../@stekoe/vue-toast-notificationcenter.js | 15 ------ .../main/frontend/services/instance.spec.ts | 18 ++++++- .../src/main/frontend/tests/setup.ts | 51 +++++++++++++------ .../src/main/frontend/utils/axios.spec.ts | 12 ++--- .../src/main/frontend/utils/axios.ts | 4 +- 5 files changed, 61 insertions(+), 39 deletions(-) delete mode 100644 spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js diff --git a/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js b/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js deleted file mode 100644 index 6a39169d5dd..00000000000 --- a/spring-boot-admin-server-ui/src/main/frontend/__mocks__/@stekoe/vue-toast-notificationcenter.js +++ /dev/null @@ -1,15 +0,0 @@ -// __mocks__/@stekoe/vue-toast-notificationcenter.js -import { vi } from 'vitest'; - -// Ensure errorSpy is available -if (!globalThis.errorSpy) { - globalThis.errorSpy = vi.fn(); -} - -export const useNotificationCenter = () => ({ error: globalThis.errorSpy }); - -export default { - install(app) { - app.config.globalProperties.$nc = { error: globalThis.errorSpy }; - }, -}; diff --git a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts index c11d903b86d..7e7313ec653 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/services/instance.spec.ts @@ -31,6 +31,8 @@ describe('Instance', () => { const instance = new Instance({ id: 'id', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error registration: { metadata: { ['hide-url']: metadataHideUrl, @@ -45,10 +47,16 @@ describe('Instance', () => { describe('fetchMetric', () => { const instance = new Instance({ id: 'test-id', - registration: { name: 'test' }, + registration: { + name: 'test', + healthUrl: '', + source: '', + }, availableMetrics: ['test.metric', 'cache.size', 'cache.gets'], }); test('should pass suppressToast option to axios config', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error // Spy on axios.get const axiosGetSpy = vi.spyOn(instance.axios, 'get'); @@ -77,6 +85,8 @@ describe('Instance', () => { }); test('should work without options parameter for backward compatibility', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -97,6 +107,8 @@ describe('Instance', () => { }); test('should pass suppressToast=false when explicitly set to false', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -122,6 +134,8 @@ describe('Instance', () => { }); test('should include tags in request parameters', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ @@ -144,6 +158,8 @@ describe('Instance', () => { }); test('should pass suppressToast function to axios config', async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const axiosGetSpy = vi.spyOn(instance.axios, 'get'); axiosGetSpy.mockResolvedValue({ diff --git a/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts b/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts index e455d3e9f7e..ce1a06ca8cd 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/tests/setup.ts @@ -6,6 +6,36 @@ import { afterAll, afterEach, beforeAll, vi } from 'vitest'; import { server } from '@/mocks/server'; import sbaConfig from '@/sba-config'; +// Setup localStorage mock +const localStorageMock = (() => { + let store: Record = {}; + + return { + get length(): number { + return Object.keys(store).length; + }, + getItem: (key: string) => store[key] || null, + setItem: (key: string, value: string) => { + store[key] = value.toString(); + }, + removeItem: (key: string) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + }; +})(); + +Object.defineProperty(window, 'localStorage', { + value: localStorageMock, +}); + +// Setup globalThis.errorSpy for toast notifications +if (!globalThis.errorSpy) { + globalThis.errorSpy = vi.fn(); +} + global.IntersectionObserver = vi.fn().mockImplementation(function () { return { observe: vi.fn(), @@ -24,24 +54,14 @@ global.matchMedia = vi.fn().mockReturnValue({ addEventListener: vi.fn(), removeEventListener: vi.fn(), }); -global.EventSource = class { - constructor() {} - close() {} -}; +global.EventSource = vi.fn().mockImplementation(function () { + return { + close: vi.fn(), + }; +}) as unknown as typeof EventSource; global.SBA = sbaConfig; -// Mock localStorage globally for all tests -Object.defineProperty(global, 'localStorage', { - value: { - getItem: vi.fn(), - setItem: vi.fn(), - removeItem: vi.fn(), - clear: vi.fn(), - }, - writable: true, -}); - beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); afterAll(() => server.close()); afterEach(() => server.resetHandlers()); @@ -49,5 +69,6 @@ afterEach(() => server.resetHandlers()); // runs a cleanup after each test case (e.g. clearing jsdom) afterEach(() => { vi.clearAllMocks(); + localStorage.clear(); cleanup(); }); diff --git a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts index 3fa6921c2d9..e6048b92947 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.spec.ts @@ -50,11 +50,11 @@ describe('redirectOn401', () => { }); it('should not redirect on 500', async () => { - const error = { + const error: AxiosError = { response: { status: 500, }, - }; + } as AxiosError; try { await redirectOn401()(error); @@ -66,11 +66,11 @@ describe('redirectOn401', () => { }); it('should redirect on 401', async () => { - const error = { + const error: AxiosError = { response: { status: 401, }, - }; + } as AxiosError; try { await redirectOn401()(error); @@ -84,11 +84,11 @@ describe('redirectOn401', () => { }); it('should not redirect on 401 for predicate yields false', async () => { - const error = { + const error: AxiosError = { response: { status: 401, }, - }; + } as AxiosError; try { await redirectOn401(() => false)(error); diff --git a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts index 4e5c13f307e..5f6897ce76f 100644 --- a/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts +++ b/spring-boot-admin-server-ui/src/main/frontend/utils/axios.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { useNotificationCenter } from '@stekoe/vue-toast-notificationcenter'; -import axios, { type AxiosError } from 'axios'; +import axios, { type AxiosError, AxiosInstance } from 'axios'; import sbaConfig from '../sba-config'; @@ -43,7 +43,7 @@ axios.interceptors.response.use((response) => response, redirectOn401()); export default axios; export const registerErrorToastInterceptor = ( - axios, + axios: AxiosInstance, notificationCenter = nc, ) => { if (sbaConfig.uiSettings.enableToasts) {