835 lines
25 KiB
TypeScript
835 lines
25 KiB
TypeScript
import { render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { ComponentProps } from 'react';
|
|
import { DatasourceSrvMock, MockDataSourceApi } from 'test/mocks/datasource_srv';
|
|
|
|
import {
|
|
LoadingState,
|
|
createDataFrame,
|
|
FieldType,
|
|
LogsSortOrder,
|
|
CoreApp,
|
|
getDefaultTimeRange,
|
|
LogsDedupStrategy,
|
|
EventBusSrv,
|
|
DataFrameType,
|
|
LogSortOrderChangeEvent,
|
|
} from '@grafana/data';
|
|
import { getAppEvents } from '@grafana/runtime';
|
|
import * as grafanaUI from '@grafana/ui';
|
|
import * as styles from 'app/features/logs/components/getLogRowStyles';
|
|
import { LogRowContextModal } from 'app/features/logs/components/log-context/LogRowContextModal';
|
|
|
|
import { LogsPanel } from './LogsPanel';
|
|
|
|
type LogsPanelProps = ComponentProps<typeof LogsPanel>;
|
|
type LogRowContextModalProps = ComponentProps<typeof LogRowContextModal>;
|
|
|
|
const logRowContextModalMock = jest.fn().mockReturnValue(<div>LogRowContextModal</div>);
|
|
jest.mock('app/features/logs/components/log-context/LogRowContextModal', () => ({
|
|
LogRowContextModal: (props: LogRowContextModalProps) => logRowContextModalMock(props),
|
|
}));
|
|
|
|
const defaultDs = new MockDataSourceApi('default datasource', { data: ['default data'] });
|
|
const noShowContextDs = new MockDataSourceApi('no-show-context');
|
|
const showContextDs = new MockDataSourceApi('show-context') as MockDataSourceApi & { getLogRowContext: jest.Mock };
|
|
|
|
const datasourceSrv = new DatasourceSrvMock(defaultDs, {
|
|
'no-show-context': noShowContextDs,
|
|
'show-context': showContextDs,
|
|
});
|
|
const getDataSourceSrvMock = jest.fn().mockReturnValue(datasourceSrv);
|
|
jest.mock('@grafana/runtime', () => ({
|
|
...jest.requireActual('@grafana/runtime'),
|
|
getAppEvents: jest.fn(),
|
|
getDataSourceSrv: () => getDataSourceSrvMock(),
|
|
}));
|
|
|
|
const hasLogsContextSupport = jest.fn().mockImplementation((ds) => {
|
|
if (!ds) {
|
|
return false;
|
|
}
|
|
return ds.name === 'show-context';
|
|
});
|
|
jest.mock('@grafana/data', () => ({
|
|
...jest.requireActual('@grafana/data'),
|
|
hasLogsContextSupport: (ds: MockDataSourceApi) => hasLogsContextSupport(ds),
|
|
}));
|
|
|
|
const defaultProps = {
|
|
data: {
|
|
error: undefined,
|
|
request: {
|
|
panelId: 4,
|
|
app: 'dashboard',
|
|
requestId: 'A',
|
|
timezone: 'browser',
|
|
interval: '30s',
|
|
intervalMs: 30000,
|
|
maxDataPoints: 823,
|
|
targets: [],
|
|
range: getDefaultTimeRange(),
|
|
scopedVars: {},
|
|
startTime: 1,
|
|
},
|
|
series: [
|
|
createDataFrame({
|
|
refId: 'A',
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: ['logline text'],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
],
|
|
state: LoadingState.Done,
|
|
timeRange: getDefaultTimeRange(),
|
|
},
|
|
timeZone: 'utc',
|
|
timeRange: getDefaultTimeRange(),
|
|
options: {
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: false,
|
|
showLogContextToggle: false,
|
|
},
|
|
title: 'Logs panel',
|
|
id: 1,
|
|
transparent: false,
|
|
width: 400,
|
|
height: 100,
|
|
renderCounter: 0,
|
|
fieldConfig: {
|
|
defaults: {},
|
|
overrides: [],
|
|
},
|
|
eventBus: new EventBusSrv(),
|
|
onOptionsChange: jest.fn(),
|
|
onFieldConfigChange: jest.fn(),
|
|
replaceVariables: jest.fn(),
|
|
onChangeTimeRange: jest.fn(),
|
|
};
|
|
|
|
const publishMock = jest.fn();
|
|
beforeAll(() => {
|
|
jest.mocked(getAppEvents).mockReturnValue({
|
|
publish: publishMock,
|
|
getStream: jest.fn(),
|
|
subscribe: jest.fn(),
|
|
removeAllListeners: jest.fn(),
|
|
newScopedBus: jest.fn(),
|
|
});
|
|
});
|
|
|
|
describe('LogsPanel', () => {
|
|
it('publishes an event with the current sort order', async () => {
|
|
publishMock.mockClear();
|
|
setup();
|
|
|
|
await screen.findByText('logline text');
|
|
|
|
expect(publishMock).toHaveBeenCalledTimes(1);
|
|
expect(publishMock).toHaveBeenCalledWith(
|
|
new LogSortOrderChangeEvent({
|
|
order: LogsSortOrder.Descending,
|
|
})
|
|
);
|
|
});
|
|
|
|
describe('when returned series include common labels', () => {
|
|
const seriesWithCommonLabels = [
|
|
createDataFrame({
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: [
|
|
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
|
|
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
|
|
],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
job: 'common_job',
|
|
},
|
|
{
|
|
app: 'common_app',
|
|
job: 'common_job',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
|
|
it('shows common labels when showCommonLabels is set to true', async () => {
|
|
setup({
|
|
data: { ...defaultProps.data, series: seriesWithCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: true },
|
|
});
|
|
|
|
expect(await screen.findByText(/common labels:/i)).toBeInTheDocument();
|
|
expect(await screen.findByText(/common_app/i)).toBeInTheDocument();
|
|
expect(await screen.findByText(/common_job/i)).toBeInTheDocument();
|
|
});
|
|
it('shows common labels on top when descending sort order', async () => {
|
|
const { container } = setup({
|
|
data: { ...defaultProps.data, series: seriesWithCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: true, sortOrder: LogsSortOrder.Descending },
|
|
});
|
|
expect(await screen.findByText(/common labels:/i)).toBeInTheDocument();
|
|
expect(container.firstChild?.childNodes[0].textContent).toMatch(/^Common labels:app=common_appjob=common_job/);
|
|
});
|
|
it('shows common labels on bottom when ascending sort order', async () => {
|
|
const { container } = setup({
|
|
data: { ...defaultProps.data, series: seriesWithCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: true, sortOrder: LogsSortOrder.Ascending },
|
|
});
|
|
expect(await screen.findByText(/common labels:/i)).toBeInTheDocument();
|
|
expect(container.firstChild?.childNodes[0].textContent).toMatch(/Common labels:app=common_appjob=common_job$/);
|
|
});
|
|
it('does not show common labels when showCommonLabels is set to false', async () => {
|
|
setup({
|
|
data: { ...defaultProps.data, series: seriesWithCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: false },
|
|
});
|
|
|
|
await waitFor(async () => {
|
|
expect(screen.queryByText(/common labels:/i)).toBeNull();
|
|
expect(screen.queryByText(/common_app/i)).toBeNull();
|
|
expect(screen.queryByText(/common_job/i)).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
describe('when returned series does not include common labels', () => {
|
|
const seriesWithoutCommonLabels = [
|
|
createDataFrame({
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: [
|
|
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
|
|
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
it('shows (no common labels) when showCommonLabels is set to true', async () => {
|
|
setup({
|
|
data: { ...defaultProps.data, series: seriesWithoutCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: true },
|
|
});
|
|
|
|
expect(await screen.findByText(/common labels:/i)).toBeInTheDocument();
|
|
expect(await screen.findByText(/(no common labels)/i)).toBeInTheDocument();
|
|
});
|
|
it('does not show common labels when showCommonLabels is set to false', async () => {
|
|
setup({
|
|
data: { ...defaultProps.data, series: seriesWithoutCommonLabels },
|
|
options: { ...defaultProps.options, showCommonLabels: false },
|
|
});
|
|
await waitFor(async () => {
|
|
expect(screen.queryByText(/common labels:/i)).toBeNull();
|
|
expect(screen.queryByText(/(no common labels)/i)).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('log context', () => {
|
|
const series = [
|
|
createDataFrame({
|
|
refId: 'A',
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: ['logline text', 'more text'],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
job: 'common_job',
|
|
},
|
|
{
|
|
app: 'common_app',
|
|
job: 'common_job',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
|
|
beforeEach(() => {
|
|
showContextDs.getLogRowContext = jest.fn().mockImplementation(() => {});
|
|
});
|
|
|
|
it('should not show the toggle if the datasource does not support show context', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
request: {
|
|
...defaultProps.data.request,
|
|
app: CoreApp.Dashboard,
|
|
targets: [{ refId: 'A', datasource: { uid: 'no-show-context' } }],
|
|
},
|
|
},
|
|
});
|
|
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
expect(screen.queryByLabelText(/show context/i)).toBeNull();
|
|
});
|
|
});
|
|
|
|
it('should show the toggle if the datasource does support show context', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
request: {
|
|
...defaultProps.data.request,
|
|
app: CoreApp.Dashboard,
|
|
targets: [{ refId: 'A', datasource: { uid: 'show-context' } }],
|
|
},
|
|
},
|
|
});
|
|
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
expect(screen.getByLabelText(/show context/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it('should not show the toggle if the datasource does support show context but the app is not Dashboard', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
request: {
|
|
...defaultProps.data.request,
|
|
app: CoreApp.CloudAlerting,
|
|
targets: [{ refId: 'A', datasource: { uid: 'show-context' } }],
|
|
},
|
|
},
|
|
});
|
|
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
expect(screen.queryByLabelText(/show context/i)).toBeNull();
|
|
});
|
|
});
|
|
|
|
it('should render the mocked `LogRowContextModal` after click', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
request: {
|
|
...defaultProps.data.request,
|
|
app: CoreApp.Dashboard,
|
|
targets: [{ refId: 'A', datasource: { uid: 'show-context' } }],
|
|
},
|
|
},
|
|
});
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
await userEvent.click(screen.getByLabelText(/show context/i));
|
|
expect(screen.getByText(/LogRowContextModal/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it('should call `getLogRowContext` if the user clicks the show context toggle', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
request: {
|
|
...defaultProps.data.request,
|
|
app: CoreApp.Dashboard,
|
|
targets: [{ refId: 'A', datasource: { uid: 'show-context' } }],
|
|
},
|
|
},
|
|
});
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
await userEvent.click(screen.getByLabelText(/show context/i));
|
|
|
|
const getRowContextCb = logRowContextModalMock.mock.calls[0][0].getRowContext;
|
|
getRowContextCb({}, {});
|
|
expect(showContextDs.getLogRowContext).toBeCalled();
|
|
});
|
|
});
|
|
|
|
it('supports adding custom options to the log row menu', async () => {
|
|
const logRowMenuIconsBefore = [
|
|
<grafanaUI.IconButton name="eye-slash" tooltip="Addon before" aria-label="Addon before" key={1} />,
|
|
];
|
|
const logRowMenuIconsAfter = [
|
|
<grafanaUI.IconButton name="rss" tooltip="Addon after" aria-label="Addon after" key={1} />,
|
|
];
|
|
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
logRowMenuIconsBefore,
|
|
logRowMenuIconsAfter,
|
|
},
|
|
});
|
|
|
|
await waitFor(async () => {
|
|
await userEvent.hover(screen.getByText(/logline text/i));
|
|
expect(screen.getByLabelText('Addon before')).toBeInTheDocument();
|
|
expect(screen.getByLabelText('Addon after')).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Performance regressions', () => {
|
|
const series = [
|
|
createDataFrame({
|
|
refId: 'A',
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: ['logline text'],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
job: 'common_job',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
|
|
beforeEach(() => {
|
|
/**
|
|
* For the lack of a better option, we spy on getLogRowStyles calls to count re-renders.
|
|
*/
|
|
jest.spyOn(styles, 'getLogRowStyles');
|
|
jest.mocked(styles.getLogRowStyles).mockClear();
|
|
});
|
|
|
|
it('does not rerender without changes', async () => {
|
|
const { rerender, props } = setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
rerender(<LogsPanel {...props} />);
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
expect(styles.getLogRowStyles).toHaveBeenCalledTimes(3);
|
|
});
|
|
|
|
it('rerenders when prop changes', async () => {
|
|
const { rerender, props } = setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
rerender(<LogsPanel {...props} data={{ ...props.data, series: [...series] }} />);
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
expect(jest.mocked(styles.getLogRowStyles).mock.calls.length).toBeGreaterThan(3);
|
|
});
|
|
|
|
it('does not re-render when data is loading', async () => {
|
|
const { rerender, props } = setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
rerender(<LogsPanel {...props} data={{ ...props.data, state: LoadingState.Loading }} />);
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
expect(styles.getLogRowStyles).toHaveBeenCalledTimes(3);
|
|
});
|
|
});
|
|
|
|
describe('Filters', () => {
|
|
const series = [
|
|
createDataFrame({
|
|
refId: 'A',
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: ['logline text'],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
|
|
it('allows to filter for a value or filter out a value', async () => {
|
|
const filterForMock = jest.fn();
|
|
const filterOutMock = jest.fn();
|
|
const isFilterLabelActiveMock = jest.fn();
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: true,
|
|
onClickFilterLabel: filterForMock,
|
|
onClickFilterOutLabel: filterOutMock,
|
|
isFilterLabelActive: isFilterLabelActiveMock,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('logline text'));
|
|
await userEvent.click(screen.getByLabelText('Filter for value'));
|
|
expect(filterForMock).toHaveBeenCalledTimes(1);
|
|
await userEvent.click(screen.getByLabelText('Filter out value'));
|
|
expect(filterOutMock).toHaveBeenCalledTimes(1);
|
|
|
|
expect(isFilterLabelActiveMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
describe('invalid handlers', () => {
|
|
it('does not show the controls if onAddAdHocFilter is not defined', async () => {
|
|
jest.spyOn(grafanaUI, 'usePanelContext').mockReturnValue({
|
|
eventsScope: 'global',
|
|
eventBus: new EventBusSrv(),
|
|
});
|
|
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
enableLogDetails: true,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('logline text'));
|
|
|
|
expect(screen.queryByLabelText('Filter for value')).not.toBeInTheDocument();
|
|
expect(screen.queryByLabelText('Filter out value')).not.toBeInTheDocument();
|
|
});
|
|
it('shows the controls if onAddAdHocFilter is defined', async () => {
|
|
jest.spyOn(grafanaUI, 'usePanelContext').mockReturnValue({
|
|
eventsScope: 'global',
|
|
eventBus: new EventBusSrv(),
|
|
onAddAdHocFilter: jest.fn(),
|
|
});
|
|
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
enableLogDetails: true,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('logline text'));
|
|
|
|
expect(await screen.findByText('common_app')).toBeInTheDocument();
|
|
|
|
expect(screen.getByLabelText('Filter for value')).toBeInTheDocument();
|
|
expect(screen.getByLabelText('Filter out value')).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Show/hide fields', () => {
|
|
const series = [
|
|
createDataFrame({
|
|
refId: 'A',
|
|
fields: [
|
|
{
|
|
name: 'timestamp',
|
|
type: FieldType.time,
|
|
values: ['2019-04-26T09:28:11.352440161Z'],
|
|
},
|
|
{
|
|
name: 'body',
|
|
type: FieldType.string,
|
|
values: ['logline text'],
|
|
},
|
|
{
|
|
name: 'labels',
|
|
type: FieldType.other,
|
|
values: [
|
|
{
|
|
app: 'common_app',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
meta: {
|
|
type: DataFrameType.LogLines,
|
|
},
|
|
}),
|
|
];
|
|
|
|
it('displays the provided fields instead of the log line', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: true,
|
|
displayedFields: ['app'],
|
|
onClickHideField: undefined,
|
|
onClickShowField: undefined,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
expect(screen.queryByText('logline text')).not.toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('app=common_app'));
|
|
|
|
expect(screen.getByLabelText('Hide this field')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByLabelText('Hide this field'));
|
|
|
|
expect(screen.getByText('logline text')).toBeInTheDocument();
|
|
});
|
|
|
|
it('updates the provided fields instead of the log line', async () => {
|
|
const { rerender, props } = setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: true,
|
|
onClickHideField: undefined,
|
|
onClickShowField: undefined,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
expect(screen.getByText('logline text')).toBeInTheDocument();
|
|
|
|
rerender(<LogsPanel {...props} options={{ ...props.options, displayedFields: ['app'] }} />);
|
|
|
|
expect(screen.getByText('app=common_app')).toBeInTheDocument();
|
|
});
|
|
|
|
it('enables the behavior with a default implementation', async () => {
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: true,
|
|
displayedFields: [],
|
|
onClickHideField: undefined,
|
|
onClickShowField: undefined,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('logline text'));
|
|
await userEvent.click(screen.getByLabelText('Show this field instead of the message'));
|
|
|
|
expect(screen.getByText('app=common_app')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByLabelText('Hide this field'));
|
|
|
|
expect(screen.getByText('logline text')).toBeInTheDocument();
|
|
});
|
|
|
|
it('overrides the default implementation when the callbacks are provided', async () => {
|
|
const onClickShowFieldMock = jest.fn();
|
|
|
|
setup({
|
|
data: {
|
|
...defaultProps.data,
|
|
series,
|
|
},
|
|
options: {
|
|
...defaultProps.options,
|
|
showLabels: false,
|
|
showTime: false,
|
|
wrapLogMessage: false,
|
|
showCommonLabels: false,
|
|
prettifyLogMessage: false,
|
|
sortOrder: LogsSortOrder.Descending,
|
|
dedupStrategy: LogsDedupStrategy.none,
|
|
enableLogDetails: true,
|
|
onClickHideField: jest.fn(),
|
|
onClickShowField: onClickShowFieldMock,
|
|
},
|
|
});
|
|
|
|
expect(await screen.findByRole('row')).toBeInTheDocument();
|
|
|
|
await userEvent.click(screen.getByText('logline text'));
|
|
await userEvent.click(screen.getByLabelText('Show this field instead of the message'));
|
|
|
|
expect(onClickShowFieldMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
});
|
|
|
|
const setup = (propsOverrides?: Partial<LogsPanelProps>) => {
|
|
const props: LogsPanelProps = {
|
|
...defaultProps,
|
|
data: {
|
|
...(propsOverrides?.data || defaultProps.data),
|
|
},
|
|
options: {
|
|
...(propsOverrides?.options || defaultProps.options),
|
|
},
|
|
};
|
|
|
|
return { ...render(<LogsPanel {...props} />), props };
|
|
};
|