Skip to content

Commit 5f07e4a

Browse files
test: Migrate AltViewOptions test from Enzyme to React Testing Library (#2878)
Replaced Enzyme-based tests with React Testing Library. Removed snapshot test and added DOM-based assertions to verify view toggling, tracking, and conditional rendering. --------- Signed-off-by: Vishvamsinh Vaghela <vaghelavishvamsinh11111@gmail.com>
1 parent 5b05b9d commit 5f07e4a

File tree

2 files changed

+167
-144
lines changed

2 files changed

+167
-144
lines changed

packages/jaeger-ui/src/components/TracePage/TracePageHeader/AltViewOptions.test.js

Lines changed: 167 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,46 @@
1313
// limitations under the License.
1414

1515
import * as React from 'react';
16-
import { shallow } from 'enzyme';
17-
import { Dropdown } from 'antd';
16+
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
17+
import '@testing-library/jest-dom';
18+
import { BrowserRouter } from 'react-router-dom';
1819
import AltViewOptions from './AltViewOptions';
1920
import * as track from './TracePageHeader.track';
2021
import { ETraceViewType } from '../types';
2122

23+
jest.mock('antd', () => {
24+
const originalModule = jest.requireActual('antd');
25+
return {
26+
...originalModule,
27+
Dropdown: ({ children, menu }) => (
28+
<div data-testid="dropdown">
29+
{children}
30+
<div data-testid="dropdown-menu">
31+
{menu.items.map(item => (
32+
<div
33+
key={item.key}
34+
data-testid={`menu-item-${item.key}`}
35+
onClick={() => {
36+
// Simulate clicking the link/button inside
37+
if (item.label?.props?.onClick) {
38+
item.label.props.onClick();
39+
}
40+
}}
41+
>
42+
{item.label}
43+
</div>
44+
))}
45+
</div>
46+
</div>
47+
),
48+
Button: ({ children, className }) => (
49+
<button type="button" className={className} data-testid="dropdown-button">
50+
{children}
51+
</button>
52+
),
53+
};
54+
});
55+
2256
describe('AltViewOptions', () => {
2357
let trackGanttView;
2458
let trackGraphView;
@@ -27,20 +61,11 @@ describe('AltViewOptions', () => {
2761
let trackStatisticsView;
2862
let trackTraceSpansView;
2963

30-
let wrapper;
31-
const getLink = text => {
32-
const links = wrapper.find(Dropdown).prop('menu').items;
33-
for (let i = 0; i < links.length; i++) {
34-
const link = links[i];
35-
if (link.label.props.children === text) return link.label.props;
36-
}
37-
throw new Error(`Could not find "${text}"`);
38-
};
39-
4064
const props = {
4165
viewType: ETraceViewType.TraceTimelineViewer,
4266
traceID: 'test trace ID',
4367
onTraceViewChange: jest.fn(),
68+
disableJsonView: false,
4469
};
4570

4671
beforeAll(() => {
@@ -52,78 +77,153 @@ describe('AltViewOptions', () => {
5277
trackTraceSpansView = jest.spyOn(track, 'trackTraceSpansView');
5378
});
5479

55-
beforeEach(() => {
80+
afterEach(() => {
5681
jest.clearAllMocks();
57-
wrapper = shallow(<AltViewOptions {...props} />);
82+
cleanup();
83+
});
84+
85+
const renderComponent = (customProps = {}) => {
86+
const mergedProps = { ...props, ...customProps };
87+
return render(
88+
<BrowserRouter>
89+
<AltViewOptions {...mergedProps} />
90+
</BrowserRouter>
91+
);
92+
};
93+
94+
it('renders dropdown button displaying the current view type', () => {
95+
renderComponent();
96+
const button = screen.getByTestId('dropdown-button');
97+
expect(button).toHaveTextContent('Trace Timeline');
98+
});
99+
100+
it('shows "Alternate Views" when viewType is not in MENU_ITEMS', () => {
101+
renderComponent({ viewType: 'UnknownViewType' });
102+
const button = screen.getByTestId('dropdown-button');
103+
expect(button).toHaveTextContent('Alternate Views');
104+
});
105+
106+
it('shows all alternate view options except current view', () => {
107+
renderComponent();
108+
109+
expect(screen.queryByTestId('menu-item-TraceTimelineViewer')).not.toBeInTheDocument();
110+
111+
expect(screen.getByTestId('menu-item-TraceGraph')).toBeInTheDocument();
112+
expect(screen.getByTestId('menu-item-TraceStatistics')).toBeInTheDocument();
113+
expect(screen.getByTestId('menu-item-TraceSpansView')).toBeInTheDocument();
114+
expect(screen.getByTestId('menu-item-TraceFlamegraph')).toBeInTheDocument();
115+
expect(screen.getByTestId('menu-item-trace-json')).toBeInTheDocument();
116+
expect(screen.getByTestId('menu-item-trace-json-unadjusted')).toBeInTheDocument();
58117
});
59118

60-
it('renders correctly', () => {
61-
expect(wrapper).toMatchSnapshot();
119+
it('hides json links when disableJsonView is true', () => {
120+
renderComponent({ disableJsonView: true });
121+
122+
expect(screen.queryByTestId('menu-item-trace-json')).not.toBeInTheDocument();
123+
expect(screen.queryByTestId('menu-item-trace-json-unadjusted')).not.toBeInTheDocument();
124+
125+
expect(screen.getByTestId('menu-item-TraceGraph')).toBeInTheDocument();
126+
expect(screen.getByTestId('menu-item-TraceStatistics')).toBeInTheDocument();
62127
});
63128

64-
it('disables json links because disableJsonView is true', () => {
65-
wrapper.setProps({ disableJsonView: true });
129+
it('tracks and changes view for Trace Graph', () => {
130+
renderComponent({ viewType: ETraceViewType.TraceTimelineViewer });
131+
const menuItem = screen.getByTestId('menu-item-TraceGraph');
132+
133+
fireEvent.click(menuItem);
66134

67-
expect(() => getLink('Trace JSON')).toThrow('Could not find "Trace JSON"');
68-
expect(() => getLink('Trace JSON (unadjusted)')).toThrow('Could not find "Trace JSON (unadjusted)"');
135+
expect(props.onTraceViewChange).toHaveBeenCalledWith(ETraceViewType.TraceGraph);
136+
expect(trackGraphView).toHaveBeenCalledTimes(1);
69137
});
70138

71-
it('tracks viewing JSONs', () => {
72-
expect(trackJsonView).not.toHaveBeenCalled();
73-
getLink('Trace JSON').onClick();
74-
expect(trackJsonView).toHaveBeenCalledTimes(1);
139+
it('tracks and changes view for Trace Statistics', () => {
140+
renderComponent({ viewType: ETraceViewType.TraceGraph });
141+
const menuItem = screen.getByTestId('menu-item-TraceStatistics');
75142

76-
expect(trackRawJsonView).not.toHaveBeenCalled();
77-
getLink('Trace JSON (unadjusted)').onClick();
78-
expect(trackRawJsonView).toHaveBeenCalledTimes(1);
143+
fireEvent.click(menuItem);
144+
145+
expect(props.onTraceViewChange).toHaveBeenCalledWith(ETraceViewType.TraceStatistics);
146+
expect(trackStatisticsView).toHaveBeenCalledTimes(1);
147+
});
148+
149+
it('tracks and changes view for Trace Timeline', () => {
150+
renderComponent({ viewType: ETraceViewType.TraceStatistics });
151+
const menuItem = screen.getByTestId('menu-item-TraceTimelineViewer');
152+
153+
fireEvent.click(menuItem);
154+
155+
expect(props.onTraceViewChange).toHaveBeenCalledWith(ETraceViewType.TraceTimelineViewer);
156+
expect(trackGanttView).toHaveBeenCalledTimes(1);
157+
});
158+
159+
it('tracks and changes view for Trace Spans Table', () => {
160+
renderComponent({ viewType: ETraceViewType.TraceTimelineViewer });
161+
const menuItem = screen.getByTestId('menu-item-TraceSpansView');
162+
163+
fireEvent.click(menuItem);
164+
165+
expect(props.onTraceViewChange).toHaveBeenCalledWith(ETraceViewType.TraceSpansView);
166+
expect(trackTraceSpansView).toHaveBeenCalledTimes(1);
167+
});
168+
169+
it('does not track or change view for Trace Flamegraph', () => {
170+
renderComponent({ viewType: ETraceViewType.TraceTimelineViewer });
171+
const menuItem = screen.getByTestId('menu-item-TraceFlamegraph');
172+
173+
fireEvent.click(menuItem);
174+
175+
expect(props.onTraceViewChange).toHaveBeenCalledWith(ETraceViewType.TraceFlamegraph);
79176

80-
expect(trackJsonView).toHaveBeenCalledTimes(1);
81177
expect(trackGanttView).not.toHaveBeenCalled();
82178
expect(trackGraphView).not.toHaveBeenCalled();
179+
expect(trackStatisticsView).not.toHaveBeenCalled();
83180
expect(trackTraceSpansView).not.toHaveBeenCalled();
84181
});
85182

86-
it('track dropdown menu', () => {
87-
const viewInteractions = [
88-
{
89-
link: 'Trace Graph',
90-
trackFn: trackGraphView,
91-
onTraceViewChangeArg: ETraceViewType.TraceGraph,
92-
},
93-
{
94-
link: 'Trace Statistics',
95-
trackFn: trackStatisticsView,
96-
onTraceViewChangeArg: ETraceViewType.TraceStatisticsView,
97-
propViewType: ETraceViewType.TraceGraph,
98-
},
99-
{
100-
link: 'Trace Timeline',
101-
trackFn: trackGanttView,
102-
onTraceViewChangeArg: ETraceViewType.TraceTimelineViewer,
103-
propViewType: ETraceViewType.TraceStatisticsView,
104-
},
105-
{
106-
link: 'Trace Spans Table',
107-
trackFn: trackTraceSpansView,
108-
onTraceViewChangeArg: ETraceViewType.TraceSpansView,
109-
propViewType: ETraceViewType.TraceTimelineViewer,
110-
},
183+
it('renders JSON links with correct URLs', () => {
184+
renderComponent();
185+
186+
const jsonMenuItem = screen.getByTestId('menu-item-trace-json');
187+
const jsonLink = jsonMenuItem.querySelector('a');
188+
expect(jsonLink).toHaveAttribute('href', '/api/traces/test trace ID?prettyPrint=true');
189+
190+
const rawJsonMenuItem = screen.getByTestId('menu-item-trace-json-unadjusted');
191+
const rawJsonLink = rawJsonMenuItem.querySelector('a');
192+
expect(rawJsonLink).toHaveAttribute('href', '/api/traces/test trace ID?raw=true&prettyPrint=true');
193+
});
194+
195+
it('updates dropdown text when view type changes', () => {
196+
const { rerender } = renderComponent({ viewType: ETraceViewType.TraceTimelineViewer });
197+
expect(screen.getByTestId('dropdown-button')).toHaveTextContent('Trace Timeline');
198+
199+
const rerenderWithViewType = (viewType, expectedText) => {
200+
rerender(
201+
<BrowserRouter>
202+
<AltViewOptions {...props} viewType={viewType} />
203+
</BrowserRouter>
204+
);
205+
expect(screen.getByTestId('dropdown-button')).toHaveTextContent(expectedText);
206+
};
207+
208+
rerenderWithViewType(ETraceViewType.TraceGraph, 'Trace Graph');
209+
rerenderWithViewType(ETraceViewType.TraceStatistics, 'Trace Statistics');
210+
rerenderWithViewType(ETraceViewType.TraceSpansView, 'Trace Spans Table');
211+
rerenderWithViewType(ETraceViewType.TraceFlamegraph, 'Trace Flamegraph');
212+
});
213+
214+
it('excludes current view from dropdown options for all view types', () => {
215+
const viewTypes = [
216+
{ type: ETraceViewType.TraceTimelineViewer, testId: 'menu-item-TraceTimelineViewer' },
217+
{ type: ETraceViewType.TraceGraph, testId: 'menu-item-TraceGraph' },
218+
{ type: ETraceViewType.TraceStatistics, testId: 'menu-item-TraceStatistics' },
219+
{ type: ETraceViewType.TraceSpansView, testId: 'menu-item-TraceSpansView' },
220+
{ type: ETraceViewType.TraceFlamegraph, testId: 'menu-item-TraceFlamegraph' },
111221
];
112222

113-
viewInteractions.forEach(({ link, trackFn, propViewType }, i) => {
114-
if (propViewType) {
115-
wrapper.setProps({
116-
viewType: propViewType,
117-
});
118-
}
119-
expect(props.onTraceViewChange).toHaveBeenCalledTimes(i);
120-
expect(trackFn).not.toHaveBeenCalled();
121-
122-
getLink(link).onClick();
123-
expect(props.onTraceViewChange).toHaveBeenCalledTimes(i + 1);
124-
viewInteractions.forEach(({ trackFn: fn }, j) => {
125-
expect(fn).toHaveBeenCalledTimes(j <= i ? 1 : 0);
126-
});
223+
viewTypes.forEach(({ type, testId }) => {
224+
cleanup();
225+
renderComponent({ viewType: type });
226+
expect(screen.queryByTestId(testId)).not.toBeInTheDocument();
127227
});
128228
});
129229
});

packages/jaeger-ui/src/components/TracePage/TracePageHeader/__snapshots__/AltViewOptions.test.js.snap

Lines changed: 0 additions & 77 deletions
This file was deleted.

0 commit comments

Comments
 (0)