grafana/public/app/features/logs/components/LogRow.test.tsx

167 lines
5.7 KiB
TypeScript
Raw Normal View History

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ComponentProps } from 'react';
import tinycolor from 'tinycolor2';
import { CoreApp, createTheme, LogLevel, LogRowModel } from '@grafana/data';
import { mockTimeRange } from '@grafana/plugin-ui';
import { LogRow } from './LogRow';
import { getLogRowStyles } from './getLogRowStyles';
import { createLogRow } from './mocks/logRow';
const reportInteraction = jest.fn();
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
reportInteraction: (interactionName: string, properties?: Record<string, unknown> | undefined) =>
reportInteraction(interactionName, properties),
usePluginLinks: jest.fn().mockReturnValue({ links: [] }),
}));
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: () => {},
Log Rows: Added popover menu with filter options when a log line is selected (#75306) * LogRow: detect text selection * LogRow: refactor menu as component * LogRow: add actions to menu * LogRow: hack menu position * Remove unsused imports * LogRowMessage: remove popover code * PopoverMenu: refactor * LogRows: implement PopoverMenu at log rows level * PopoverMenu: implement copy * PopoverMenu: receive row model * PopoverMenu: fix onClick capture issue * Explore: add new filter methods and props for line filters * PopoverMenu: use new filter props * Explore: separate toggleable and non toggleable filters * PopoverMenu: improve copy * ModifyQuery: extend line filter with value argument * PopoverMenu: close with escape * Remove unused import * Prettier * PopoverMenu: remove label filter options * LogRow: rename text selection handling prop * Update test * Remove unused import * Popover menu: add unit test * LogRows: update unit test * Log row: hide the log row menu if the user is selecting text * Log row: dont hide row menu if popover is not in scope * Log rows: rename state variable * Popover menu: allow menu to scroll * Log rows: fix classname prop * Log rows: close popover if mouse event comes from outside the log rows * Declare new class using object style * Fix style declaration * Logs Popover Menu: add string filtering functions (#76757) * Loki modifyQuery: add line does not contain query modification * Elastic modifyQuery: implement line filters * Modify query: change action name to not be loki specific * Prettier * Prettier * Elastic: escape filter values * Popover menu: create feature flag * Log Rows: integrate logsRowsPopoverMenu flag * Rename feature flag * Popover menu: track interactions * Prettier * logRowsPopoverMenu: update stage * Popover menu: add ds type to tracking data * Log rows: move feature flag check * Improve handle deselection
2023-11-16 17:48:10 +08:00
handleTextSelection: jest.fn(),
prettifyLogMessage: false,
app: CoreApp.Explore,
showDuplicates: false,
showLabels: false,
showTime: false,
wrapLogMessage: false,
timeZone: 'utc',
styles,
timeRange: mockTimeRange(),
...(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', () => {
it('reports via feature tracking when log line matches', () => {
const scrollIntoView = jest.fn();
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
expect(reportInteraction).toHaveBeenCalledWith('grafana_explore_logs_permalink_opened', {
logRowUid: 'log-row-id',
datasourceType: 'unknown',
});
expect(scrollIntoView).toHaveBeenCalledTimes(1);
});
it('highlights row with same permalink-id', () => {
const { container } = setup({
permalinkedRowId: 'log-row-id',
scrollIntoView: jest.fn(),
});
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 () => {
const { container } = setup({
permalinkedRowId: 'log-row-id',
enableLogDetails: true,
scrollIntoView: jest.fn(),
});
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();
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
expect(scrollIntoView).toHaveBeenCalled();
});
it('does not call `scrollIntoView` if permalink does not match', () => {
const scrollIntoView = jest.fn();
setup({ permalinkedRowId: 'wrong-log-row-id', scrollIntoView });
expect(scrollIntoView).not.toHaveBeenCalled();
});
it('calls `scrollIntoView` once', async () => {
const scrollIntoView = jest.fn();
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
await userEvent.hover(screen.getByText('test123'));
expect(scrollIntoView).toHaveBeenCalledTimes(1);
});
});
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();
});
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();
});
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()}`);
});
});