import {OrganizationFixture} from 'sentry-fixture/organization';
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
import {useLocation} from 'sentry/utils/useLocation';
import {useNavigate} from 'sentry/utils/useNavigate';
import {useSpanMetrics} from 'sentry/views/insights/common/queries/useDiscover';
import {DatabaseSystemSelector} from 'sentry/views/insights/database/components/databaseSystemSelector';
import {SpanMetricsField} from 'sentry/views/insights/types';
jest.mock('sentry/views/insights/common/queries/useDiscover', () => ({
useSpanMetrics: jest.fn(),
}));
jest.mock('sentry/utils/useLocalStorageState', () => ({
useLocalStorageState: jest.fn(),
}));
jest.mock('sentry/utils/useLocation', () => ({
useLocation: jest.fn(),
}));
jest.mock('sentry/utils/useNavigate', () => ({
useNavigate: jest.fn(),
}));
const mockUseLocalStorageState = jest.mocked(useLocalStorageState);
const mockUseSpanMetrics = jest.mocked(useSpanMetrics);
const mockUseLocation = jest.mocked(useLocation);
const mockUseNavigate = jest.mocked(useNavigate);
describe('DatabaseSystemSelector', function () {
const organization = OrganizationFixture();
afterAll(() => {
jest.clearAllMocks();
});
beforeEach(() => {
mockUseLocation.mockReturnValue({
query: {project: ['1']},
pathname: '',
search: '',
hash: '',
state: undefined,
action: 'POP',
key: '',
});
});
it('is disabled and does not select a system if there are none available', async function () {
const mockSetState = jest.fn();
mockUseLocalStorageState.mockReturnValue(['', mockSetState]);
mockUseSpanMetrics.mockReturnValue({
data: [],
isLoading: false,
isError: false,
} as any);
render(, {organization});
expect(mockSetState).not.toHaveBeenCalled();
const dropdownButton = await screen.findByRole('button');
expect(dropdownButton).toBeInTheDocument();
expect(dropdownButton).toHaveTextContent('SystemNone');
});
it('is disabled when only one database system is present and shows that system as selected', async function () {
const mockSetState = jest.fn();
mockUseLocalStorageState.mockReturnValue(['', mockSetState]);
mockUseSpanMetrics.mockReturnValue({
data: [
{
'span.system': 'postgresql',
'count()': 1000,
},
],
isLoading: false,
isError: false,
} as any);
render(, {organization});
const dropdownSelector = await screen.findByRole('button');
expect(dropdownSelector).toBeDisabled();
expect(mockSetState).toHaveBeenCalledWith('postgresql');
});
it('renders all database system options correctly', async function () {
mockUseSpanMetrics.mockReturnValue({
data: [
{
'span.system': 'postgresql',
'count()': 1000,
},
{
'span.system': 'mongodb',
'count()': 500,
},
{
'span.system': 'chungusdb',
'count()': 200,
},
],
isLoading: false,
isError: false,
} as any);
render(, {organization});
const dropdownSelector = await screen.findByRole('button');
expect(dropdownSelector).toBeEnabled();
expect(mockUseSpanMetrics).toHaveBeenCalled();
const dropdownButton = await screen.findByRole('button');
expect(dropdownButton).toBeInTheDocument();
await userEvent.click(dropdownButton);
const dropdownOptionLabels = await screen.findAllByTestId('menu-list-item-label');
expect(dropdownOptionLabels[0]).toHaveTextContent('PostgreSQL');
expect(dropdownOptionLabels[1]).toHaveTextContent('MongoDB');
// chungusdb should not be added as an option
expect(dropdownOptionLabels).toHaveLength(2);
});
it('chooses the currently selected system from localStorage', async function () {
mockUseLocalStorageState.mockReturnValue(['mongodb', () => {}]);
mockUseSpanMetrics.mockReturnValue({
data: [
{
'span.system': 'postgresql',
'count()': 1000,
},
{
'span.system': 'mongodb',
'count()': 500,
},
{
'span.system': 'chungusdb',
'count()': 200,
},
],
isLoading: false,
isError: false,
} as any);
render(, {organization});
expect(await screen.findByText('MongoDB')).toBeInTheDocument();
});
it('does not set the value from localStorage if the value is invalid', async function () {
const mockSetState = jest.fn();
mockUseLocalStorageState.mockReturnValue(['chungusdb', mockSetState]);
mockUseSpanMetrics.mockReturnValue({
data: [
{
'span.system': 'postgresql',
'count()': 1000,
},
],
isLoading: false,
isError: false,
} as any);
render(, {organization});
const dropdownSelector = await screen.findByRole('button');
expect(dropdownSelector).toBeInTheDocument();
expect(mockSetState).not.toHaveBeenCalledWith('chungusdb');
});
it('prioritizes the system set in query parameters but does not replace localStorage value until an option is clicked', async function () {
const {SPAN_SYSTEM} = SpanMetricsField;
const mockNavigate = jest.fn();
mockUseNavigate.mockReturnValue(mockNavigate);
mockUseLocation.mockReturnValue({
query: {project: ['1'], [SPAN_SYSTEM]: 'mongodb'},
pathname: '',
search: '',
hash: '',
state: undefined,
action: 'POP',
key: '',
});
mockUseSpanMetrics.mockReturnValue({
data: [
{
'span.system': 'postgresql',
'count()': 1000,
},
{
'span.system': 'mongodb',
'count()': 500,
},
],
isLoading: false,
isError: false,
} as any);
const mockSetState = jest.fn();
mockUseLocalStorageState.mockReturnValue(['postgresql', mockSetState]);
render(, {organization});
const dropdownSelector = await screen.findByRole('button');
expect(dropdownSelector).toHaveTextContent('SystemMongoDB');
expect(mockSetState).not.toHaveBeenCalledWith('mongodb');
// Now that it has been confirmed that following a URL does not reset localStorage state, confirm that
// clicking a different option will update both the state and the URL
await userEvent.click(dropdownSelector);
const dropdownOptionLabels = await screen.findAllByTestId('menu-list-item-label');
expect(dropdownOptionLabels[0]).toHaveTextContent('PostgreSQL');
expect(dropdownOptionLabels[1]).toHaveTextContent('MongoDB');
await userEvent.click(dropdownOptionLabels[0]);
expect(dropdownSelector).toHaveTextContent('SystemPostgreSQL');
expect(mockSetState).toHaveBeenCalledWith('postgresql');
expect(mockNavigate).toHaveBeenCalledWith({
action: 'POP',
hash: '',
key: '',
pathname: '',
query: {project: ['1'], 'span.system': 'postgresql'},
search: '',
state: undefined,
});
});
});