Skip to content

Commit fa97e63

Browse files
fix: added test cases for exportoption wrapper and export function (#9321)
1 parent c8419c1 commit fa97e63

File tree

1 file changed

+363
-0
lines changed

1 file changed

+363
-0
lines changed
Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
import { PANEL_TYPES } from 'constants/queryBuilder';
2+
import { MOCK_QUERY } from 'container/QueryTable/Drilldown/__tests__/mockTableData';
3+
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
4+
import { rest, server } from 'mocks-server/server';
5+
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
6+
import { Dashboard } from 'types/api/dashboard/getAll';
7+
import { Query } from 'types/api/queryBuilder/queryBuilderData';
8+
import { DataSource } from 'types/common/queryBuilder';
9+
import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToDashboardLink';
10+
import { v4 } from 'uuid';
11+
12+
import ExplorerOptionWrapper from '../ExplorerOptionWrapper';
13+
import { getExplorerToolBarVisibility } from '../utils';
14+
15+
// Mock dependencies
16+
jest.mock('hooks/dashboard/useUpdateDashboard');
17+
18+
jest.mock('../utils', () => ({
19+
getExplorerToolBarVisibility: jest.fn(),
20+
generateRGBAFromHex: jest.fn(() => 'rgba(0, 0, 0, 0.08)'),
21+
getRandomColor: jest.fn(() => '#000000'),
22+
saveNewViewHandler: jest.fn(),
23+
setExplorerToolBarVisibility: jest.fn(),
24+
DATASOURCE_VS_ROUTES: {},
25+
}));
26+
27+
const mockGetExplorerToolBarVisibility = jest.mocked(
28+
getExplorerToolBarVisibility,
29+
);
30+
31+
const mockUseUpdateDashboard = jest.mocked(useUpdateDashboard);
32+
33+
// Mock data
34+
const TEST_QUERY_ID = 'test-query-id';
35+
const TEST_DASHBOARD_ID = 'test-dashboard-id';
36+
const TEST_DASHBOARD_TITLE = 'Test Dashboard';
37+
const TEST_DASHBOARD_DESCRIPTION = 'Test Description';
38+
const TEST_TIMESTAMP = '2023-01-01T00:00:00Z';
39+
const TEST_DASHBOARD_TITLE_2 = 'Test Dashboard for Export';
40+
const NEW_DASHBOARD_ID = 'new-dashboard-id';
41+
const DASHBOARDS_API_ENDPOINT = '*/api/v1/dashboards';
42+
43+
// Use the existing mock query from the codebase
44+
const mockQuery: Query = {
45+
...MOCK_QUERY,
46+
id: TEST_QUERY_ID, // Override with our test ID
47+
} as Query;
48+
49+
const createMockDashboard = (id: string = TEST_DASHBOARD_ID): Dashboard => ({
50+
id,
51+
data: {
52+
title: TEST_DASHBOARD_TITLE,
53+
description: TEST_DASHBOARD_DESCRIPTION,
54+
tags: [],
55+
layout: [],
56+
variables: {},
57+
},
58+
createdAt: TEST_TIMESTAMP,
59+
updatedAt: TEST_TIMESTAMP,
60+
createdBy: 'test-user',
61+
updatedBy: 'test-user',
62+
});
63+
64+
const ADD_TO_DASHBOARD_BUTTON_NAME = /add to dashboard/i;
65+
66+
// Helper function to render component with props
67+
const renderExplorerOptionWrapper = (
68+
overrides = {},
69+
): ReturnType<typeof render> => {
70+
const props = {
71+
disabled: false,
72+
query: mockQuery,
73+
isLoading: false,
74+
onExport: jest.fn() as jest.MockedFunction<
75+
(
76+
dashboard: Dashboard | null,
77+
isNewDashboard?: boolean,
78+
queryToExport?: Query,
79+
) => void
80+
>,
81+
sourcepage: DataSource.LOGS,
82+
isOneChartPerQuery: false,
83+
splitedQueries: [],
84+
signalSource: 'test-signal',
85+
...overrides,
86+
};
87+
88+
return render(
89+
<ExplorerOptionWrapper
90+
disabled={props.disabled}
91+
query={props.query}
92+
isLoading={props.isLoading}
93+
onExport={props.onExport}
94+
sourcepage={props.sourcepage}
95+
isOneChartPerQuery={props.isOneChartPerQuery}
96+
splitedQueries={props.splitedQueries}
97+
signalSource={props.signalSource}
98+
/>,
99+
);
100+
};
101+
102+
describe('ExplorerOptionWrapper', () => {
103+
beforeEach(() => {
104+
jest.clearAllMocks();
105+
mockGetExplorerToolBarVisibility.mockReturnValue(true);
106+
107+
// Mock useUpdateDashboard to return a mutation object
108+
mockUseUpdateDashboard.mockReturnValue(({
109+
mutate: jest.fn(),
110+
mutateAsync: jest.fn(),
111+
isLoading: false,
112+
isError: false,
113+
isSuccess: false,
114+
data: undefined,
115+
error: null,
116+
reset: jest.fn(),
117+
} as unknown) as ReturnType<typeof useUpdateDashboard>);
118+
});
119+
120+
describe('onExport functionality', () => {
121+
it('should call onExport when New Dashboard button is clicked in export modal', async () => {
122+
const user = userEvent.setup({ pointerEventsCheck: 0 });
123+
const testOnExport = jest.fn() as jest.MockedFunction<
124+
(
125+
dashboard: Dashboard | null,
126+
isNewDashboard?: boolean,
127+
queryToExport?: Query,
128+
) => void
129+
>;
130+
131+
// Mock the dashboard creation API
132+
const mockNewDashboard = createMockDashboard(NEW_DASHBOARD_ID);
133+
server.use(
134+
rest.post(DASHBOARDS_API_ENDPOINT, (_req, res, ctx) =>
135+
res(ctx.status(200), ctx.json({ data: mockNewDashboard })),
136+
),
137+
);
138+
139+
renderExplorerOptionWrapper({
140+
onExport: testOnExport,
141+
});
142+
143+
// Find and click the "Add to Dashboard" button
144+
const addToDashboardButton = screen.getByRole('button', {
145+
name: ADD_TO_DASHBOARD_BUTTON_NAME,
146+
});
147+
await user.click(addToDashboardButton);
148+
149+
// Wait for the export modal to appear
150+
await waitFor(() => {
151+
expect(screen.getByRole('dialog')).toBeInTheDocument();
152+
});
153+
154+
// Click the "New Dashboard" button
155+
const newDashboardButton = screen.getByRole('button', {
156+
name: /new dashboard/i,
157+
});
158+
await user.click(newDashboardButton);
159+
160+
// Wait for the API call to complete and onExport to be called
161+
await waitFor(() => {
162+
expect(testOnExport).toHaveBeenCalledWith(mockNewDashboard, true);
163+
});
164+
});
165+
166+
it('should call onExport when selecting existing dashboard and clicking Export button', async () => {
167+
const user = userEvent.setup({ pointerEventsCheck: 0 });
168+
const testOnExport = jest.fn() as jest.MockedFunction<
169+
(
170+
dashboard: Dashboard | null,
171+
isNewDashboard?: boolean,
172+
queryToExport?: Query,
173+
) => void
174+
>;
175+
176+
// Mock existing dashboards with unique titles
177+
const mockDashboard1 = createMockDashboard('dashboard-1');
178+
mockDashboard1.data.title = 'Dashboard 1';
179+
const mockDashboard2 = createMockDashboard('dashboard-2');
180+
mockDashboard2.data.title = 'Dashboard 2';
181+
const mockDashboards = [mockDashboard1, mockDashboard2];
182+
183+
server.use(
184+
rest.get(DASHBOARDS_API_ENDPOINT, (_req, res, ctx) =>
185+
res(ctx.status(200), ctx.json({ data: mockDashboards })),
186+
),
187+
);
188+
189+
renderExplorerOptionWrapper({
190+
onExport: testOnExport,
191+
});
192+
193+
// Find and click the "Add to Dashboard" button
194+
const addToDashboardButton = screen.getByRole('button', {
195+
name: ADD_TO_DASHBOARD_BUTTON_NAME,
196+
});
197+
await user.click(addToDashboardButton);
198+
199+
// Wait for the export modal to appear
200+
await waitFor(() => {
201+
expect(screen.getByRole('dialog')).toBeInTheDocument();
202+
});
203+
204+
// Wait for dashboards to load and then click on the dashboard select dropdown
205+
await waitFor(() => {
206+
expect(screen.getByText('Select Dashboard')).toBeInTheDocument();
207+
});
208+
209+
// Get the modal and find the dashboard select dropdown within it
210+
const modal = screen.getByRole('dialog');
211+
const dashboardSelect = modal.querySelector(
212+
'[role="combobox"]',
213+
) as HTMLElement;
214+
expect(dashboardSelect).toBeInTheDocument();
215+
await user.click(dashboardSelect);
216+
217+
// Wait for the dropdown options to appear and select the first dashboard
218+
await waitFor(() => {
219+
expect(screen.getByText(mockDashboard1.data.title)).toBeInTheDocument();
220+
});
221+
222+
// Click on the first dashboard option
223+
const dashboardOption = screen.getByText(mockDashboard1.data.title);
224+
await user.click(dashboardOption);
225+
226+
// Wait for the selection to be made and the Export button to be enabled
227+
await waitFor(() => {
228+
const exportButton = screen.getByRole('button', { name: /export/i });
229+
expect(exportButton).not.toBeDisabled();
230+
});
231+
232+
// Click the Export button
233+
const exportButton = screen.getByRole('button', { name: /export/i });
234+
await user.click(exportButton);
235+
236+
// Wait for onExport to be called with the selected dashboard
237+
await waitFor(() => {
238+
expect(testOnExport).toHaveBeenCalledWith(mockDashboard1, false);
239+
});
240+
});
241+
242+
it('should test actual handleExport function with generateExportToDashboardLink and verify useUpdateDashboard is NOT called', async () => {
243+
const user = userEvent.setup({ pointerEventsCheck: 0 });
244+
245+
// Mock the safeNavigate function
246+
const mockSafeNavigate = jest.fn();
247+
248+
// Get the mock mutate function to track calls
249+
const mockMutate = mockUseUpdateDashboard().mutate as jest.MockedFunction<
250+
(...args: unknown[]) => void
251+
>;
252+
253+
const panelTypeParam = PANEL_TYPES.TIME_SERIES;
254+
const widgetId = v4();
255+
const query = mockQuery;
256+
257+
// Create a real handleExport function similar to LogsExplorerViews
258+
// This should NOT call useUpdateDashboard (as per PR #8029)
259+
const handleExport = (dashboard: Dashboard | null): void => {
260+
if (!dashboard) return;
261+
262+
// Call the actual generateExportToDashboardLink function (not mocked)
263+
const dashboardEditView = generateExportToDashboardLink({
264+
query,
265+
panelType: panelTypeParam,
266+
dashboardId: dashboard.id,
267+
widgetId,
268+
});
269+
270+
// Simulate navigation
271+
mockSafeNavigate(dashboardEditView);
272+
};
273+
274+
// Mock existing dashboards
275+
const mockDashboard = createMockDashboard('test-dashboard-id');
276+
mockDashboard.data.title = TEST_DASHBOARD_TITLE_2;
277+
278+
server.use(
279+
rest.get(DASHBOARDS_API_ENDPOINT, (_req, res, ctx) =>
280+
res(ctx.status(200), ctx.json({ data: [mockDashboard] })),
281+
),
282+
);
283+
284+
renderExplorerOptionWrapper({
285+
onExport: handleExport,
286+
});
287+
288+
// Find and click the "Add to Dashboard" button
289+
const addToDashboardButton = screen.getByRole('button', {
290+
name: ADD_TO_DASHBOARD_BUTTON_NAME,
291+
});
292+
await user.click(addToDashboardButton);
293+
294+
// Wait for the export modal to appear
295+
await waitFor(() => {
296+
expect(screen.getByRole('dialog')).toBeInTheDocument();
297+
});
298+
299+
// Wait for dashboards to load and then click on the dashboard select dropdown
300+
await waitFor(() => {
301+
expect(screen.getByText('Select Dashboard')).toBeInTheDocument();
302+
});
303+
304+
// Get the modal and find the dashboard select dropdown within it
305+
const modal = screen.getByRole('dialog');
306+
const dashboardSelect = modal.querySelector(
307+
'[role="combobox"]',
308+
) as HTMLElement;
309+
expect(dashboardSelect).toBeInTheDocument();
310+
await user.click(dashboardSelect);
311+
312+
// Wait for the dropdown options to appear and select the dashboard
313+
await waitFor(() => {
314+
expect(screen.getByText(mockDashboard.data.title)).toBeInTheDocument();
315+
});
316+
317+
// Click on the dashboard option
318+
const dashboardOption = screen.getByText(mockDashboard.data.title);
319+
await user.click(dashboardOption);
320+
321+
// Wait for the selection to be made and the Export button to be enabled
322+
await waitFor(() => {
323+
const exportButton = screen.getByRole('button', { name: /export/i });
324+
expect(exportButton).not.toBeDisabled();
325+
});
326+
327+
// Click the Export button
328+
const exportButton = screen.getByRole('button', { name: /export/i });
329+
await user.click(exportButton);
330+
331+
// Wait for the handleExport function to be called and navigation to occur
332+
await waitFor(() => {
333+
expect(mockSafeNavigate).toHaveBeenCalledTimes(1);
334+
expect(mockSafeNavigate).toHaveBeenCalledWith(
335+
`/dashboard/test-dashboard-id/new?graphType=${panelTypeParam}&widgetId=${widgetId}&compositeQuery=${encodeURIComponent(
336+
JSON.stringify(query),
337+
)}`,
338+
);
339+
});
340+
341+
// Assert that useUpdateDashboard was NOT called (as per PR #8029)
342+
expect(mockMutate).not.toHaveBeenCalled();
343+
});
344+
345+
it('should not show export buttons when component is disabled', () => {
346+
const testOnExport = jest.fn() as jest.MockedFunction<
347+
(
348+
dashboard: Dashboard | null,
349+
isNewDashboard?: boolean,
350+
queryToExport?: Query,
351+
) => void
352+
>;
353+
354+
renderExplorerOptionWrapper({ disabled: true, onExport: testOnExport });
355+
356+
// The "Add to Dashboard" button should be disabled
357+
const addToDashboardButton = screen.getByRole('button', {
358+
name: ADD_TO_DASHBOARD_BUTTON_NAME,
359+
});
360+
expect(addToDashboardButton).toBeDisabled();
361+
});
362+
});
363+
});

0 commit comments

Comments
 (0)