|
|
|
@ -11,86 +11,44 @@ |
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
import { shallow, mount, ShallowWrapper } from 'enzyme'; |
|
|
|
|
import { render, screen } from '@testing-library/react'; |
|
|
|
|
import React from 'react'; |
|
|
|
|
import { TNil } from 'src/types'; |
|
|
|
|
import { Trace, TraceSpan } from 'src/types/trace'; |
|
|
|
|
import { Trace } from 'src/types/trace'; |
|
|
|
|
|
|
|
|
|
import traceGenerator from '../demo/trace-generators'; |
|
|
|
|
import transformTraceData from '../model/transform-trace-data'; |
|
|
|
|
|
|
|
|
|
import ListView from './ListView'; |
|
|
|
|
import SpanBarRow, { SpanBarRowProps } from './SpanBarRow'; |
|
|
|
|
import DetailState from './SpanDetail/DetailState'; |
|
|
|
|
import SpanDetailRow, { SpanDetailRowProps } from './SpanDetailRow'; |
|
|
|
|
import SpanTreeOffset from './SpanTreeOffset'; |
|
|
|
|
import VirtualizedTraceView, { |
|
|
|
|
DEFAULT_HEIGHTS, |
|
|
|
|
UnthemedVirtualizedTraceView, |
|
|
|
|
VirtualizedTraceViewProps, |
|
|
|
|
} from './VirtualizedTraceView'; |
|
|
|
|
import VirtualizedTraceView, { VirtualizedTraceViewProps } from './VirtualizedTraceView'; |
|
|
|
|
|
|
|
|
|
jest.mock('./SpanTreeOffset'); |
|
|
|
|
|
|
|
|
|
describe('<VirtualizedTraceViewImpl>', () => { |
|
|
|
|
let wrapper: ShallowWrapper<VirtualizedTraceViewProps, {}, UnthemedVirtualizedTraceView>; |
|
|
|
|
let instance: UnthemedVirtualizedTraceView; |
|
|
|
|
|
|
|
|
|
const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 }))!; |
|
|
|
|
const topOfExploreViewRef = jest.fn(); |
|
|
|
|
const props = { |
|
|
|
|
childrenHiddenIDs: new Set(), |
|
|
|
|
childrenToggle: jest.fn(), |
|
|
|
|
clearShouldScrollToFirstUiFindMatch: jest.fn(), |
|
|
|
|
currentViewRangeTime: [0.25, 0.75], |
|
|
|
|
detailLogItemToggle: jest.fn(), |
|
|
|
|
detailLogsToggle: jest.fn(), |
|
|
|
|
detailProcessToggle: jest.fn(), |
|
|
|
|
detailStates: new Map(), |
|
|
|
|
detailTagsToggle: jest.fn(), |
|
|
|
|
detailToggle: jest.fn(), |
|
|
|
|
findMatchesIDs: null, |
|
|
|
|
registerAccessors: jest.fn(), |
|
|
|
|
scrollToFirstVisibleSpan: jest.fn(), |
|
|
|
|
setSpanNameColumnWidth: jest.fn(), |
|
|
|
|
setTrace: jest.fn(), |
|
|
|
|
shouldScrollToFirstUiFindMatch: false, |
|
|
|
|
spanNameColumnWidth: 0.5, |
|
|
|
|
trace, |
|
|
|
|
uiFind: 'uiFind', |
|
|
|
|
topOfExploreViewRef, |
|
|
|
|
} as unknown as VirtualizedTraceViewProps; |
|
|
|
|
|
|
|
|
|
function expandRow(rowIndex: number) { |
|
|
|
|
const detailStates = new Map(); |
|
|
|
|
const detailState = new DetailState(); |
|
|
|
|
detailStates.set(trace.spans[rowIndex].spanID, detailState); |
|
|
|
|
wrapper.setProps({ detailStates }); |
|
|
|
|
return detailState; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function addSpansAndCollapseTheirParent(newSpanID = 'some-id') { |
|
|
|
|
const childrenHiddenIDs = new Set([newSpanID]); |
|
|
|
|
const spans = [ |
|
|
|
|
trace.spans[0], |
|
|
|
|
// this span is condidered to have collapsed children
|
|
|
|
|
{ spanID: newSpanID, depth: 1, traceID: trace.traceID }, |
|
|
|
|
// these two "spans" are children and should be hidden
|
|
|
|
|
{ depth: 2 }, |
|
|
|
|
{ depth: 3 }, |
|
|
|
|
...trace.spans.slice(1), |
|
|
|
|
] as TraceSpan[]; |
|
|
|
|
const _trace = { ...trace, spans }; |
|
|
|
|
wrapper.setProps({ childrenHiddenIDs, trace: _trace }); |
|
|
|
|
return spans; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function updateSpan(srcTrace: Trace, spanIndex: number, update: Partial<TraceSpan>) { |
|
|
|
|
const span = { ...srcTrace.spans[spanIndex], ...update }; |
|
|
|
|
const spans = [...srcTrace.spans.slice(0, spanIndex), span, ...srcTrace.spans.slice(spanIndex + 1)]; |
|
|
|
|
return { ...srcTrace, spans }; |
|
|
|
|
} |
|
|
|
|
const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 2 }))!; |
|
|
|
|
const topOfExploreViewRef = jest.fn(); |
|
|
|
|
let props = { |
|
|
|
|
childrenHiddenIDs: new Set(), |
|
|
|
|
childrenToggle: jest.fn(), |
|
|
|
|
clearShouldScrollToFirstUiFindMatch: jest.fn(), |
|
|
|
|
currentViewRangeTime: [0.25, 0.75], |
|
|
|
|
detailLogItemToggle: jest.fn(), |
|
|
|
|
detailLogsToggle: jest.fn(), |
|
|
|
|
detailProcessToggle: jest.fn(), |
|
|
|
|
detailStates: new Map(), |
|
|
|
|
detailTagsToggle: jest.fn(), |
|
|
|
|
detailToggle: jest.fn(), |
|
|
|
|
findMatchesIDs: null, |
|
|
|
|
registerAccessors: jest.fn(), |
|
|
|
|
scrollToFirstVisibleSpan: jest.fn(), |
|
|
|
|
setSpanNameColumnWidth: jest.fn(), |
|
|
|
|
setTrace: jest.fn(), |
|
|
|
|
shouldScrollToFirstUiFindMatch: false, |
|
|
|
|
spanNameColumnWidth: 0.5, |
|
|
|
|
trace, |
|
|
|
|
uiFind: 'uiFind', |
|
|
|
|
topOfExploreViewRef, |
|
|
|
|
} as unknown as VirtualizedTraceViewProps; |
|
|
|
|
|
|
|
|
|
describe('<VirtualizedTraceViewImpl>', () => { |
|
|
|
|
beforeEach(() => { |
|
|
|
|
jest.mocked(SpanTreeOffset).mockReturnValue(<div />); |
|
|
|
|
Object.keys(props).forEach((key) => { |
|
|
|
@ -98,344 +56,71 @@ describe('<VirtualizedTraceViewImpl>', () => { |
|
|
|
|
(props[key as keyof VirtualizedTraceViewProps] as jest.Mock).mockReset(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
wrapper = shallow(<VirtualizedTraceView {...(props as unknown as VirtualizedTraceViewProps)} />) |
|
|
|
|
.dive() |
|
|
|
|
.dive(); |
|
|
|
|
instance = wrapper.instance(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders without exploding', () => { |
|
|
|
|
expect(wrapper).toBeDefined(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders when a trace is not set', () => { |
|
|
|
|
wrapper.setProps({ trace: null as unknown as Trace }); |
|
|
|
|
expect(wrapper).toBeDefined(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders a ListView', () => { |
|
|
|
|
expect(wrapper.find(ListView)).toBeDefined(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders scrollToTopButton', () => { |
|
|
|
|
expect(wrapper.find({ title: 'Scroll to top' }).exists()).toBeTruthy(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('sets the trace for global state.traceTimeline', () => { |
|
|
|
|
expect(jest.mocked(props.setTrace).mock.calls).toEqual([[trace, props.uiFind]]); |
|
|
|
|
expect(jest.mocked(props.setTrace).mock.calls).toEqual([[trace, props.uiFind]]); |
|
|
|
|
jest.mocked(props.setTrace).mockReset(); |
|
|
|
|
const traceID = 'some-other-id'; |
|
|
|
|
const _trace = { ...trace, traceID }; |
|
|
|
|
wrapper.setProps({ trace: _trace }); |
|
|
|
|
expect(jest.mocked(props.setTrace).mock.calls).toEqual([[_trace, props.uiFind]]); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('props.registerAccessors', () => { |
|
|
|
|
let lv: ListView; |
|
|
|
|
let expectedArg: { |
|
|
|
|
getBottomRowIndexVisible: () => void; |
|
|
|
|
getTopRowIndexVisible: () => void; |
|
|
|
|
getViewHeight: () => number; |
|
|
|
|
getRowPosition: (index: number) => { height: number; y: number }; |
|
|
|
|
getViewRange: () => [number, number]; |
|
|
|
|
getSearchedSpanIDs: () => Set<string> | TNil; |
|
|
|
|
getCollapsedChildren: () => Set<string>; |
|
|
|
|
mapRowIndexToSpanIndex: (index: number) => number; |
|
|
|
|
mapSpanIndexToRowIndex: (index: number) => number; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
|
const getBottomRowIndexVisible = () => {}; |
|
|
|
|
const getTopRowIndexVisible = () => {}; |
|
|
|
|
lv = { |
|
|
|
|
getViewHeight: () => {}, |
|
|
|
|
getBottomVisibleIndex: getBottomRowIndexVisible, |
|
|
|
|
getTopVisibleIndex: getTopRowIndexVisible, |
|
|
|
|
getRowPosition: () => {}, |
|
|
|
|
} as unknown as ListView; |
|
|
|
|
expectedArg = { |
|
|
|
|
getBottomRowIndexVisible, |
|
|
|
|
getTopRowIndexVisible, |
|
|
|
|
getViewHeight: lv.getViewHeight, |
|
|
|
|
getRowPosition: lv.getRowPosition, |
|
|
|
|
getViewRange: instance.getViewRange, |
|
|
|
|
getSearchedSpanIDs: instance.getSearchedSpanIDs, |
|
|
|
|
getCollapsedChildren: instance.getCollapsedChildren, |
|
|
|
|
mapRowIndexToSpanIndex: instance.mapRowIndexToSpanIndex, |
|
|
|
|
mapSpanIndexToRowIndex: instance.mapSpanIndexToRowIndex, |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('invokes when the listView is set', () => { |
|
|
|
|
expect(jest.mocked(props.registerAccessors).mock.calls.length).toBe(0); |
|
|
|
|
instance.setListView(lv); |
|
|
|
|
expect(jest.mocked(props.registerAccessors).mock.calls).toEqual([[expectedArg]]); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('invokes when registerAccessors changes', () => { |
|
|
|
|
const registerAccessors = jest.fn(); |
|
|
|
|
instance.setListView(lv); |
|
|
|
|
wrapper.setProps({ registerAccessors }); |
|
|
|
|
expect(registerAccessors.mock.calls).toEqual([[expectedArg]]); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns the current view range via getViewRange()', () => { |
|
|
|
|
expect(instance.getViewRange()).toBe(props.currentViewRangeTime); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns findMatchesIDs via getSearchedSpanIDs()', () => { |
|
|
|
|
const findMatchesIDs: Set<string> = new Set(); |
|
|
|
|
wrapper.setProps({ findMatchesIDs }); |
|
|
|
|
expect(instance.getSearchedSpanIDs()).toBe(findMatchesIDs); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns childrenHiddenIDs via getCollapsedChildren()', () => { |
|
|
|
|
const childrenHiddenIDs: Set<string> = new Set(); |
|
|
|
|
wrapper.setProps({ childrenHiddenIDs }); |
|
|
|
|
expect(instance.getCollapsedChildren()).toBe(childrenHiddenIDs); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('mapRowIndexToSpanIndex() maps row index to span index', () => { |
|
|
|
|
it('works when nothing is collapsed or expanded', () => { |
|
|
|
|
const i = trace.spans.length - 1; |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(i)).toBe(i); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('works when a span is expanded', () => { |
|
|
|
|
expandRow(1); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(0)).toBe(0); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(1)).toBe(1); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(2)).toBe(1); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(3)).toBe(2); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('works when a parent span is collapsed', () => { |
|
|
|
|
addSpansAndCollapseTheirParent(); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(0)).toBe(0); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(1)).toBe(1); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(2)).toBe(4); |
|
|
|
|
expect(instance.mapRowIndexToSpanIndex(3)).toBe(5); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('mapSpanIndexToRowIndex() maps span index to row index', () => { |
|
|
|
|
it('works when nothing is collapsed or expanded', () => { |
|
|
|
|
const i = trace.spans.length - 1; |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(i)).toBe(i); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('works when a span is expanded', () => { |
|
|
|
|
expandRow(1); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(0)).toBe(0); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(1)).toBe(1); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(2)).toBe(3); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(3)).toBe(4); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('works when a parent span is collapsed', () => { |
|
|
|
|
addSpansAndCollapseTheirParent(); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(0)).toBe(0); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(1)).toBe(1); |
|
|
|
|
expect(() => instance.mapSpanIndexToRowIndex(2)).toThrow(); |
|
|
|
|
expect(() => instance.mapSpanIndexToRowIndex(3)).toThrow(); |
|
|
|
|
expect(instance.mapSpanIndexToRowIndex(4)).toBe(2); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
it('renders service name, operation name and duration for each span', () => { |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect(screen.getAllByText(trace.services[0].name)).toBeTruthy(); |
|
|
|
|
|
|
|
|
|
describe('getKeyFromIndex() generates a "key" from a row index', () => { |
|
|
|
|
function verify(input: number, output: string) { |
|
|
|
|
expect(instance.getKeyFromIndex(input)).toBe(output); |
|
|
|
|
if (trace.services.length > 1) { |
|
|
|
|
expect(screen.getAllByText(trace.services[1].name)).toBeTruthy(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it('works when nothing is expanded or collapsed', () => { |
|
|
|
|
verify(0, `${trace.spans[0].traceID}--${trace.spans[0].spanID}--bar`); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('works when rows are expanded', () => { |
|
|
|
|
expandRow(1); |
|
|
|
|
verify(1, `${trace.spans[1].traceID}--${trace.spans[1].spanID}--bar`); |
|
|
|
|
verify(2, `${trace.spans[1].traceID}--${trace.spans[1].spanID}--detail`); |
|
|
|
|
verify(3, `${trace.spans[2].traceID}--${trace.spans[2].spanID}--bar`); |
|
|
|
|
}); |
|
|
|
|
expect(screen.getAllByText(trace.spans[0].operationName)).toBeTruthy(); |
|
|
|
|
expect(screen.getAllByText(trace.spans[1].operationName)).toBeTruthy(); |
|
|
|
|
|
|
|
|
|
it('works when a parent span is collapsed', () => { |
|
|
|
|
const spans = addSpansAndCollapseTheirParent(); |
|
|
|
|
verify(1, `${spans[1].traceID}--${spans[1].spanID}--bar`); |
|
|
|
|
verify(2, `${spans[4].traceID}--${spans[4].spanID}--bar`); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
let durationSpan0 = trace.spans[0].duration; |
|
|
|
|
|
|
|
|
|
describe('getIndexFromKey() converts a "key" to the corresponding row index', () => { |
|
|
|
|
function verify(input: string, output: number) { |
|
|
|
|
expect(instance.getIndexFromKey(input)).toBe(output); |
|
|
|
|
if (trace.spans[0].duration >= 1_000_000) { |
|
|
|
|
durationSpan0 = Math.floor(trace.spans[0].duration / 1000000); |
|
|
|
|
} else if (trace.spans[0].duration >= 1000) { |
|
|
|
|
durationSpan0 = Math.floor(trace.spans[0].duration / 1000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it('works when nothing is expanded or collapsed', () => { |
|
|
|
|
verify(`${trace.traceID}--${trace.spans[0].spanID}--bar`, 0); |
|
|
|
|
}); |
|
|
|
|
let durationSpan1 = trace.spans[1].duration; |
|
|
|
|
|
|
|
|
|
it('works when rows are expanded', () => { |
|
|
|
|
expandRow(1); |
|
|
|
|
verify(`${trace.spans[1].traceID}--${trace.spans[1].spanID}--bar`, 1); |
|
|
|
|
verify(`${trace.spans[1].traceID}--${trace.spans[1].spanID}--detail`, 2); |
|
|
|
|
verify(`${trace.spans[2].traceID}--${trace.spans[2].spanID}--bar`, 3); |
|
|
|
|
}); |
|
|
|
|
if (trace.spans[1].duration >= 1_000_000) { |
|
|
|
|
durationSpan1 = Math.floor(trace.spans[1].duration / 1000000); |
|
|
|
|
} else if (trace.spans[1].duration >= 1000) { |
|
|
|
|
durationSpan1 = Math.floor(trace.spans[1].duration / 1000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it('works when a parent span is collapsed', () => { |
|
|
|
|
const spans = addSpansAndCollapseTheirParent(); |
|
|
|
|
verify(`${spans[1].traceID}--${spans[1].spanID}--bar`, 1); |
|
|
|
|
verify(`${spans[4].traceID}--${spans[4].spanID}--bar`, 2); |
|
|
|
|
}); |
|
|
|
|
expect(screen.getAllByText(durationSpan0, { exact: false })).toBeTruthy(); |
|
|
|
|
expect(screen.getAllByText(durationSpan1, { exact: false })).toBeTruthy(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('getRowHeight()', () => { |
|
|
|
|
it('returns the expected height for non-detail rows', () => { |
|
|
|
|
expect(instance.getRowHeight(0)).toBe(DEFAULT_HEIGHTS.bar); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns the expected height for detail rows that do not have logs', () => { |
|
|
|
|
expandRow(0); |
|
|
|
|
expect(instance.getRowHeight(1)).toBe(DEFAULT_HEIGHTS.detail); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns the expected height for detail rows that do have logs', () => { |
|
|
|
|
const logs = [ |
|
|
|
|
{ |
|
|
|
|
timestamp: Date.now(), |
|
|
|
|
fields: traceGenerator.tags(), |
|
|
|
|
}, |
|
|
|
|
]; |
|
|
|
|
const altTrace = updateSpan(trace, 0, { logs }); |
|
|
|
|
expandRow(0); |
|
|
|
|
wrapper.setProps({ trace: altTrace }); |
|
|
|
|
expect(instance.getRowHeight(1)).toBe(DEFAULT_HEIGHTS.detailWithLogs); |
|
|
|
|
}); |
|
|
|
|
it('renders without exploding', () => { |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect(screen.getByTestId('ListView')).toBeInTheDocument(); |
|
|
|
|
expect(screen.getByTitle('Scroll to top')).toBeInTheDocument(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('renderRow()', () => { |
|
|
|
|
it('renders a SpanBarRow when it is not a detail', () => { |
|
|
|
|
const span = trace.spans[1]; |
|
|
|
|
const row = instance.renderRow('some-key', {}, 1, {}); |
|
|
|
|
const rowWrapper = shallow(row!); |
|
|
|
|
|
|
|
|
|
expect( |
|
|
|
|
rowWrapper.containsMatchingElement( |
|
|
|
|
<SpanBarRow |
|
|
|
|
{...({ |
|
|
|
|
clippingLeft: instance.getClipping().left, |
|
|
|
|
clippingRight: instance.getClipping().right, |
|
|
|
|
columnDivision: props.spanNameColumnWidth, |
|
|
|
|
isChildrenExpanded: true, |
|
|
|
|
isDetailExpanded: false, |
|
|
|
|
isMatchingFilter: false, |
|
|
|
|
numTicks: 5, |
|
|
|
|
onDetailToggled: props.detailToggle, |
|
|
|
|
onChildrenToggled: props.childrenToggle, |
|
|
|
|
rpc: undefined, |
|
|
|
|
showErrorIcon: false, |
|
|
|
|
span: span, |
|
|
|
|
} as unknown as SpanBarRowProps)} |
|
|
|
|
/> |
|
|
|
|
) |
|
|
|
|
).toBe(true); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders a SpanBarRow with a RPC span if the row is collapsed and a client span', () => { |
|
|
|
|
const clientTags = [{ key: 'span.kind', value: 'client' }, ...trace.spans[0].tags]; |
|
|
|
|
const serverTags = [{ key: 'span.kind', value: 'server' }, ...trace.spans[1].tags]; |
|
|
|
|
let altTrace = updateSpan(trace, 0, { tags: clientTags }); |
|
|
|
|
altTrace = updateSpan(altTrace, 1, { tags: serverTags }); |
|
|
|
|
const childrenHiddenIDs = new Set([altTrace.spans[0].spanID]); |
|
|
|
|
wrapper.setProps({ childrenHiddenIDs, trace: altTrace }); |
|
|
|
|
|
|
|
|
|
const rowWrapper = mount(instance.renderRow('some-key', {}, 0, {})!); |
|
|
|
|
const spanBarRow = rowWrapper.find(SpanBarRow); |
|
|
|
|
expect(spanBarRow.length).toBe(1); |
|
|
|
|
expect(spanBarRow.prop('rpc')).toBeDefined(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders a SpanDetailRow when it is a detail', () => { |
|
|
|
|
const detailState = expandRow(1); |
|
|
|
|
const span = trace.spans[1]; |
|
|
|
|
const row = instance.renderRow('some-key', {}, 2, {}); |
|
|
|
|
const rowWrapper = shallow(row!); |
|
|
|
|
expect( |
|
|
|
|
rowWrapper.containsMatchingElement( |
|
|
|
|
<SpanDetailRow |
|
|
|
|
{...({ |
|
|
|
|
columnDivision: props.spanNameColumnWidth, |
|
|
|
|
onDetailToggled: props.detailToggle, |
|
|
|
|
detailState: detailState, |
|
|
|
|
logItemToggle: props.detailLogItemToggle, |
|
|
|
|
logsToggle: props.detailLogsToggle, |
|
|
|
|
processToggle: props.detailProcessToggle, |
|
|
|
|
span: span, |
|
|
|
|
tagsToggle: props.detailTagsToggle, |
|
|
|
|
} as unknown as SpanDetailRowProps)} |
|
|
|
|
/> |
|
|
|
|
) |
|
|
|
|
).toBe(true); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('renders a SpanBarRow with a client span and no instrumented server span', () => { |
|
|
|
|
const externServiceName = 'externalServiceTest'; |
|
|
|
|
const leafSpan = trace.spans.find((span) => !span.hasChildren); |
|
|
|
|
const leafSpanIndex = trace.spans.indexOf(leafSpan!); |
|
|
|
|
const clientTags = [ |
|
|
|
|
{ key: 'span.kind', value: 'client' }, |
|
|
|
|
{ key: 'peer.service', value: externServiceName }, |
|
|
|
|
...leafSpan!.tags, |
|
|
|
|
]; |
|
|
|
|
const altTrace = updateSpan(trace, leafSpanIndex, { tags: clientTags }); |
|
|
|
|
wrapper.setProps({ trace: altTrace }); |
|
|
|
|
const rowWrapper = mount(instance.renderRow('some-key', {}, leafSpanIndex, {})!); |
|
|
|
|
const spanBarRow = rowWrapper.find(SpanBarRow); |
|
|
|
|
expect(spanBarRow.length).toBe(1); |
|
|
|
|
expect(spanBarRow.prop('noInstrumentedServer')).not.toBeNull(); |
|
|
|
|
}); |
|
|
|
|
it('renders when a trace is not set', () => { |
|
|
|
|
props = { ...props, trace: null as unknown as Trace }; |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect(screen.getByTestId('ListView')).toBeInTheDocument(); |
|
|
|
|
expect(screen.getByTitle('Scroll to top')).toBeInTheDocument(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('shouldScrollToFirstUiFindMatch', () => { |
|
|
|
|
const propsWithTrueShouldScrollToFirstUiFindMatch = { ...props, shouldScrollToFirstUiFindMatch: true }; |
|
|
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
|
jest.mocked(props.scrollToFirstVisibleSpan).mockReset(); |
|
|
|
|
jest.mocked(props.clearShouldScrollToFirstUiFindMatch).mockReset(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('calls props.scrollToFirstVisibleSpan if shouldScrollToFirstUiFindMatch is true', () => { |
|
|
|
|
expect(props.scrollToFirstVisibleSpan).not.toHaveBeenCalled(); |
|
|
|
|
expect(props.clearShouldScrollToFirstUiFindMatch).not.toHaveBeenCalled(); |
|
|
|
|
|
|
|
|
|
wrapper.setProps(propsWithTrueShouldScrollToFirstUiFindMatch); |
|
|
|
|
expect(props.scrollToFirstVisibleSpan).toHaveBeenCalledTimes(1); |
|
|
|
|
expect(props.clearShouldScrollToFirstUiFindMatch).toHaveBeenCalledTimes(1); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('shouldComponentUpdate', () => { |
|
|
|
|
it('returns true if props.shouldScrollToFirstUiFindMatch changes to true', () => { |
|
|
|
|
expect(wrapper.instance().shouldComponentUpdate(propsWithTrueShouldScrollToFirstUiFindMatch)).toBe(true); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns true if props.shouldScrollToFirstUiFindMatch changes to false and another props change', () => { |
|
|
|
|
const propsWithOtherDifferenceAndTrueshouldScrollToFirstUiFindMatch = { |
|
|
|
|
...propsWithTrueShouldScrollToFirstUiFindMatch, |
|
|
|
|
clearShouldScrollToFirstUiFindMatch: () => {}, |
|
|
|
|
}; |
|
|
|
|
wrapper.setProps(propsWithOtherDifferenceAndTrueshouldScrollToFirstUiFindMatch); |
|
|
|
|
expect(wrapper.instance().shouldComponentUpdate(props)).toBe(true); |
|
|
|
|
}); |
|
|
|
|
it('renders ListView', () => { |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect(screen.getByTestId('ListView')).toBeInTheDocument(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns false if props.shouldScrollToFirstUiFindMatch changes to false and no other props change', () => { |
|
|
|
|
wrapper.setProps(propsWithTrueShouldScrollToFirstUiFindMatch); |
|
|
|
|
expect(wrapper.instance().shouldComponentUpdate(props)).toBe(false); |
|
|
|
|
}); |
|
|
|
|
it('renders scrollToTopButton', () => { |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect( |
|
|
|
|
screen.getByRole('button', { |
|
|
|
|
name: /Scroll to top/i, |
|
|
|
|
}) |
|
|
|
|
).toBeInTheDocument(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
it('returns false if all props are unchanged', () => { |
|
|
|
|
expect(wrapper.instance().shouldComponentUpdate(props)).toBe(false); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
it('sets the trace for global state.traceTimeline', () => { |
|
|
|
|
const traceID = 'some-other-id'; |
|
|
|
|
const _trace = { ...trace, traceID }; |
|
|
|
|
props = { ...props, trace: _trace }; |
|
|
|
|
render(<VirtualizedTraceView {...props} />); |
|
|
|
|
expect(jest.mocked(props.setTrace).mock.calls).toEqual([[_trace, props.uiFind]]); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|