2023-06-16 20:07:51 +08:00
|
|
|
import { render, screen } from '@testing-library/react';
|
|
|
|
import userEvent from '@testing-library/user-event';
|
2024-06-25 19:43:47 +08:00
|
|
|
import { ComponentProps } from 'react';
|
2023-06-16 20:07:51 +08:00
|
|
|
import tinycolor from 'tinycolor2';
|
|
|
|
|
|
|
|
import { CoreApp, createTheme, LogLevel, LogRowModel } from '@grafana/data';
|
2025-09-24 15:49:18 +08:00
|
|
|
import { mockTimeRange } from '@grafana/plugin-ui';
|
2023-06-16 20:07:51 +08:00
|
|
|
|
|
|
|
import { LogRow } from './LogRow';
|
|
|
|
import { getLogRowStyles } from './getLogRowStyles';
|
2025-07-02 15:25:25 +08:00
|
|
|
import { createLogRow } from './mocks/logRow';
|
2023-06-16 20:07:51 +08:00
|
|
|
|
2023-06-20 20:55:51 +08:00
|
|
|
const reportInteraction = jest.fn();
|
|
|
|
jest.mock('@grafana/runtime', () => ({
|
|
|
|
...jest.requireActual('@grafana/runtime'),
|
|
|
|
reportInteraction: (interactionName: string, properties?: Record<string, unknown> | undefined) =>
|
|
|
|
reportInteraction(interactionName, properties),
|
2025-06-04 15:55:08 +08:00
|
|
|
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
|
2023-06-20 20:55:51 +08:00
|
|
|
}));
|
|
|
|
|
2023-06-16 20:07:51 +08:00
|
|
|
const theme = createTheme();
|
|
|
|
const styles = getLogRowStyles(theme);
|
|
|
|
const setup = (propOverrides?: Partial<ComponentProps<typeof LogRow>>, rowOverrides?: Partial<LogRowModel>) => {
|
|
|
|
const props: ComponentProps<typeof LogRow> = {
|
|
|
|
row: createLogRow({
|
|
|
|
entry: 'test123',
|
|
|
|
uid: 'log-row-id',
|
|
|
|
logLevel: LogLevel.error,
|
|
|
|
timeEpochMs: 1546297200000,
|
|
|
|
...rowOverrides,
|
|
|
|
}),
|
|
|
|
enableLogDetails: false,
|
|
|
|
getRows: () => [],
|
|
|
|
onOpenContext: () => {},
|
2023-11-16 17:48:10 +08:00
|
|
|
handleTextSelection: jest.fn(),
|
2023-06-16 20:07:51 +08:00
|
|
|
prettifyLogMessage: false,
|
|
|
|
app: CoreApp.Explore,
|
|
|
|
showDuplicates: false,
|
|
|
|
showLabels: false,
|
|
|
|
showTime: false,
|
|
|
|
wrapLogMessage: false,
|
|
|
|
timeZone: 'utc',
|
|
|
|
styles,
|
2025-09-24 15:49:18 +08:00
|
|
|
timeRange: mockTimeRange(),
|
2023-06-16 20:07:51 +08:00
|
|
|
...(propOverrides || {}),
|
|
|
|
};
|
|
|
|
|
|
|
|
const { container } = render(
|
|
|
|
<table>
|
|
|
|
<tbody>
|
|
|
|
<LogRow {...props} />
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
);
|
|
|
|
|
|
|
|
return { props, container };
|
|
|
|
};
|
|
|
|
|
|
|
|
describe('LogRow', () => {
|
|
|
|
it('renders row entry', () => {
|
|
|
|
setup();
|
|
|
|
expect(screen.queryByText('test123')).toBeInTheDocument();
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with permalinking', () => {
|
2023-06-20 20:55:51 +08:00
|
|
|
it('reports via feature tracking when log line matches', () => {
|
|
|
|
const scrollIntoView = jest.fn();
|
2024-12-19 02:03:47 +08:00
|
|
|
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
|
2023-06-20 20:55:51 +08:00
|
|
|
expect(reportInteraction).toHaveBeenCalledWith('grafana_explore_logs_permalink_opened', {
|
|
|
|
logRowUid: 'log-row-id',
|
|
|
|
datasourceType: 'unknown',
|
|
|
|
});
|
2023-07-26 00:00:10 +08:00
|
|
|
expect(scrollIntoView).toHaveBeenCalledTimes(1);
|
2023-06-20 20:55:51 +08:00
|
|
|
});
|
|
|
|
|
2023-06-16 20:07:51 +08:00
|
|
|
it('highlights row with same permalink-id', () => {
|
2023-08-18 18:54:08 +08:00
|
|
|
const { container } = setup({
|
|
|
|
permalinkedRowId: 'log-row-id',
|
|
|
|
scrollIntoView: jest.fn(),
|
|
|
|
});
|
2023-06-16 20:07:51 +08:00
|
|
|
const row = container.querySelector('tr');
|
|
|
|
expect(row).toHaveStyle(
|
|
|
|
`background-color: ${tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString()}`
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not highlight row details with different permalink-id', async () => {
|
2023-08-18 18:54:08 +08:00
|
|
|
const { container } = setup({
|
|
|
|
permalinkedRowId: 'log-row-id',
|
|
|
|
enableLogDetails: true,
|
|
|
|
scrollIntoView: jest.fn(),
|
|
|
|
});
|
2023-06-16 20:07:51 +08:00
|
|
|
const row = container.querySelector('tr');
|
|
|
|
await userEvent.click(row!);
|
|
|
|
const allRows = container.querySelectorAll('tr');
|
|
|
|
|
|
|
|
expect(row).toHaveStyle(
|
|
|
|
`background-color: ${tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString()}`
|
|
|
|
);
|
|
|
|
expect(allRows[allRows.length - 1]).not.toHaveStyle(
|
|
|
|
`background-color: ${tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString()}`
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('not highlights row with different permalink-id', () => {
|
|
|
|
const { container } = setup({ permalinkedRowId: 'wrong-log-row-id' });
|
|
|
|
const row = container.querySelector('tr');
|
|
|
|
expect(row).not.toHaveStyle(
|
|
|
|
`background-color: ${tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString()}`
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls `scrollIntoView` if permalink matches', () => {
|
|
|
|
const scrollIntoView = jest.fn();
|
2024-12-19 02:03:47 +08:00
|
|
|
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
|
2023-06-16 20:07:51 +08:00
|
|
|
expect(scrollIntoView).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2023-07-26 00:00:10 +08:00
|
|
|
it('does not call `scrollIntoView` if permalink does not match', () => {
|
2023-06-16 20:07:51 +08:00
|
|
|
const scrollIntoView = jest.fn();
|
2024-12-19 02:03:47 +08:00
|
|
|
setup({ permalinkedRowId: 'wrong-log-row-id', scrollIntoView });
|
2023-06-16 20:07:51 +08:00
|
|
|
expect(scrollIntoView).not.toHaveBeenCalled();
|
|
|
|
});
|
2023-07-26 00:00:10 +08:00
|
|
|
|
|
|
|
it('calls `scrollIntoView` once', async () => {
|
|
|
|
const scrollIntoView = jest.fn();
|
2024-12-19 02:03:47 +08:00
|
|
|
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
|
2023-07-26 00:00:10 +08:00
|
|
|
await userEvent.hover(screen.getByText('test123'));
|
|
|
|
expect(scrollIntoView).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
2023-06-16 20:07:51 +08:00
|
|
|
});
|
2023-07-14 19:49:08 +08:00
|
|
|
|
|
|
|
it('should render the menu cell on mouse over', async () => {
|
|
|
|
setup({ showContextToggle: jest.fn().mockReturnValue(true) });
|
|
|
|
|
|
|
|
expect(screen.queryByLabelText('Show context')).not.toBeInTheDocument();
|
|
|
|
|
|
|
|
await userEvent.hover(screen.getByText('test123'));
|
|
|
|
|
|
|
|
expect(screen.getByLabelText('Show context')).toBeInTheDocument();
|
|
|
|
});
|
2023-07-17 23:20:25 +08:00
|
|
|
|
|
|
|
it('should render the menu cell on mouse over with displayed fields', async () => {
|
|
|
|
setup(
|
|
|
|
{ showContextToggle: jest.fn().mockReturnValue(true), displayedFields: ['test'] },
|
|
|
|
{ labels: { test: 'field value' } }
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(screen.queryByLabelText('Show context')).not.toBeInTheDocument();
|
|
|
|
|
|
|
|
await userEvent.hover(screen.getByText('test=field value'));
|
|
|
|
|
|
|
|
expect(screen.getByLabelText('Show context')).toBeInTheDocument();
|
|
|
|
});
|
2023-08-16 23:51:18 +08:00
|
|
|
|
|
|
|
it('should highlight the original log row when showing its context', async () => {
|
|
|
|
const { container } = setup({ showContextToggle: jest.fn().mockReturnValue(true) });
|
|
|
|
|
|
|
|
await userEvent.hover(screen.getByText('test123'));
|
|
|
|
await userEvent.click(screen.getByLabelText('Show context'));
|
|
|
|
await userEvent.unhover(screen.getByText('test123'));
|
|
|
|
|
|
|
|
const row = container.querySelector('tr');
|
|
|
|
expect(row).toHaveStyle(`background-color: ${tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString()}`);
|
|
|
|
});
|
2023-06-16 20:07:51 +08:00
|
|
|
});
|