Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f358173
temp, cursor assisted code
mgiota Nov 19, 2025
3a112f6
PR feedback: use uiActions instead of contentManegement service
mgiota Nov 19, 2025
fa77772
remove unneeded initializerContext
mgiota Nov 19, 2025
37b22ec
revert addVersion to its original format
mgiota Nov 19, 2025
14fde4a
remove dashboard service
mgiota Nov 20, 2025
66c0223
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 20, 2025
4434c0c
add unit tests
mgiota Nov 20, 2025
6fc4bb5
remove redundant tests
mgiota Nov 20, 2025
c371e46
FTR tests for related dashboards
mgiota Nov 20, 2025
9409d9c
PR feedback
mgiota Nov 20, 2025
d0265fd
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 20, 2025
90ea22c
remove tests
mgiota Nov 20, 2025
965ea23
remove duplicated comment
mgiota Nov 20, 2025
6c135d7
no need to check for details tab, edit rule opens in a page
mgiota Nov 20, 2025
014a7d8
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 20, 2025
de825f4
Changes from node scripts/lint_ts_projects --fix
kibanamachine Nov 20, 2025
c29b105
add get dashboard action
mgiota Nov 20, 2025
4ab0f20
fix eslint errors
mgiota Nov 20, 2025
b2d1fa4
fix types
mgiota Nov 20, 2025
935af17
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Nov 20, 2025
c8c41d4
fix types
mgiota Nov 20, 2025
647c29d
fix type issues
mgiota Nov 20, 2025
c8f66a5
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 21, 2025
6984f43
fix failing unit tests
mgiota Nov 21, 2025
ea666cb
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 21, 2025
1dd42e1
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Nov 21, 2025
26c9c57
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 21, 2025
0a06db7
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 21, 2025
5f540a7
PR feedback
mgiota Nov 21, 2025
6de775c
rename to getDashboardsByIds
mgiota Nov 21, 2025
1d0898d
fix failing ftr tests
mgiota Nov 21, 2025
c6f1c5d
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 23, 2025
0e7ea01
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 24, 2025
e0fa3d0
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 26, 2025
fada513
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine Nov 26, 2025
8eab8c6
pass uiActions to the synthetics context
mgiota Nov 26, 2025
fe8dd3e
add uiActions to the triggers_actions_ui plugin
mgiota Nov 26, 2025
ca2a811
fix type issues
mgiota Nov 26, 2025
fd37547
fix redundant comment
mgiota Nov 26, 2025
d2d51e0
Merge branch 'main' into fix_empty_related_dashboards
mgiota Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { DashboardsSelector } from './dashboards_selector';
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import userEvent from '@testing-library/user-event';

const MOCK_FIRST_DASHBOARD_ID = 'dashboard-1';
Expand All @@ -20,86 +20,125 @@ const MOCK_SECOND_DASHBOARD_TITLE = 'Second Dashboard';
const MOCK_PLACEHOLDER = 'Select a dashboard';

const MOCK_FIRST_DASHBOARD = {
status: 'success',
id: MOCK_FIRST_DASHBOARD_ID,
attributes: { title: MOCK_FIRST_DASHBOARD_TITLE },
references: [],
isManaged: false,
title: MOCK_FIRST_DASHBOARD_TITLE,
};

const MOCK_SECOND_DASHBOARD = {
status: 'success',
id: MOCK_SECOND_DASHBOARD_ID,
attributes: { title: MOCK_SECOND_DASHBOARD_TITLE },
references: [],
isManaged: false,
title: MOCK_SECOND_DASHBOARD_TITLE,
};

const mockFetchDashboard = jest.fn();
const mockFetchDashboards = jest
.fn()
.mockResolvedValue([MOCK_FIRST_DASHBOARD, MOCK_SECOND_DASHBOARD]);
const mockSearchExecute = jest.fn((context: any) => {
if (context.onResults) {
context.onResults([MOCK_FIRST_DASHBOARD, MOCK_SECOND_DASHBOARD]);
}
});

const mockGetByIdExecute = jest.fn((context: any) => {
if (context.onResults && context.ids) {
const requestedDashboards = context.ids
.map((id: string) => {
if (id === MOCK_FIRST_DASHBOARD_ID) return MOCK_FIRST_DASHBOARD;
if (id === MOCK_SECOND_DASHBOARD_ID) return MOCK_SECOND_DASHBOARD;
return null;
})
.filter(Boolean);
context.onResults(requestedDashboards);
}
});

// Mock the dashboard service
jest.mock('../services/dashboard_service', () => ({
dashboardServiceProvider: jest.fn(() => ({
fetchDashboards: (options: { limit: number; text: string }) => mockFetchDashboards(options),
fetchDashboard: (id: string) => mockFetchDashboard(id),
})),
}));
const mockSearchAction = {
execute: mockSearchExecute,
};

const mockGetDashboardsByIdsAction = {
execute: mockGetByIdExecute,
};

const mockGetAction = jest.fn((actionId: string) => {
if (actionId === 'getDashboardsByIdsAction') {
return Promise.resolve(mockGetDashboardsByIdsAction);
}
return Promise.resolve(mockSearchAction);
});

const mockOnChange = jest.fn();

describe('DashboardsSelector', () => {
beforeEach(() => {
mockFetchDashboard.mockResolvedValueOnce(MOCK_FIRST_DASHBOARD);
mockFetchDashboard.mockResolvedValueOnce(MOCK_SECOND_DASHBOARD);
jest.clearAllMocks();
mockGetAction.mockImplementation((actionId: string) => {
if (actionId === 'getDashboardsByIdsAction') {
return Promise.resolve(mockGetDashboardsByIdsAction);
}
return Promise.resolve(mockSearchAction);
});
mockSearchExecute.mockImplementation((context: any) => {
if (context.onResults) {
context.onResults([MOCK_FIRST_DASHBOARD, MOCK_SECOND_DASHBOARD]);
}
});
mockGetByIdExecute.mockImplementation((context: any) => {
if (context.onResults && context.ids) {
const requestedDashboards = context.ids
.map((id: string) => {
if (id === MOCK_FIRST_DASHBOARD_ID) return MOCK_FIRST_DASHBOARD;
if (id === MOCK_SECOND_DASHBOARD_ID) return MOCK_SECOND_DASHBOARD;
return null;
})
.filter(Boolean);
context.onResults(requestedDashboards);
}
});
});

afterEach(() => {
jest.clearAllMocks();
});

const contentManagement = contentManagementMock.createStartContract();
const mockUiActions = {
getAction: mockGetAction,
} as unknown as UiActionsStart;

it('renders the component', () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
/>
);

// Check that the component renders with the placeholder text
expect(screen.getByTestId('dashboardsSelector')).toBeInTheDocument();
expect(screen.getByPlaceholderText(MOCK_PLACEHOLDER)).toBeInTheDocument();
});

it('displays selected dashboard titles from dashboardsFormData', async () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[{ id: MOCK_FIRST_DASHBOARD_ID }, { id: MOCK_SECOND_DASHBOARD_ID }]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
/>
);

// Wait for the dashboard titles to be fetched and displayed
await waitFor(() => {
expect(screen.getByText(MOCK_FIRST_DASHBOARD_TITLE)).toBeInTheDocument();
expect(screen.getByText(MOCK_SECOND_DASHBOARD_TITLE)).toBeInTheDocument();
});

// Verify that fetchDashboard was called for each dashboard ID
expect(mockFetchDashboard).toHaveBeenCalledWith(MOCK_FIRST_DASHBOARD_ID);
expect(mockFetchDashboard).toHaveBeenCalledWith(MOCK_SECOND_DASHBOARD_ID);
expect(mockGetAction).toHaveBeenCalledWith('getDashboardsByIdsAction');
});

it('debounces and triggers dashboard search with user input in the ComboBox', async () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
Expand All @@ -109,13 +148,17 @@ describe('DashboardsSelector', () => {
const searchInput = screen.getByPlaceholderText(MOCK_PLACEHOLDER);
await userEvent.type(searchInput, MOCK_FIRST_DASHBOARD_TITLE);

// Assert that fetchDashboards was called with the correct search value
// Wait for the next tick to allow state update and effect to run
await waitFor(() => {
expect(searchInput).toHaveValue(MOCK_FIRST_DASHBOARD_TITLE);

expect(mockFetchDashboards).toHaveBeenCalledWith(
expect.objectContaining({ limit: 100, text: `${MOCK_FIRST_DASHBOARD_TITLE}*` })
expect(mockSearchExecute).toHaveBeenCalledWith(
expect.objectContaining({
search: {
search: MOCK_FIRST_DASHBOARD_TITLE,
per_page: 100,
},
trigger: { id: 'searchDashboards' },
})
);

expect(screen.getByText(MOCK_FIRST_DASHBOARD_TITLE)).toBeInTheDocument();
Expand All @@ -125,7 +168,7 @@ describe('DashboardsSelector', () => {
it('fetches dashboard list when combobox is focused', async () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
Expand All @@ -135,61 +178,68 @@ describe('DashboardsSelector', () => {
fireEvent.focus(searchInput);

await waitFor(() => {
expect(mockFetchDashboards).toHaveBeenCalledWith(expect.objectContaining({ limit: 100 }));
expect(mockSearchExecute).toHaveBeenCalledWith(
expect.objectContaining({
search: {
search: '',
per_page: 100,
},
})
);
});
});

it('does not fetch dashboard list when combobox is not focused', async () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
/>
);

expect(mockFetchDashboards).not.toHaveBeenCalled();
expect(mockSearchExecute).not.toHaveBeenCalled();
});

it('dispatches selected dashboards on change', async () => {
render(
<DashboardsSelector
contentManagement={contentManagement}
uiActions={mockUiActions}
dashboardsFormData={[{ id: MOCK_FIRST_DASHBOARD_ID }]}
onChange={mockOnChange}
placeholder={MOCK_PLACEHOLDER}
/>
);

// Click on the combobox to open it
const searchInput = screen.getByPlaceholderText(MOCK_PLACEHOLDER);
fireEvent.focus(searchInput);

// Wait for the dropdown to open and options to load
await waitFor(() => {
expect(mockFetchDashboards).toHaveBeenCalledWith(
expect.objectContaining({ limit: 100, text: '*' })
expect(mockSearchExecute).toHaveBeenCalled();
expect(mockSearchExecute).toHaveBeenLastCalledWith(
expect.objectContaining({
search: {
search: '',
per_page: 100,
},
})
Comment thread
cesco-f marked this conversation as resolved.
);
});

// Wait for the second dashboard option to appear in the dropdown
await waitFor(() => {
expect(screen.getByText(MOCK_SECOND_DASHBOARD_TITLE)).toBeInTheDocument();
});

// Click on the second dashboard option to select it
await userEvent.click(screen.getByText(MOCK_SECOND_DASHBOARD_TITLE));

// Verify that the onChange callback was called with both dashboards
await waitFor(() => {
expect(mockOnChange).toHaveBeenCalledWith([
{ label: MOCK_FIRST_DASHBOARD_TITLE, value: MOCK_FIRST_DASHBOARD_ID },
{ label: MOCK_SECOND_DASHBOARD_TITLE, value: MOCK_SECOND_DASHBOARD_ID },
]);
});

// Verify that both selected options are now displayed
expect(screen.getByText(MOCK_FIRST_DASHBOARD_TITLE)).toBeInTheDocument();
expect(screen.getByText(MOCK_SECOND_DASHBOARD_TITLE)).toBeInTheDocument();
});
Expand Down
Loading