mirror of
https://github.com/grafana/grafana.git
synced 2025-09-24 09:23:54 +08:00
Chore: Refactor packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail
to TS (#59850)
This commit is contained in:
@ -15,14 +15,14 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import AccordianKeyValues, { KeyValuesSummary } from './AccordianKeyValues';
|
import AccordianKeyValues, { KeyValuesSummary, AccordianKeyValuesProps } from './AccordianKeyValues';
|
||||||
|
|
||||||
const tags = [
|
const tags = [
|
||||||
{ key: 'span.kind', value: 'client' },
|
{ key: 'span.kind', value: 'client' },
|
||||||
{ key: 'omg', value: 'mos-def' },
|
{ key: 'omg', value: 'mos-def' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const setupAccordian = (propOverrides) => {
|
const setupAccordian = (propOverrides?: AccordianKeyValuesProps) => {
|
||||||
const props = {
|
const props = {
|
||||||
compact: false,
|
compact: false,
|
||||||
data: tags,
|
data: tags,
|
||||||
@ -31,10 +31,10 @@ const setupAccordian = (propOverrides) => {
|
|||||||
onToggle: jest.fn(),
|
onToggle: jest.fn(),
|
||||||
...propOverrides,
|
...propOverrides,
|
||||||
};
|
};
|
||||||
return render(<AccordianKeyValues {...props} />);
|
return render(<AccordianKeyValues {...(props as AccordianKeyValuesProps)} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupKeyValues = (propOverrides) => {
|
const setupKeyValues = (propOverrides?: AccordianKeyValuesProps) => {
|
||||||
const props = {
|
const props = {
|
||||||
data: tags,
|
data: tags,
|
||||||
...propOverrides,
|
...propOverrides,
|
||||||
@ -48,7 +48,7 @@ describe('KeyValuesSummary tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns `null` when props.data is empty', () => {
|
it('returns `null` when props.data is empty', () => {
|
||||||
setupKeyValues({ data: null });
|
setupKeyValues({ data: null } as unknown as AccordianKeyValuesProps);
|
||||||
|
|
||||||
expect(screen.queryAllByRole('table')).toHaveLength(0);
|
expect(screen.queryAllByRole('table')).toHaveLength(0);
|
||||||
expect(screen.queryAllByRole('row')).toHaveLength(0);
|
expect(screen.queryAllByRole('row')).toHaveLength(0);
|
||||||
@ -95,7 +95,7 @@ describe('AccordianKeyValues test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders the summary instead of the table when it is not expanded', () => {
|
it('renders the summary instead of the table when it is not expanded', () => {
|
||||||
setupAccordian({ isOpen: false });
|
setupAccordian({ isOpen: false } as AccordianKeyValuesProps);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('switch', { name: 'test accordian: span.kind = client omg = mos-def' })
|
screen.getByRole('switch', { name: 'test accordian: span.kind = client omg = mos-def' })
|
@ -86,7 +86,7 @@ export const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type AccordianKeyValuesProps = {
|
export type AccordianKeyValuesProps = {
|
||||||
className?: string | TNil;
|
className?: string | TNil;
|
||||||
data: TraceKeyValuePair[];
|
data: TraceKeyValuePair[];
|
||||||
highContrast?: boolean;
|
highContrast?: boolean;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import AccordianLogs from './AccordianLogs';
|
import AccordianLogs, { AccordianLogsProps } from './AccordianLogs';
|
||||||
|
|
||||||
const logs = [
|
const logs = [
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ const logs = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const setup = (propOverrides) => {
|
const setup = (propOverrides?: AccordianLogsProps) => {
|
||||||
const props = {
|
const props = {
|
||||||
logs,
|
logs,
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
@ -60,13 +60,13 @@ describe('AccordianLogs tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('hides log entries when not expanded', () => {
|
it('hides log entries when not expanded', () => {
|
||||||
setup({ isOpen: false });
|
setup({ isOpen: false } as AccordianLogsProps);
|
||||||
|
|
||||||
expect(screen.queryByRole('table')).not.toBeInTheDocument();
|
expect(screen.queryByRole('table')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows log entries when expanded', () => {
|
it('shows log entries when expanded', () => {
|
||||||
setup({ isOpen: true });
|
setup({ isOpen: true } as AccordianLogsProps);
|
||||||
|
|
||||||
expect(screen.getByRole('table')).toBeInTheDocument();
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
expect(screen.queryAllByRole('cell')).toHaveLength(6);
|
expect(screen.queryAllByRole('cell')).toHaveLength(6);
|
@ -60,7 +60,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type AccordianLogsProps = {
|
export type AccordianLogsProps = {
|
||||||
interactive?: boolean;
|
interactive?: boolean;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
linksGetter: ((pairs: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
linksGetter: ((pairs: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import AccordianReferences, { References } from './AccordianReferences';
|
import AccordianReferences, { AccordianReferencesProps } from './AccordianReferences';
|
||||||
|
|
||||||
const traceID = 'trace1';
|
const traceID = 'trace1';
|
||||||
const references = [
|
const references = [
|
||||||
@ -54,7 +54,7 @@ const references = [
|
|||||||
|
|
||||||
const link = { href: 'link' };
|
const link = { href: 'link' };
|
||||||
|
|
||||||
const setup = (propOverrides) => {
|
const setup = (propOverrides?: AccordianReferencesProps) => {
|
||||||
const props = {
|
const props = {
|
||||||
compact: false,
|
compact: false,
|
||||||
data: references,
|
data: references,
|
||||||
@ -65,7 +65,7 @@ const setup = (propOverrides) => {
|
|||||||
...propOverrides,
|
...propOverrides,
|
||||||
};
|
};
|
||||||
|
|
||||||
return render(<AccordianReferences {...props} />);
|
return render(<AccordianReferences {...(props as AccordianReferencesProps)} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('AccordianReferences tests', () => {
|
describe('AccordianReferences tests', () => {
|
||||||
@ -80,14 +80,14 @@ describe('AccordianReferences tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('content doesnt show when not expanded', () => {
|
it('content doesnt show when not expanded', () => {
|
||||||
setup({ isOpen: false });
|
setup({ isOpen: false } as AccordianReferencesProps);
|
||||||
|
|
||||||
expect(screen.queryByRole('link', { name: /^View\sLinked/ })).not.toBeInTheDocument();
|
expect(screen.queryByRole('link', { name: /^View\sLinked/ })).not.toBeInTheDocument();
|
||||||
expect(screen.queryAllByRole('link', { name: /^service\d\sop\d/ })).toHaveLength(0);
|
expect(screen.queryAllByRole('link', { name: /^service\d\sop\d/ })).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the content when it is expanded', () => {
|
it('renders the content when it is expanded', () => {
|
||||||
setup({ isOpen: true });
|
setup({ isOpen: true } as AccordianReferencesProps);
|
||||||
|
|
||||||
expect(screen.getByRole('switch', { name: 'References (3)' })).toBeInTheDocument();
|
expect(screen.getByRole('switch', { name: 'References (3)' })).toBeInTheDocument();
|
||||||
expect(screen.getAllByRole('link', { name: /^service\d\sop\d/ })).toHaveLength(2);
|
expect(screen.getAllByRole('link', { name: /^service\d\sop\d/ })).toHaveLength(2);
|
@ -111,7 +111,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type AccordianReferencesProps = {
|
export type AccordianReferencesProps = {
|
||||||
data: TraceSpanReference[];
|
data: TraceSpanReference[];
|
||||||
highContrast?: boolean;
|
highContrast?: boolean;
|
||||||
interactive?: boolean;
|
interactive?: boolean;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import KeyValuesTable, { LinkValue } from './KeyValuesTable';
|
import KeyValuesTable, { LinkValue, KeyValuesTableProps } from './KeyValuesTable';
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{ key: 'span.kind', value: 'client' },
|
{ key: 'span.kind', value: 'client' },
|
||||||
@ -24,12 +24,12 @@ const data = [
|
|||||||
{ key: 'jsonkey', value: JSON.stringify({ hello: 'world' }) },
|
{ key: 'jsonkey', value: JSON.stringify({ hello: 'world' }) },
|
||||||
];
|
];
|
||||||
|
|
||||||
const setup = (propOverrides) => {
|
const setup = (propOverrides?: KeyValuesTableProps) => {
|
||||||
const props = {
|
const props = {
|
||||||
data: data,
|
data: data,
|
||||||
...propOverrides,
|
...propOverrides,
|
||||||
};
|
};
|
||||||
return render(<KeyValuesTable {...props} />);
|
return render(<KeyValuesTable {...(props as KeyValuesTableProps)} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('LinkValue', () => {
|
describe('LinkValue', () => {
|
||||||
@ -79,7 +79,7 @@ describe('KeyValuesTable tests', () => {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
});
|
} as KeyValuesTableProps);
|
||||||
|
|
||||||
expect(screen.getByRole('row', { name: 'span.kind More info about client' })).toBeInTheDocument();
|
expect(screen.getByRole('row', { name: 'span.kind More info about client' })).toBeInTheDocument();
|
||||||
});
|
});
|
@ -99,7 +99,7 @@ LinkValue.defaultProps = {
|
|||||||
title: '',
|
title: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
type KeyValuesTableProps = {
|
export type KeyValuesTableProps = {
|
||||||
data: TraceKeyValuePair[];
|
data: TraceKeyValuePair[];
|
||||||
linksGetter: ((pairs: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
linksGetter: ((pairs: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { render, screen, within } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import TextList from './TextList';
|
import TextList from './TextList';
|
@ -17,6 +17,7 @@ jest.mock('../utils');
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { TraceSpanReference } from 'src/types/trace';
|
||||||
|
|
||||||
import traceGenerator from '../../demo/trace-generators';
|
import traceGenerator from '../../demo/trace-generators';
|
||||||
import transformTraceData from '../../model/transform-trace-data';
|
import transformTraceData from '../../model/transform-trace-data';
|
||||||
@ -24,11 +25,11 @@ import { formatDuration } from '../utils';
|
|||||||
|
|
||||||
import DetailState from './DetailState';
|
import DetailState from './DetailState';
|
||||||
|
|
||||||
import SpanDetail, { getAbsoluteTime } from './index';
|
import SpanDetail, { getAbsoluteTime, SpanDetailProps } from './index';
|
||||||
|
|
||||||
describe('<SpanDetail>', () => {
|
describe('<SpanDetail>', () => {
|
||||||
// use `transformTraceData` on a fake trace to get a fully processed span
|
// use `transformTraceData` on a fake trace to get a fully processed span
|
||||||
const span = transformTraceData(traceGenerator.trace({ numberOfSpans: 1 })).spans[0];
|
const span = transformTraceData(traceGenerator.trace({ numberOfSpans: 1 }))!.spans[0];
|
||||||
const detailState = new DetailState().toggleLogs().toggleProcess().toggleReferences().toggleTags();
|
const detailState = new DetailState().toggleLogs().toggleProcess().toggleReferences().toggleTags();
|
||||||
const traceStartTime = 5;
|
const traceStartTime = 5;
|
||||||
const topOfExploreViewRef = jest.fn();
|
const topOfExploreViewRef = jest.fn();
|
||||||
@ -78,7 +79,7 @@ describe('<SpanDetail>', () => {
|
|||||||
},
|
},
|
||||||
spanID: 'span1',
|
spanID: 'span1',
|
||||||
traceID: 'trace1',
|
traceID: 'trace1',
|
||||||
},
|
} as TraceSpanReference,
|
||||||
{
|
{
|
||||||
refType: 'CHILD_OF',
|
refType: 'CHILD_OF',
|
||||||
span: {
|
span: {
|
||||||
@ -91,7 +92,7 @@ describe('<SpanDetail>', () => {
|
|||||||
},
|
},
|
||||||
spanID: 'span4',
|
spanID: 'span4',
|
||||||
traceID: 'trace1',
|
traceID: 'trace1',
|
||||||
},
|
} as TraceSpanReference,
|
||||||
{
|
{
|
||||||
refType: 'CHILD_OF',
|
refType: 'CHILD_OF',
|
||||||
span: {
|
span: {
|
||||||
@ -104,11 +105,11 @@ describe('<SpanDetail>', () => {
|
|||||||
},
|
},
|
||||||
spanID: 'span5',
|
spanID: 'span5',
|
||||||
traceID: 'trace2',
|
traceID: 'trace2',
|
||||||
},
|
} as TraceSpanReference,
|
||||||
];
|
];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
formatDuration.mockReset();
|
jest.mocked(formatDuration).mockReset();
|
||||||
props.tagsToggle.mockReset();
|
props.tagsToggle.mockReset();
|
||||||
props.processToggle.mockReset();
|
props.processToggle.mockReset();
|
||||||
props.logsToggle.mockReset();
|
props.logsToggle.mockReset();
|
||||||
@ -116,24 +117,24 @@ describe('<SpanDetail>', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders without exploding', () => {
|
it('renders without exploding', () => {
|
||||||
expect(() => render(<SpanDetail {...props} />)).not.toThrow();
|
expect(() => render(<SpanDetail {...(props as unknown as SpanDetailProps)} />)).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows the operation name', () => {
|
it('shows the operation name', () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
expect(screen.getByRole('heading', { name: span.operationName })).toBeInTheDocument();
|
expect(screen.getByRole('heading', { name: span.operationName })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('lists the service name, duration and start time', () => {
|
it('lists the service name, duration and start time', () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
expect(screen.getByText('Duration:')).toBeInTheDocument();
|
expect(screen.getByText('Duration:')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Service:')).toBeInTheDocument();
|
expect(screen.getByText('Service:')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Start Time:')).toBeInTheDocument();
|
expect(screen.getByText('Start Time:')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('start time shows the absolute time', () => {
|
it('start time shows the absolute time', () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
const absoluteTime = getAbsoluteTime(span.startTime);
|
const absoluteTime = getAbsoluteTime(span.startTime, 'browser');
|
||||||
expect(
|
expect(
|
||||||
screen.getByText((text) => {
|
screen.getByText((text) => {
|
||||||
return text.includes(absoluteTime);
|
return text.includes(absoluteTime);
|
||||||
@ -142,19 +143,19 @@ describe('<SpanDetail>', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders the span tags', async () => {
|
it('renders the span tags', async () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /Attributes/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /Attributes/ }));
|
||||||
expect(props.tagsToggle).toHaveBeenLastCalledWith(span.spanID);
|
expect(props.tagsToggle).toHaveBeenLastCalledWith(span.spanID);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the process tags', async () => {
|
it('renders the process tags', async () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /Resource/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /Resource/ }));
|
||||||
expect(props.processToggle).toHaveBeenLastCalledWith(span.spanID);
|
expect(props.processToggle).toHaveBeenLastCalledWith(span.spanID);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the logs', async () => {
|
it('renders the logs', async () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /Events/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /Events/ }));
|
||||||
expect(props.logsToggle).toHaveBeenLastCalledWith(span.spanID);
|
expect(props.logsToggle).toHaveBeenLastCalledWith(span.spanID);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /oh the log/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /oh the log/ }));
|
||||||
@ -162,19 +163,19 @@ describe('<SpanDetail>', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders the warnings', async () => {
|
it('renders the warnings', async () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /Warnings/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /Warnings/ }));
|
||||||
expect(props.warningsToggle).toHaveBeenLastCalledWith(span.spanID);
|
expect(props.warningsToggle).toHaveBeenLastCalledWith(span.spanID);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the references', async () => {
|
it('renders the references', async () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
await userEvent.click(screen.getByRole('switch', { name: /References/ }));
|
await userEvent.click(screen.getByRole('switch', { name: /References/ }));
|
||||||
expect(props.referencesToggle).toHaveBeenLastCalledWith(span.spanID);
|
expect(props.referencesToggle).toHaveBeenLastCalledWith(span.spanID);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders deep link URL', () => {
|
it('renders deep link URL', () => {
|
||||||
render(<SpanDetail {...props} />);
|
render(<SpanDetail {...(props as unknown as SpanDetailProps)} />);
|
||||||
expect(document.getElementsByTagName('a').length).toBeGreaterThan(1);
|
expect(document.getElementsByTagName('a').length).toBeGreaterThan(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -103,7 +103,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type SpanDetailProps = {
|
export type SpanDetailProps = {
|
||||||
detailState: DetailState;
|
detailState: DetailState;
|
||||||
linksGetter: ((links: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
linksGetter: ((links: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil;
|
||||||
logItemToggle: (spanID: string, log: TraceLog) => void;
|
logItemToggle: (spanID: string, log: TraceLog) => void;
|
||||||
|
Reference in New Issue
Block a user