Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions src/components/TabSelector/TabSelectorItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {useState} from 'react';
import {Animated} from 'react-native';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Tooltip from '@components/Tooltip';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import type IconAsset from '@src/types/utils/IconAsset';
Expand Down Expand Up @@ -49,29 +50,34 @@ function TabSelectorItem({
const [isHovered, setIsHovered] = useState(false);

return (
<AnimatedPressableWithFeedback
accessibilityLabel={title}
style={[styles.tabSelectorButton, styles.tabBackground(isHovered, isActive, backgroundColor), styles.userSelectNone]}
wrapperStyle={[styles.flexGrow1]}
onPress={onPress}
onHoverIn={() => setIsHovered(true)}
onHoverOut={() => setIsHovered(false)}
role={CONST.ROLE.BUTTON}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
<Tooltip
shouldRender={!shouldShowLabelWhenInactive && !isActive}
text={title}
>
<TabIcon
icon={icon}
activeOpacity={styles.tabOpacity(isHovered, isActive, activeOpacity, inactiveOpacity).opacity}
inactiveOpacity={styles.tabOpacity(isHovered, isActive, inactiveOpacity, activeOpacity).opacity}
/>
{(shouldShowLabelWhenInactive || isActive) && (
<TabLabel
title={title}
<AnimatedPressableWithFeedback
accessibilityLabel={title}
style={[styles.tabSelectorButton, styles.tabBackground(isHovered, isActive, backgroundColor), styles.userSelectNone]}
wrapperStyle={[styles.flexGrow1]}
onPress={onPress}
onHoverIn={() => setIsHovered(true)}
onHoverOut={() => setIsHovered(false)}
role={CONST.ROLE.BUTTON}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
<TabIcon
icon={icon}
activeOpacity={styles.tabOpacity(isHovered, isActive, activeOpacity, inactiveOpacity).opacity}
inactiveOpacity={styles.tabOpacity(isHovered, isActive, inactiveOpacity, activeOpacity).opacity}
/>
)}
</AnimatedPressableWithFeedback>
{(shouldShowLabelWhenInactive || isActive) && (
<TabLabel
title={title}
activeOpacity={styles.tabOpacity(isHovered, isActive, activeOpacity, inactiveOpacity).opacity}
inactiveOpacity={styles.tabOpacity(isHovered, isActive, inactiveOpacity, activeOpacity).opacity}
/>
)}
</AnimatedPressableWithFeedback>
</Tooltip>
);
}

Expand Down
95 changes: 95 additions & 0 deletions tests/ui/components/TabSelectorItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {fireEvent, render, screen} from '@testing-library/react-native';
import React from 'react';
import TabSelectorItem from '@components/TabSelector/TabSelectorItem';
import Tooltip from '@components/Tooltip';
import CONST from '@src/CONST';

// Mock the Tooltip component since it uses portals which aren't supported in RNTL
jest.mock('@components/Tooltip', () => {
return jest.fn(({children, shouldRender, text}: {children: React.ReactNode; shouldRender: boolean; text: string}) => {
return (
<>
{shouldRender && <div data-testid="tooltip">{text}</div>}
{children}
</>
);
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we just test with toHaveBeenCalledWith, I think we can simply mock with empty jest.fn

jest.mock('@components/Tooltip', () => jest.fn());
jest.mock('@components/Tooltip'); // factory param already have empty function as a default


describe('TabSelectorItem Component', () => {
const defaultProps = {
title: 'Test Tab',
icon: 'icon-home',
onPress: jest.fn(),
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused parameters, we just use the title here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also use it below as a const instead of duplicate initialization in title="Test Tab"


beforeEach(() => {
jest.clearAllMocks();
});

it('should show tooltip for inactive tab with hidden label', () => {
// Given an inactive tab with a hidden label
render(
<TabSelectorItem
title="Test Tab"
shouldShowLabelWhenInactive={false}
isActive={false}
/>,
);

// When hovering over the tab button
const button = screen.getByRole(CONST.ROLE.BUTTON, {name: defaultProps.title});
fireEvent(button, 'hoverIn');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think hoverIn will not trigger anything because we mocked up the Tooltip. Also, it looks related to Tooltip test not TabSelectorItem test.
Let's remove it, the below test that check the Tooltip is called with the correct props is a good enough.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the valuable feedback, updated.


// Then the tooltip should be rendered with correct content because the label is hidden
expect(Tooltip).toHaveBeenCalledWith(
expect.objectContaining({
shouldRender: true,
text: defaultProps.title,
}),
expect.any(Object),
);
});

it('should not show tooltip for active tab', () => {
// Given an active tab
render(
<TabSelectorItem
title="Test Tab"
shouldShowLabelWhenInactive={false}
isActive
/>,
);

// When hovering over the tab button
// Then the tooltip should not render because the tab is active
expect(Tooltip).toHaveBeenCalledWith(
expect.objectContaining({
shouldRender: false,
text: defaultProps.title,
}),
expect.any(Object),
);
});

it('should not show tooltip when label is visible', () => {
// Given an inactive tab with visible label
render(
<TabSelectorItem
title="Test Tab"
shouldShowLabelWhenInactive
isActive={false}
/>,
);

// When hovering over the tab button
// Then the tooltip should not render because the label is already visible
expect(Tooltip).toHaveBeenCalledWith(
expect.objectContaining({
shouldRender: false,
text: defaultProps.title,
}),
expect.any(Object),
);
});
});