+ 100 + | +
+
+ serviceName
+
+ |
+
+ operationName + | +
+ + + + + 100 + | +
+
+ serviceName
+
+ |
+
+ + + + + 100 + + % + + | ++ operationName + | +
+ + + + + 50 + | +
+
+ serviceName
+
+ |
+
+ + + + + 50 + + % + + | ++ operationName + | +
+ + - + + 100 + | +
+
+ serviceName
+
+ |
+
+ + - + + 50 + + % + + | ++ operationName + | +
+ + - + + 100 + | +
+
+ serviceName
+
+ |
+
+ + - + + 100 + + % + + | ++ operationName + | +
+ 100 + | +
+
+ serviceName
+
+ |
+
+ operationName + | +
{isSame ? null : {chgSign}}
@@ -88,7 +88,21 @@ class DiffNode extends React.PureComponentEnter a Trace ID or perform a search and select from the results.diff --git a/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/CohortTable.test.js b/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/CohortTable.test.js new file mode 100644 index 0000000000..0a7d03b9e9 --- /dev/null +++ b/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/CohortTable.test.js @@ -0,0 +1,229 @@ +// Copyright (c) 2019 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 React from 'react'; +import { shallow } from 'enzyme'; +import { Table, Tag } from 'antd'; + +import CohortTable, { NEED_MORE_TRACES_MESSAGE } from './CohortTable'; +import TraceTimelineLink from './TraceTimelineLink'; +import RelativeDate from '../../common/RelativeDate'; +import TraceName from '../../common/TraceName'; +import { fetchedState } from '../../../constants'; +import * as dateUtils from '../../../utils/date'; + +const { Column } = Table; + +describe('CohortTable', () => { + const cohort = [ + { + data: { + traceName: 'trace name 0', + }, + error: 'api error', + id: 'trace-id-0', + state: fetchedState.ERROR, + }, + { + id: 'trace-id-1', + }, + { + id: 'trace-id-2', + }, + ]; + const selectTrace = jest.fn(); + const props = { + cohort, + current: cohort[0].id, + selection: { + [cohort[0].id]: { + label: 'selected index 0', + }, + }, + selectTrace, + }; + + let formatDurationSpy; + let wrapper; + + /** + * Creates a new wrapper with default props and specified props. It is necessary to create a new wrapper + * when props change because enzyme does not support wrapper.setProps for classes that render an array of + * elements. + * + * @param {Object} [specifiedProps={}] - Props to set that are different from props defined above. + * @returns {Object} - New wrapper. + */ + function updateWrapper(specifiedProps = {}) { + wrapper = shallow({traceNameColumnRenderer('unused argument', testTrace)}
+ );
+
+ const tag = renderedTraceNameColumn.find(Tag);
+ expect(tag.length).toBe(1);
+ expect(tag.html().includes(props.selection[id].label)).toBe(true);
+
+ const renderedTraceName = renderedTraceNameColumn.find(TraceName);
+ expect(renderedTraceName.length).toBe(1);
+ expect(renderedTraceName.props()).toEqual(
+ expect.objectContaining({
+ error,
+ state,
+ traceName,
+ })
+ );
+ });
+
+ it('renders TraceName fragment when given minimal data', () => {
+ const traceNameColumnRenderer = getRowRenderer('traceName');
+ const testTrace = cohort[1];
+ const renderedTraceNameColumn = shallow(
+ // traceNameRenderer returns a React Fragment, wrapper div helps enzyme
+ {traceNameColumnRenderer('unused argument', testTrace)}
+ );
+
+ expect(renderedTraceNameColumn.find(Tag).length).toBe(0);
+ expect(renderedTraceNameColumn.find(TraceName).length).toBe(1);
+ });
+
+ it('renders date iff record state is fetchedState.DONE', () => {
+ const dateRenderer = getRowRenderer('startTime');
+ const date = 1548689901403;
+
+ expect(dateRenderer(date, { state: fetchedState.ERROR })).toBe(false);
+ const renderedDate = dateRenderer(date, { state: fetchedState.DONE });
+ expect(renderedDate.type).toBe(RelativeDate);
+ expect(renderedDate.props).toEqual({
+ fullMonthName: true,
+ includeTime: true,
+ value: date / 1000,
+ });
+ });
+
+ it('renders duration iff record state is fetchedState.DONE', () => {
+ const durationRenderer = getRowRenderer('duration');
+ const duration = 150;
+ const formatDurationSpyMockReturnValue = 'formatDurationSpyMockReturnValue';
+ formatDurationSpy.mockReturnValue(formatDurationSpyMockReturnValue);
+
+ expect(durationRenderer(duration, { state: fetchedState.ERROR })).toBe(false);
+ expect(formatDurationSpy).toHaveBeenCalledTimes(0);
+
+ expect(durationRenderer(duration, { state: fetchedState.DONE })).toBe(formatDurationSpyMockReturnValue);
+ expect(formatDurationSpy).toHaveBeenCalledTimes(1);
+ expect(formatDurationSpy).toHaveBeenCalledWith(duration);
+ });
+
+ it('renders link', () => {
+ const linkRenderer = getRowRenderer('traceID');
+ const traceID = 'trace-id';
+ const renderedLink = linkRenderer(traceID);
+ expect(renderedLink.type).toBe(TraceTimelineLink);
+ expect(renderedLink.props).toEqual({
+ traceID,
+ });
+ });
+
+ it('renders NEED_MORE_TRACES_MESSAGE if cohort is too small', () => {
+ expect(wrapper.contains(NEED_MORE_TRACES_MESSAGE)).toBe(false);
+ updateWrapper({ cohort: cohort.slice(0, 1) });
+ expect(wrapper.contains(NEED_MORE_TRACES_MESSAGE)).toBe(true);
+ updateWrapper({ cohort: [] });
+ expect(wrapper.contains(NEED_MORE_TRACES_MESSAGE)).toBe(true);
+ });
+});
diff --git a/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/TraceDiffHeader.js b/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/TraceDiffHeader.js
index 59bce3ee40..81e515fa94 100644
--- a/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/TraceDiffHeader.js
+++ b/packages/jaeger-ui/src/components/TraceDiff/TraceDiffHeader/TraceDiffHeader.js
@@ -76,10 +76,9 @@ export default class TraceDiffHeader extends React.PureComponent
+
+ + A ++
+
+
+
+
+ + VS ++
+
+ + B ++
+
+
+
+
+ + A ++
+
+
+
+
+ + VS ++
+
+ + B ++
+
+
+
+
+ + A ++
+
+
+
+
+ + VS ++
+
+ + B ++
+
+
+
+
+ + A ++
+
+
+
+
+ + VS ++
+
+ + B ++
+
+
+
+
+
+
+ |