From c76b0ce1ba24b1e60fc6769ac23fd2592f49bca3 Mon Sep 17 00:00:00 2001 From: Kishore Kumaar Natarajan Date: Fri, 31 Jan 2025 17:52:32 -0800 Subject: [PATCH 1/7] Unit test for QueryUtils, application, plugin Signed-off-by: Kishore Kumaar Natarajan --- common/utils/QueryUtils.test.ts | 47 ++++++++++++++++++++ public/application.test.tsx | 54 +++++++++++++++++++++++ public/plugin.test.tsx | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 common/utils/QueryUtils.test.ts create mode 100644 public/application.test.tsx create mode 100644 public/plugin.test.tsx diff --git a/common/utils/QueryUtils.test.ts b/common/utils/QueryUtils.test.ts new file mode 100644 index 0000000..ea67aeb --- /dev/null +++ b/common/utils/QueryUtils.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { retrieveQueryById } from './QueryUtils'; // Update with the correct path +const mockHttpGet = jest.fn(); +const mockCore = { http: { get: mockHttpGet } }; + +describe('retrieveQueryById', () => { + const dataSourceId = 'test-ds'; + const start = '2025-01-01T00:00:00Z'; + const end = '2025-01-31T23:59:59Z'; + const id = 'query-123'; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return the first top query from the fastest responding API', async () => { + mockHttpGet.mockImplementation((endpoint) => { + if (endpoint.includes('latency')) { + return Promise.resolve({ + response: { top_queries: [{ id: 'query-123', query: 'SELECT * FROM test' }] }, + }); + } + return Promise.resolve({ response: { top_queries: [] } }); + }); + + const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); + expect(result).toEqual({ id: 'query-123', query: 'SELECT * FROM test' }); + }); + + it('should return null if no top queries are found', async () => { + mockHttpGet.mockResolvedValue({ response: { top_queries: [] } }); + + const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); + expect(result).toBeNull(); + }); + + it('should handle API errors gracefully and return null', async () => { + mockHttpGet.mockRejectedValue(new Error('API error')); + + const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); + expect(result).toBeNull(); + }); +}); diff --git a/public/application.test.tsx b/public/application.test.tsx new file mode 100644 index 0000000..58a9712 --- /dev/null +++ b/public/application.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { HashRouter as Router } from 'react-router-dom'; +import * as ReactDOM from 'react-dom'; +import { renderApp } from './application'; +import { QueryInsightsDashboardsApp } from './components/app'; + +jest.mock('react-dom', () => { + const actualReactDOM = jest.requireActual('react-dom'); + return { + ...actualReactDOM, + render: jest.fn(), + unmountComponentAtNode: jest.fn(), + }; +}); +describe('renderApp', () => { + const coreMock = {}; + const depsStartMock = {}; + const paramsMock = { element: document.createElement('div') }; + const dataSourceManagementMock = {}; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should render the QueryInsightsDashboardsApp component inside Router', () => { + const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); + + expect(ReactDOM.render).toHaveBeenCalledWith( + + + , + paramsMock.element + ); + + expect(typeof unmount).toBe('function'); + }); + + it('should unmount the component when the returned function is called', () => { + const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); + unmount(); + + expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(paramsMock.element); // ✅ Corrected + }); +}); diff --git a/public/plugin.test.tsx b/public/plugin.test.tsx new file mode 100644 index 0000000..83bfbb4 --- /dev/null +++ b/public/plugin.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, CoreStart } from '../../../src/core/public'; +import { QueryInsightsDashboardsPlugin } from './plugin'; +import { PLUGIN_NAME } from '../common'; +import { renderApp } from './application'; + +jest.mock('./application', () => ({ + renderApp: jest.fn(), +})); + +describe('QueryInsightsDashboardsPlugin', () => { + let plugin: QueryInsightsDashboardsPlugin; + let coreSetupMock: jest.Mocked; + let coreStartMock: jest.Mocked; + let registerMock: jest.Mock; + let addNavLinksMock: jest.Mock; + + beforeEach(() => { + coreSetupMock = ({ + application: { + register: jest.fn(), + }, + chrome: { + navGroup: { + addNavLinksToGroup: jest.fn(), + }, + }, + getStartServices: jest.fn().mockResolvedValue([coreStartMock, {}]), + } as unknown) as jest.Mocked; + + coreStartMock = {} as jest.Mocked; + + plugin = new QueryInsightsDashboardsPlugin(); + registerMock = coreSetupMock.application.register; + addNavLinksMock = coreSetupMock.chrome.navGroup.addNavLinksToGroup; + }); + + it('should register the application in setup', () => { + plugin.setup(coreSetupMock, {} as any); + + expect(registerMock).toHaveBeenCalledWith( + expect.objectContaining({ + id: PLUGIN_NAME, + title: 'Query Insights', + }) + ); + }); + + it('should mount the application correctly', async () => { + plugin.setup(coreSetupMock, {} as any); + + const appRegistration = registerMock.mock.calls[0][0]; // Get the registered app config + expect(appRegistration).toBeDefined(); + + const paramsMock = { element: document.createElement('div') }; + const mountFunction = appRegistration.mount; + + await mountFunction(paramsMock); + + expect(renderApp).toHaveBeenCalled(); + }); + + it('should add the navigation link to nav group', () => { + plugin.setup(coreSetupMock, {} as any); + expect(addNavLinksMock).toHaveBeenCalled(); + }); + + it('should return empty start and stop methods', () => { + expect(plugin.start(coreStartMock)).toEqual({}); + expect(plugin.stop()).toBeUndefined(); + }); +}); From 88c1e3e95f42f49b78265d6cb9e99ebf6b06424a Mon Sep 17 00:00:00 2001 From: Kishore Kumaar Natarajan Date: Tue, 11 Feb 2025 17:00:53 -0800 Subject: [PATCH 2/7] Changes Signed-off-by: Kishore Kumaar Natarajan --- common/utils/QueryUtils.test.ts | 18 ++++++++++++++---- public/application.test.tsx | 2 +- public/plugin.test.tsx | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/common/utils/QueryUtils.test.ts b/common/utils/QueryUtils.test.ts index ea67aeb..60a45c3 100644 --- a/common/utils/QueryUtils.test.ts +++ b/common/utils/QueryUtils.test.ts @@ -11,24 +11,34 @@ describe('retrieveQueryById', () => { const dataSourceId = 'test-ds'; const start = '2025-01-01T00:00:00Z'; const end = '2025-01-31T23:59:59Z'; - const id = 'query-123'; + const id = '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59'; afterEach(() => { jest.clearAllMocks(); }); - it('should return the first top query from the fastest responding API', async () => { + it('should return the top query', async () => { mockHttpGet.mockImplementation((endpoint) => { if (endpoint.includes('latency')) { return Promise.resolve({ - response: { top_queries: [{ id: 'query-123', query: 'SELECT * FROM test' }] }, + response: { + top_queries: [{ + id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', + query: JSON.stringify({ match: { user_action: "login_attempt" } }) + }] + }, }); } return Promise.resolve({ response: { top_queries: [] } }); }); const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); - expect(result).toEqual({ id: 'query-123', query: 'SELECT * FROM test' }); + expect(result).toEqual({ + id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', + query: JSON.stringify( + {"match":{"user_action":"login_attempt"}} + ) + }); }); it('should return null if no top queries are found', async () => { diff --git a/public/application.test.tsx b/public/application.test.tsx index 58a9712..c7a8cce 100644 --- a/public/application.test.tsx +++ b/public/application.test.tsx @@ -49,6 +49,6 @@ describe('renderApp', () => { const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); unmount(); - expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(paramsMock.element); // ✅ Corrected + expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(paramsMock.element); }); }); diff --git a/public/plugin.test.tsx b/public/plugin.test.tsx index 83bfbb4..b4014e8 100644 --- a/public/plugin.test.tsx +++ b/public/plugin.test.tsx @@ -53,7 +53,7 @@ describe('QueryInsightsDashboardsPlugin', () => { it('should mount the application correctly', async () => { plugin.setup(coreSetupMock, {} as any); - const appRegistration = registerMock.mock.calls[0][0]; // Get the registered app config + const appRegistration = registerMock.mock.calls[0][0]; expect(appRegistration).toBeDefined(); const paramsMock = { element: document.createElement('div') }; From df9e021e9c08b2cdfa9ade0b6ac0632ee1d42f29 Mon Sep 17 00:00:00 2001 From: Kishore Kumaar Natarajan Date: Tue, 11 Feb 2025 17:13:16 -0800 Subject: [PATCH 3/7] Changes Signed-off-by: Kishore Kumaar Natarajan --- common/utils/QueryUtils.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/utils/QueryUtils.test.ts b/common/utils/QueryUtils.test.ts index 60a45c3..e861fca 100644 --- a/common/utils/QueryUtils.test.ts +++ b/common/utils/QueryUtils.test.ts @@ -22,10 +22,12 @@ describe('retrieveQueryById', () => { if (endpoint.includes('latency')) { return Promise.resolve({ response: { - top_queries: [{ - id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', - query: JSON.stringify({ match: { user_action: "login_attempt" } }) - }] + top_queries: [ + { + id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', + query: JSON.stringify({ match: { user_action: 'login_attempt' } }), + }, + ], }, }); } @@ -35,9 +37,7 @@ describe('retrieveQueryById', () => { const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); expect(result).toEqual({ id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', - query: JSON.stringify( - {"match":{"user_action":"login_attempt"}} - ) + query: JSON.stringify({ match: { user_action: 'login_attempt' } }), }); }); From 5c316890dd86e223faae1ef3068d35cb166c3913 Mon Sep 17 00:00:00 2001 From: Kishore Kumaar Natarajan Date: Tue, 18 Feb 2025 11:59:06 -0800 Subject: [PATCH 4/7] Updated QueryUtils.test.ts Signed-off-by: Kishore Kumaar Natarajan --- common/utils/QueryUtils.test.ts | 82 ++++++++++++++++++--------------- test/mocks/testConstants.ts | 10 ++++ 2 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 test/mocks/testConstants.ts diff --git a/common/utils/QueryUtils.test.ts b/common/utils/QueryUtils.test.ts index e861fca..e859fbe 100644 --- a/common/utils/QueryUtils.test.ts +++ b/common/utils/QueryUtils.test.ts @@ -3,55 +3,65 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { retrieveQueryById } from './QueryUtils'; // Update with the correct path -const mockHttpGet = jest.fn(); -const mockCore = { http: { get: mockHttpGet } }; +import { retrieveQueryById } from './QueryUtils'; +import { mockQueries } from '../../test/mocks/mockQueries'; +import { testQueryParams } from '../../test/mocks/testConstants'; -describe('retrieveQueryById', () => { - const dataSourceId = 'test-ds'; - const start = '2025-01-01T00:00:00Z'; - const end = '2025-01-31T23:59:59Z'; - const id = '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59'; +jest.unmock('../../common/utils/QueryUtils'); - afterEach(() => { +describe('retrieveQueryById - Fetch Query Record by ID from API', () => { + const mockCore = { + http: { + get: jest.fn(), + post: jest.fn(), + }, + }; + + beforeEach(() => { jest.clearAllMocks(); }); - it('should return the top query', async () => { - mockHttpGet.mockImplementation((endpoint) => { - if (endpoint.includes('latency')) { - return Promise.resolve({ - response: { - top_queries: [ - { - id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', - query: JSON.stringify({ match: { user_action: 'login_attempt' } }), - }, - ], - }, - }); - } - return Promise.resolve({ response: { top_queries: [] } }); - }); + const testStart = testQueryParams?.start; + const testEnd = testQueryParams?.end; + const testId = testQueryParams?.id; + const mockQuery = mockQueries[0]; + + const mockResponse = { + response: { + top_queries: [mockQuery], + }, + }; + + it('should make three GET requests to fetch different query records', async () => { + mockCore.http.get.mockResolvedValue(mockResponse); + + await retrieveQueryById(mockCore, undefined, testStart, testEnd, testId); - const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); - expect(result).toEqual({ - id: '1e5fde5b-c85f-419e-b8b6-3f43b3da4d59', - query: JSON.stringify({ match: { user_action: 'login_attempt' } }), + expect(mockCore.http.get).toHaveBeenCalledTimes(3); + expect(mockCore.http.get).toHaveBeenCalledWith('/api/top_queries/latency', { + query: { from: testStart, to: testEnd, id: testId, dataSourceId: undefined }, + }); + expect(mockCore.http.get).toHaveBeenCalledWith('/api/top_queries/cpu', { + query: { from: testStart, to: testEnd, id: testId, dataSourceId: undefined }, + }); + expect(mockCore.http.get).toHaveBeenCalledWith('/api/top_queries/memory', { + query: { from: testStart, to: testEnd, id: testId, dataSourceId: undefined }, }); }); - it('should return null if no top queries are found', async () => { - mockHttpGet.mockResolvedValue({ response: { top_queries: [] } }); + it('should return the valid query result', async () => { + mockCore.http.get.mockResolvedValue(mockResponse); - const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); - expect(result).toBeNull(); + const result = await retrieveQueryById(mockCore, undefined, testStart, testEnd, testId); + + expect(result).toEqual(mockResponse.response.top_queries[0]); }); - it('should handle API errors gracefully and return null', async () => { - mockHttpGet.mockRejectedValue(new Error('API error')); + it('should return null if no queries are found', async () => { + mockCore.http.get.mockResolvedValue({ response: { top_queries: [] } }); + + const result = await retrieveQueryById(mockCore, undefined, testStart, testEnd, testId); - const result = await retrieveQueryById(mockCore, dataSourceId, start, end, id); expect(result).toBeNull(); }); }); diff --git a/test/mocks/testConstants.ts b/test/mocks/testConstants.ts new file mode 100644 index 0000000..e43dfc2 --- /dev/null +++ b/test/mocks/testConstants.ts @@ -0,0 +1,10 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const testQueryParams = { + start: '2025-01-01T00:00:00Z', + end: '2025-01-31T23:59:59Z', + id: '8c1e50c035663459d567fa11d8eb494d', +}; From 83cfb208a251680882e45001fb9ed40beda2fca9 Mon Sep 17 00:00:00 2001 From: "kishore.nat98@gmail.com" Date: Tue, 18 Feb 2025 13:58:44 -0800 Subject: [PATCH 5/7] Updated Application.test.tsx Signed-off-by: kishore.nat98@gmail.com --- public/application.test.tsx | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/public/application.test.tsx b/public/application.test.tsx index c7a8cce..ffc374a 100644 --- a/public/application.test.tsx +++ b/public/application.test.tsx @@ -3,11 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; -import { HashRouter as Router } from 'react-router-dom'; import * as ReactDOM from 'react-dom'; import { renderApp } from './application'; -import { QueryInsightsDashboardsApp } from './components/app'; jest.mock('react-dom', () => { const actualReactDOM = jest.requireActual('react-dom'); @@ -27,24 +24,6 @@ describe('renderApp', () => { jest.clearAllMocks(); }); - it('should render the QueryInsightsDashboardsApp component inside Router', () => { - const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); - - expect(ReactDOM.render).toHaveBeenCalledWith( - - - , - paramsMock.element - ); - - expect(typeof unmount).toBe('function'); - }); - it('should unmount the component when the returned function is called', () => { const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); unmount(); From 9cdb9dad1cdb2eb4e2402ddd366e5649a82ebf93 Mon Sep 17 00:00:00 2001 From: "kishore.nat98@gmail.com" Date: Tue, 18 Feb 2025 23:45:57 -0800 Subject: [PATCH 6/7] Updated plugin.test.tsx Signed-off-by: kishore.nat98@gmail.com --- public/plugin.test.tsx | 56 ++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/public/plugin.test.tsx b/public/plugin.test.tsx index b4014e8..6a28242 100644 --- a/public/plugin.test.tsx +++ b/public/plugin.test.tsx @@ -6,7 +6,6 @@ import { CoreSetup, CoreStart } from '../../../src/core/public'; import { QueryInsightsDashboardsPlugin } from './plugin'; import { PLUGIN_NAME } from '../common'; -import { renderApp } from './application'; jest.mock('./application', () => ({ renderApp: jest.fn(), @@ -32,7 +31,15 @@ describe('QueryInsightsDashboardsPlugin', () => { getStartServices: jest.fn().mockResolvedValue([coreStartMock, {}]), } as unknown) as jest.Mocked; - coreStartMock = {} as jest.Mocked; + coreStartMock = ({ + http: { + get: jest.fn(), + put: jest.fn(), + }, + uiSettings: { + get: jest.fn().mockReturnValue(false), + }, + } as unknown) as jest.Mocked; plugin = new QueryInsightsDashboardsPlugin(); registerMock = coreSetupMock.application.register; @@ -46,31 +53,38 @@ describe('QueryInsightsDashboardsPlugin', () => { expect.objectContaining({ id: PLUGIN_NAME, title: 'Query Insights', + category: expect.objectContaining({ + id: expect.any(String), + label: expect.any(String), + order: expect.any(Number), + }), + order: expect.any(Number), + mount: expect.any(Function), + description: expect.any(String), }) ); }); - it('should mount the application correctly', async () => { - plugin.setup(coreSetupMock, {} as any); - - const appRegistration = registerMock.mock.calls[0][0]; - expect(appRegistration).toBeDefined(); - - const paramsMock = { element: document.createElement('div') }; - const mountFunction = appRegistration.mount; - - await mountFunction(paramsMock); - - expect(renderApp).toHaveBeenCalled(); - }); - it('should add the navigation link to nav group', () => { plugin.setup(coreSetupMock, {} as any); - expect(addNavLinksMock).toHaveBeenCalled(); - }); - it('should return empty start and stop methods', () => { - expect(plugin.start(coreStartMock)).toEqual({}); - expect(plugin.stop()).toBeUndefined(); + expect(addNavLinksMock).toHaveBeenCalledWith( + expect.objectContaining({ + id: expect.any(String), + description: expect.any(String), + }), + expect.arrayContaining([ + expect.objectContaining({ + id: 'query-insights-dashboards', + order: expect.any(Number), + category: expect.objectContaining({ + euiIconType: expect.any(String), + id: 'performance', // Adjusted to match received data + label: expect.any(String), + order: expect.any(Number), + }), + }), + ]) + ); }); }); From f79e0ebc7fa61d5b2d73c3c5a487fba15eb55519 Mon Sep 17 00:00:00 2001 From: "kishore.nat98@gmail.com" Date: Wed, 19 Feb 2025 00:38:00 -0800 Subject: [PATCH 7/7] used coremock in application.test.tsx and plugin.test.tsx Signed-off-by: kishore.nat98@gmail.com --- public/application.test.tsx | 6 ++-- public/plugin.test.tsx | 72 ++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/public/application.test.tsx b/public/application.test.tsx index ffc374a..8c2971d 100644 --- a/public/application.test.tsx +++ b/public/application.test.tsx @@ -5,6 +5,7 @@ import * as ReactDOM from 'react-dom'; import { renderApp } from './application'; +import { coreMock } from '../../../src/core/public/mocks'; jest.mock('react-dom', () => { const actualReactDOM = jest.requireActual('react-dom'); @@ -14,8 +15,9 @@ jest.mock('react-dom', () => { unmountComponentAtNode: jest.fn(), }; }); + describe('renderApp', () => { - const coreMock = {}; + const coreMockStart = coreMock.createStart(); const depsStartMock = {}; const paramsMock = { element: document.createElement('div') }; const dataSourceManagementMock = {}; @@ -25,7 +27,7 @@ describe('renderApp', () => { }); it('should unmount the component when the returned function is called', () => { - const unmount = renderApp(coreMock, depsStartMock, paramsMock, dataSourceManagementMock); + const unmount = renderApp(coreMockStart, depsStartMock, paramsMock, dataSourceManagementMock); unmount(); expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(paramsMock.element); diff --git a/public/plugin.test.tsx b/public/plugin.test.tsx index 6a28242..1fe0159 100644 --- a/public/plugin.test.tsx +++ b/public/plugin.test.tsx @@ -6,6 +6,8 @@ import { CoreSetup, CoreStart } from '../../../src/core/public'; import { QueryInsightsDashboardsPlugin } from './plugin'; import { PLUGIN_NAME } from '../common'; +import { renderApp } from './application'; +import { coreMock } from '../../../src/core/public/mocks'; jest.mock('./application', () => ({ renderApp: jest.fn(), @@ -16,34 +18,13 @@ describe('QueryInsightsDashboardsPlugin', () => { let coreSetupMock: jest.Mocked; let coreStartMock: jest.Mocked; let registerMock: jest.Mock; - let addNavLinksMock: jest.Mock; beforeEach(() => { - coreSetupMock = ({ - application: { - register: jest.fn(), - }, - chrome: { - navGroup: { - addNavLinksToGroup: jest.fn(), - }, - }, - getStartServices: jest.fn().mockResolvedValue([coreStartMock, {}]), - } as unknown) as jest.Mocked; - - coreStartMock = ({ - http: { - get: jest.fn(), - put: jest.fn(), - }, - uiSettings: { - get: jest.fn().mockReturnValue(false), - }, - } as unknown) as jest.Mocked; + coreSetupMock = coreMock.createSetup(); + coreStartMock = coreMock.createStart(); plugin = new QueryInsightsDashboardsPlugin(); registerMock = coreSetupMock.application.register; - addNavLinksMock = coreSetupMock.chrome.navGroup.addNavLinksToGroup; }); it('should register the application in setup', () => { @@ -58,33 +39,40 @@ describe('QueryInsightsDashboardsPlugin', () => { label: expect.any(String), order: expect.any(Number), }), - order: expect.any(Number), mount: expect.any(Function), + order: expect.any(Number), description: expect.any(String), }) ); }); - it('should add the navigation link to nav group', () => { + it('should mount the application correctly', async () => { plugin.setup(coreSetupMock, {} as any); - expect(addNavLinksMock).toHaveBeenCalledWith( - expect.objectContaining({ - id: expect.any(String), - description: expect.any(String), - }), - expect.arrayContaining([ - expect.objectContaining({ - id: 'query-insights-dashboards', - order: expect.any(Number), - category: expect.objectContaining({ - euiIconType: expect.any(String), - id: 'performance', // Adjusted to match received data - label: expect.any(String), - order: expect.any(Number), - }), - }), - ]) + const appRegistration = registerMock.mock.calls[0][0]; + expect(appRegistration).toBeDefined(); + + const paramsMock = { element: document.createElement('div') }; + const mountFunction = appRegistration.mount; + + await mountFunction(paramsMock); + + const depsMock = { dataSourceManagement: undefined }; + coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, depsMock]); + + await mountFunction(paramsMock); + + expect(renderApp).toHaveBeenCalledWith( + coreStartMock, + depsMock, + expect.objectContaining({ element: expect.any(HTMLElement) }), + depsMock.dataSourceManagement ); }); + + it('should return empty start and stop methods', () => { + // Ensures `start` and `stop` do not introduce unwanted behavior + expect(plugin.start(coreStartMock)).toEqual({}); + expect(plugin.stop()).toBeUndefined(); + }); });