Skip to content

Commit ad84ea6

Browse files
authored
Migrate HopsSelector tests (#2746)
## Which problem is this PR solving? - Part of #1668 ## Description of the changes - Migrates `HopsSelector` test ## How was this change tested? - Test itself. ## Checklist - [x] I have read https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md - [x] I have signed all commits - [x] I have added unit tests for the new functionality - [x] I have run lint and test steps successfully - for `jaeger`: `make lint test` - for `jaeger-ui`: `npm run lint` and `npm run test` --------- Signed-off-by: nojaf <[email protected]>
1 parent f5adf84 commit ad84ea6

File tree

5 files changed

+269
-530
lines changed

5 files changed

+269
-530
lines changed

packages/jaeger-ui/src/components/DeepDependencies/Header/HopsSelector/Selector.test.js

Lines changed: 64 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,86 +12,93 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import * as React from 'react';
16-
import { shallow } from 'enzyme';
17-
import { Popover } from 'antd';
15+
import React from 'react';
16+
import { render, screen, fireEvent } from '@testing-library/react';
17+
import '@testing-library/jest-dom';
1818

19-
import { EDirection } from '../../../../model/ddg/types';
19+
import { EDirection, ECheckedStatus } from '../../../../model/ddg/types';
2020
import Selector from './Selector';
2121

22+
// Mock the tracking function as it's called within the component
23+
jest.mock('../../index.track', () => ({
24+
trackHopChange: jest.fn(),
25+
}));
26+
2227
describe('Selector', () => {
2328
const handleClick = jest.fn();
24-
const hops = ['full', 'partial', 'full', 'empty', 'empty'];
25-
const makeHops = (fullnessArr, direction = EDirection.Downstream) =>
26-
fullnessArr.map((fullness, i) => ({
27-
distance: i * direction,
28-
fullness,
29-
}));
30-
const props = {
29+
const hopsData = [
30+
{ distance: 0, fullness: ECheckedStatus.Full },
31+
{ distance: 1, fullness: ECheckedStatus.Partial },
32+
{ distance: 2, fullness: ECheckedStatus.Full },
33+
{ distance: 3, fullness: ECheckedStatus.Empty },
34+
{ distance: 4, fullness: ECheckedStatus.Empty },
35+
];
36+
37+
const defaultProps = {
3138
furthestDistance: 2,
32-
furthestFullness: 'full',
33-
hops: makeHops(hops),
39+
furthestFullness: ECheckedStatus.Full,
40+
furthestFullDistance: 2,
41+
hops: hopsData,
3442
direction: EDirection.Downstream,
3543
handleClick,
3644
};
37-
let wrapper;
38-
function getPopoverButtons() {
39-
const popoverContent = wrapper.find(Popover).prop('content');
40-
return shallow(<div>{popoverContent}</div>).find('button');
41-
}
4245

4346
beforeEach(() => {
44-
wrapper = shallow(<Selector {...props} />);
47+
handleClick.mockClear();
48+
// Clean up document body to prevent test interference
49+
document.body.innerHTML = '';
4550
});
4651

47-
it('renders message when there are no options', () => {
48-
const message = shallow(<Selector hops={makeHops(['full'])} />);
49-
expect(message).toMatchSnapshot();
52+
it('renders message when there are not enough hops', () => {
53+
// Render with only one hop
54+
render(<Selector {...defaultProps} hops={[{ distance: 0, fullness: ECheckedStatus.Full }]} />);
55+
expect(screen.getByText('No downstream hops')).toBeInTheDocument();
5056
});
5157

52-
it('renders buttons with expected text and classNames', () => {
53-
expect(wrapper).toMatchSnapshot();
54-
});
58+
it('renders buttons with expected text and classes for Downstream', () => {
59+
render(<Selector {...defaultProps} />);
60+
61+
// Check main display buttons (furthest visible and max hops)
62+
expect(screen.getByTestId('hop-down-2')).toHaveTextContent('2');
63+
expect(screen.getByTestId('hop-down-2')).toHaveClass('is-Full');
64+
expect(screen.getByTestId('hop-down-4')).toHaveTextContent('4');
65+
expect(screen.getByTestId('hop-down-4')).toHaveClass('is-Empty');
5566

56-
it('renders upstream hops with negative distance correctly', () => {
57-
const upstreamProps = {
58-
direction: EDirection.Upstream,
59-
furthestDistance: EDirection.Upstream * props.furthestDistance,
60-
furthestFullness: 'full',
61-
hops: makeHops(hops, EDirection.Upstream),
62-
handleClick,
63-
};
64-
const upstreamWrapper = shallow(<Selector {...upstreamProps} />);
65-
expect(upstreamWrapper).toMatchSnapshot();
67+
// Check label
68+
expect(screen.getByText('Downstream hops')).toBeInTheDocument();
6669
});
6770

68-
it('calls handleClick with correct arguments from label buttons', () => {
69-
const buttons = wrapper.find('button');
70-
expect(buttons.length).toBe(2);
71+
it('renders buttons with expected text and classes for Upstream', () => {
72+
const upstreamHops = hopsData.map(h => ({ ...h, distance: -h.distance }));
73+
render(
74+
<Selector
75+
{...defaultProps}
76+
direction={EDirection.Upstream}
77+
furthestDistance={-2}
78+
furthestFullDistance={-2}
79+
hops={upstreamHops}
80+
/>
81+
);
7182

72-
buttons.first().simulate('click');
73-
expect(handleClick).toHaveBeenLastCalledWith(props.furthestDistance, props.direction);
83+
// Check main display buttons (abs value is used for display)
84+
expect(screen.getByTestId('hop-up-2')).toHaveTextContent('2');
85+
expect(screen.getByTestId('hop-up-2')).toHaveClass('is-Full');
86+
expect(screen.getByTestId('hop-up-4')).toHaveTextContent('4');
87+
expect(screen.getByTestId('hop-up-4')).toHaveClass('is-Empty');
7488

75-
buttons.last().simulate('click');
76-
expect(handleClick).toHaveBeenLastCalledWith(props.hops.length - 1, props.direction);
89+
// Check label
90+
expect(screen.getByText('Upstream hops')).toBeInTheDocument();
7791
});
7892

79-
it('calls handleClick with correct arguments from popover buttons', () => {
80-
const expectedDistances = [1, 0, 1, 2, 3, 4, 3];
81-
const popoverButtons = getPopoverButtons();
82-
expect(popoverButtons.length).toBe(expectedDistances.length);
83-
84-
popoverButtons.forEach((btn, i) => {
85-
btn.simulate('click');
86-
expect(handleClick).toHaveBeenLastCalledWith(expectedDistances[i], props.direction);
87-
});
88-
});
93+
it('calls handleClick with correct arguments from label buttons', () => {
94+
render(<Selector {...defaultProps} />);
8995

90-
it('disables increment/decrement buttons', () => {
91-
wrapper.setProps({ furthestDistance: 0 });
92-
expect(getPopoverButtons().first().prop('disabled')).toBe(true);
96+
// Furthest visible hop button
97+
fireEvent.click(screen.getByTestId('hop-down-2'));
98+
expect(handleClick).toHaveBeenCalledWith(2, EDirection.Downstream);
9399

94-
wrapper.setProps({ furthestDistance: hops.length - 1 });
95-
expect(getPopoverButtons().last().prop('disabled')).toBe(true);
100+
// Max hop button (delimiter)
101+
fireEvent.click(screen.getByTestId('hop-down-4'));
102+
expect(handleClick).toHaveBeenCalledWith(4, EDirection.Downstream);
96103
});
97104
});

packages/jaeger-ui/src/components/DeepDependencies/Header/HopsSelector/Selector.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,15 @@ export default class Selector extends PureComponent<TProps> {
4646
showChevron?: number
4747
) => {
4848
const { direction } = this.props;
49+
const testIdSuffix = `${direction === EDirection.Downstream ? 'down' : 'up'}-${Math.abs(distance)}`;
4950
return (
5051
<React.Fragment key={`${distance} ${direction} ${suffix}`}>
5152
{Boolean(showChevron) && <IoChevronForward className={`${CLASSNAME}--ChevronRight is-${fullness}`} />}
5253
<button
5354
className={`${CLASSNAME}--btn is-${fullness} ${CLASSNAME}--${suffix}`}
5455
type="button"
5556
onClick={() => this.handleClick(distance)}
57+
data-testid={`hop-${testIdSuffix}${suffix === 'popover-content' ? '-popover' : ''}`}
5658
>
5759
{Math.abs(distance)}
5860
</button>
@@ -76,6 +78,7 @@ export default class Selector extends PureComponent<TProps> {
7678
className={`${CLASSNAME}--decrement`}
7779
type="button"
7880
onClick={() => handleClick(furthestDistance - direction, direction)}
81+
data-testid={`decrement-${direction === EDirection.Downstream ? 'down' : 'up'}`}
7982
>
8083
-
8184
</button>
@@ -87,6 +90,7 @@ export default class Selector extends PureComponent<TProps> {
8790
className={`${CLASSNAME}--increment`}
8891
type="button"
8992
onClick={() => handleClick(furthestDistance + direction, direction)}
93+
data-testid={`increment-${direction === EDirection.Downstream ? 'down' : 'up'}`}
9094
>
9195
+
9296
</button>
@@ -103,18 +107,24 @@ export default class Selector extends PureComponent<TProps> {
103107

104108
return (
105109
<Popover
106-
arrowPointAtCenter
107-
content={[decrementBtn, ...hops.map(this.makeBtn), incrementBtn]}
110+
arrow={{ pointAtCenter: true }}
111+
content={
112+
<div data-testid={`popover-content-${direction === EDirection.Downstream ? 'down' : 'up'}`}>
113+
{[decrementBtn, ...hops.map(this.makeBtn), incrementBtn]}
114+
</div>
115+
}
108116
placement="bottom"
109117
title={`Visible ${lowercaseLabel}`}
110118
>
111-
<span className={CLASSNAME}>
119+
<span
120+
className={CLASSNAME}
121+
data-testid={`hops-selector-${direction === EDirection.Downstream ? 'down' : 'up'}`}
122+
>
112123
<ImSortAmountAsc className={`${CLASSNAME}--AscIcon is-${streamText}`} />
113124
{streamLabel}
114125
{furthestBtn}
115126
<span className={`${CLASSNAME}--delimiter`}>/</span>
116127
{delimiterBtn}
117-
{/* <IoChevronDown className={`${CLASSNAME}--ChevronDown`} /> */}
118128
<ChevronDown className="ub-ml1" />
119129
</span>
120130
</Popover>

0 commit comments

Comments
 (0)