Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

e2e: added money request flow e2e test #52751

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3af050b
e2e: added money request flow e2e test
kirillzyusko Nov 12, 2024
c55d0de
fix: nativeID -> testID
kirillzyusko Nov 19, 2024
0994d6f
refactor: removed unused code
kirillzyusko Nov 19, 2024
513340f
fix: flat test structure
kirillzyusko Nov 19, 2024
f3ed8a1
fix: clear previous field to make sure you always can type a new one
kirillzyusko Nov 19, 2024
2123207
fix: remove hardcoded intervals from the test
kirillzyusko Nov 19, 2024
4913fdc
fix: TS types
kirillzyusko Nov 19, 2024
606ac25
fix: ci
kirillzyusko Nov 19, 2024
3b54445
fix: speed up clear command
kirillzyusko Nov 21, 2024
e8ceb29
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Dec 17, 2024
7e14df1
update BaseTextInput
perunt Dec 17, 2024
128b4e7
clean duplications
perunt Dec 18, 2024
a41b9bb
fix: duplicated identifiers
kirillzyusko Dec 18, 2024
335eb12
fix: move OPEN_SUBMIT_EXPENSE_CONTACT start to app code
kirillzyusko Dec 18, 2024
04cade1
fix: move OPEN_SUBMIT_EXPENSE_APPROVE start to app code
kirillzyusko Dec 18, 2024
ab157c0
fix: no external navigation dispatches
kirillzyusko Dec 18, 2024
c2f9221
Merge branch 'main' into e2e/money-request-flow
kirillzyusko Dec 18, 2024
545e896
fix: ci
kirillzyusko Dec 19, 2024
9d39e16
docs: update documentation
kirillzyusko Dec 19, 2024
951543c
Merge branch 'main' into e2e/money-request-flow
kirillzyusko Dec 20, 2024
1b5e9d7
fix: post merge fixes
kirillzyusko Dec 20, 2024
9e660ba
fix: new eslint rules
kirillzyusko Dec 20, 2024
e4c77b7
fix: new eslint rules
kirillzyusko Dec 20, 2024
ef04655
fix: new eslint rules
kirillzyusko Dec 20, 2024
b6f51f2
Merge branch 'main' into e2e/money-request-flow
kirillzyusko Jan 3, 2025
6c69904
fix: prettier
kirillzyusko Jan 3, 2025
7bc9f08
Merge branch 'main' into e2e/money-request-flow
kirillzyusko Jan 7, 2025
1019668
fix: new eslint rules in
perunt Jan 21, 2025
e25f200
fix after merge
perunt Jan 21, 2025
e21c158
Merge branch 'e2e/money-request-flow' of https://github.com/margelo/e…
perunt Jan 21, 2025
3f58021
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Jan 21, 2025
204a90a
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 6, 2025
12020d5
fix BaseTextInput after the merge
perunt Feb 6, 2025
571e10a
FloatingActionButton fix id
perunt Feb 6, 2025
6ac6946
fix id for PopoverMenu
perunt Feb 6, 2025
066807f
lint
perunt Feb 6, 2025
8486a23
fix: new eslint rules
perunt Feb 6, 2025
1fb95a9
fix: new eslint rules
perunt Feb 6, 2025
7c7f2ec
bring back Tooltip
perunt Feb 6, 2025
490ccf4
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 11, 2025
4db92d6
fix after merge
perunt Feb 11, 2025
1cbfd6e
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 14, 2025
11c12f5
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 18, 2025
5eca3fd
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 18, 2025
82fb23d
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 18, 2025
c953dd2
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 18, 2025
5740d37
Merge branch 'main' of https://github.com/Expensify/App into e2e/mone…
perunt Feb 21, 2025
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
4 changes: 3 additions & 1 deletion contributingGuides/PERFORMANCE_METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Project is using Firebase for tracking these metrics. However, not all of them a
| `open_report_thread` | ✅ | Time taken to open a thread in a report.<br><br>**Platforms:** All | Starts when user presses Report Action Item. | Stops when the `ReportActionsList` finishes laying out. |
| `send_message` | ✅ | Time taken to send a message.<br><br>**Platforms:** All | Starts when the new message is sent. | Stops when the message is being rendered in the chat. |
| `pusher_ping_pong` | ✅ | The time it takes to receive a PONG event through Pusher.<br><br>**Platforms:** All | Starts every minute and repeats on the minute. | Stops when the event is received from the server. |
| `open_submit_expense` | ❌ | Time taken to open "Submit expense" screen.<br><br>**Platforms:** All | Starts when the `Create expense` is pressed. | Stops when the `IOURequestStartPage` finishes laying out. |
| `open_submit_expense_contact` | ❌ | Time taken to Submit expense screen.<br><br>**Platforms:** All | Starts when the `Next` button on `Create expense` screen is pressed. | Stops when the `IOURequestStepParticipants` finishes laying out. |
| `open_submit_expense_approve` | ❌ | Time taken to Submit expense screen.<br><br>**Platforms:** All | Starts when the `Contact` on `Choose recipient` screen is selected. | Stops when the `IOURequestStepConfirmation` finishes laying out. |

## Documentation Maintenance

Expand All @@ -38,7 +41,6 @@ To ensure this documentation remains accurate and useful, please adhere to the f

4. **Code Location Changes**: If the placement of a metric in the code changes, update the "Start time" and "End time" columns to reflect the new location.


## Additional Resources

- [Firebase Documentation](https://firebase.google.com/docs)
Expand Down
3 changes: 3 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1390,6 +1390,9 @@ const CONST = {
SIDEBAR_LOADED: 'sidebar_loaded',
LOAD_SEARCH_OPTIONS: 'load_search_options',
SEND_MESSAGE: 'send_message',
OPEN_SUBMIT_EXPENSE: 'open_submit_expense',
OPEN_SUBMIT_EXPENSE_CONTACT: 'open_submit_expense_contact',
OPEN_SUBMIT_EXPENSE_APPROVE: 'open_submit_expense_approve',
Comment on lines +1415 to +1417
Copy link
Contributor

Choose a reason for hiding this comment

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

@adhorodyski any feedback here on the event names?

Copy link
Contributor

Choose a reason for hiding this comment

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

looking into it

APPLY_AIRSHIP_UPDATES: 'apply_airship_updates',
APPLY_PUSHER_UPDATES: 'apply_pusher_updates',
APPLY_HTTPS_UPDATES: 'apply_https_updates',
Expand Down
1 change: 1 addition & 0 deletions src/components/BigNumberPad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function BigNumberPad({numberPressed, longPressHandlerStateChanged = () => {}, i
e.preventDefault();
}}
isLongPressDisabled={isLongPressDisabled}
testID={`button_${column}`}
/>
);
})}
Expand Down
6 changes: 3 additions & 3 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ type ButtonProps = Partial<ChildrenProps> & {
/** Id to use for this button */
id?: string;

/** Used to locate this button in ui tests */
testID?: string;

/** Accessibility label for the component */
accessibilityLabel?: string;

Expand All @@ -145,6 +142,9 @@ type ButtonProps = Partial<ChildrenProps> & {

/** Whether the Enter keyboard listening is active whether or not the screen that contains the button is focused */
isPressOnEnterActive?: boolean;

/** The testID of the button. Used to locate this view in end-to-end tests. */
testID?: string;
};

type KeyboardShortcutComponentProps = Pick<ButtonProps, 'isDisabled' | 'isLoading' | 'onPress' | 'pressOnEnter' | 'allowBubble' | 'enterKeyEventListenerPriority' | 'isPressOnEnterActive'>;
Expand Down
1 change: 1 addition & 0 deletions src/components/FloatingActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
onLongPress={() => {}}
role={role}
shouldUseHapticsOnLongPress={false}
testID="floating-action-button"
>
<Animated.View style={[styles.floatingActionButton, animatedStyle]}>
<Svg
Expand Down
33 changes: 18 additions & 15 deletions src/components/MoneyRequestAmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} fr
import type {NativeSyntheticEvent, StyleProp, TextStyle, ViewStyle} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import {useMouseContext} from '@hooks/useMouseContext';
import * as Browser from '@libs/Browser';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import {isMobileSafari} from '@libs/Browser';
import {convertToFrontendAmountAsString, getCurrencyDecimals} from '@libs/CurrencyUtils';
import getOperatingSystem from '@libs/getOperatingSystem';
import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
import {replaceAllDigits, replaceCommasWithPeriod, stripCommaFromAmount, stripDecimalsFromAmount, stripSpacesFromAmount, validateAmount} from '@libs/MoneyRequestUtils';
import shouldIgnoreSelectionWhenUpdatedManually from '@libs/shouldIgnoreSelectionWhenUpdatedManually';
import CONST from '@src/CONST';
import isTextInputFocused from './TextInput/BaseTextInput/isTextInputFocused';
Expand Down Expand Up @@ -92,6 +92,9 @@ type MoneyRequestAmountInputProps = {

/** The width of inner content */
contentWidth?: number;

/** The testID of the input. Used to locate this view in end-to-end tests. */
testID?: string;
} & Pick<TextInputWithCurrencySymbolProps, 'autoGrowExtraSpace'>;

type Selection = {
Expand All @@ -107,7 +110,7 @@ const getNewSelection = (oldSelection: Selection, prevLength: number, newLength:
return {start: cursorPosition, end: cursorPosition};
};

const defaultOnFormatAmount = (amount: number, currency?: string) => CurrencyUtils.convertToFrontendAmountAsString(amount, currency ?? CONST.CURRENCY.USD);
const defaultOnFormatAmount = (amount: number, currency?: string) => convertToFrontendAmountAsString(amount, currency ?? CONST.CURRENCY.USD);

function MoneyRequestAmountInput(
{
Expand All @@ -129,6 +132,7 @@ function MoneyRequestAmountInput(
autoGrow = true,
autoGrowExtraSpace,
contentWidth,
testID,
...props
}: MoneyRequestAmountInputProps,
forwardedRef: ForwardedRef<BaseTextInputRef>,
Expand All @@ -139,7 +143,7 @@ function MoneyRequestAmountInput(

const amountRef = useRef<string | undefined>(undefined);

const decimals = CurrencyUtils.getCurrencyDecimals(currency);
const decimals = getCurrencyDecimals(currency);
const selectedAmountAsString = amount ? onFormatAmount(amount, currency) : '';

const [currentAmount, setCurrentAmount] = useState(selectedAmountAsString);
Expand All @@ -161,13 +165,11 @@ function MoneyRequestAmountInput(
(newAmount: string) => {
// Remove spaces from the newAmount value because Safari on iOS adds spaces when pasting a copied value
// More info: https://github.com/Expensify/App/issues/16974
const newAmountWithoutSpaces = MoneyRequestUtils.stripSpacesFromAmount(newAmount);
const finalAmount = newAmountWithoutSpaces.includes('.')
? MoneyRequestUtils.stripCommaFromAmount(newAmountWithoutSpaces)
: MoneyRequestUtils.replaceCommasWithPeriod(newAmountWithoutSpaces);
const newAmountWithoutSpaces = stripSpacesFromAmount(newAmount);
const finalAmount = newAmountWithoutSpaces.includes('.') ? stripCommaFromAmount(newAmountWithoutSpaces) : replaceCommasWithPeriod(newAmountWithoutSpaces);
// Use a shallow copy of selection to trigger setSelection
// More info: https://github.com/Expensify/App/issues/16385
if (!MoneyRequestUtils.validateAmount(finalAmount, decimals)) {
if (!validateAmount(finalAmount, decimals)) {
setSelection((prevSelection) => ({...prevSelection}));
return;
}
Expand All @@ -176,7 +178,7 @@ function MoneyRequestAmountInput(

willSelectionBeUpdatedManually.current = true;
let hasSelectionBeenSet = false;
const strippedAmount = MoneyRequestUtils.stripCommaFromAmount(finalAmount);
const strippedAmount = stripCommaFromAmount(finalAmount);
amountRef.current = strippedAmount;
setCurrentAmount((prevAmount) => {
const isForwardDelete = prevAmount.length > strippedAmount.length && forwardDeletePressedRef.current;
Expand Down Expand Up @@ -233,12 +235,12 @@ function MoneyRequestAmountInput(
// Modifies the amount to match the decimals for changed currency.
useEffect(() => {
// If the changed currency supports decimals, we can return
if (MoneyRequestUtils.validateAmount(currentAmount, decimals)) {
if (validateAmount(currentAmount, decimals)) {
return;
}

// If the changed currency doesn't support decimals, we can strip the decimals
setNewAmount(MoneyRequestUtils.stripDecimalsFromAmount(currentAmount));
setNewAmount(stripDecimalsFromAmount(currentAmount));

// we want to update only when decimals change (setNewAmount also changes when decimals change).
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
Expand All @@ -249,7 +251,7 @@ function MoneyRequestAmountInput(
*/
const textInputKeyPress = ({nativeEvent}: NativeSyntheticEvent<KeyboardEvent>) => {
const key = nativeEvent?.key.toLowerCase();
if (Browser.isMobileSafari() && key === CONST.PLATFORM_SPECIFIC_KEYS.CTRL.DEFAULT) {
if (isMobileSafari() && key === CONST.PLATFORM_SPECIFIC_KEYS.CTRL.DEFAULT) {
// Optimistically anticipate forward-delete on iOS Safari (in cases where the Mac Accessiblity keyboard is being
// used for input). If the Control-D shortcut doesn't get sent, the ref will still be reset on the next key press.
forwardDeletePressedRef.current = true;
Expand All @@ -276,7 +278,7 @@ function MoneyRequestAmountInput(
});
}, [amount, currency, onFormatAmount, formatAmountOnBlur, maxLength]);

const formattedAmount = MoneyRequestUtils.replaceAllDigits(currentAmount, toLocaleDigit);
const formattedAmount = replaceAllDigits(currentAmount, toLocaleDigit);

const {setMouseDown, setMouseUp} = useMouseContext();
const handleMouseDown = (e: React.MouseEvent<Element, MouseEvent>) => {
Expand Down Expand Up @@ -340,6 +342,7 @@ function MoneyRequestAmountInput(
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
contentWidth={contentWidth}
testID={testID}
/>
);
}
Expand Down
20 changes: 12 additions & 8 deletions src/components/PopoverMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
import * as Modal from '@userActions/Modal';
import {isSafari} from '@libs/Browser';
import {close} from '@userActions/Modal';
import CONST from '@src/CONST';
import type {AnchorPosition} from '@src/styles';
import type {PendingAction} from '@src/types/onyx/OnyxCommon';
Expand Down Expand Up @@ -54,6 +54,9 @@ type PopoverMenuItem = MenuItemProps & {
shouldCloseAllModals?: boolean;

pendingAction?: PendingAction;

/** Test identifier used to find elements in unit and e2e tests */
testID?: string;
};

type PopoverModalProps = Pick<ModalProps, 'animationIn' | 'animationOut' | 'animationInTiming'>;
Expand Down Expand Up @@ -177,7 +180,7 @@ function PopoverMenu({
shouldUseScrollView = false,
shouldUpdateFocusedIndex = true,
shouldUseModalPaddingStyle,
testID,
testID: testIDProp,
}: PopoverMenuProps) {
const styles = useThemeStyles();
const theme = useTheme();
Expand All @@ -202,9 +205,9 @@ function PopoverMenu({
setEnteredSubMenuIndexes([...enteredSubMenuIndexes, index]);
const selectedSubMenuItemIndex = selectedItem?.subMenuItems.findIndex((option) => option.isSelected);
setFocusedIndex(selectedSubMenuItemIndex);
} else if (selectedItem.shouldCallAfterModalHide && !Browser.isSafari()) {
} else if (selectedItem.shouldCallAfterModalHide && !isSafari()) {
onItemSelected?.(selectedItem, index);
Modal.close(
close(
() => {
selectedItem.onSelected?.();
},
Expand Down Expand Up @@ -255,7 +258,7 @@ function PopoverMenu({
};

const renderedMenuItems = currentMenuItems.map((item, menuIndex) => {
const {text, onSelected, subMenuItems, shouldCallAfterModalHide, ...menuItemProps} = item;
const {text, onSelected, subMenuItems, shouldCallAfterModalHide, testID, ...menuItemProps} = item;
return (
<OfflineWithFeedback
// eslint-disable-next-line react/no-array-index-key
Expand All @@ -265,7 +268,8 @@ function PopoverMenu({
<FocusableMenuItem
// eslint-disable-next-line react/no-array-index-key
key={`${item.text}_${menuIndex}`}
pressableTestID={`PopoverMenuItem-${item.text}`}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
pressableTestID={testID || `PopoverMenuItem-${item.text}`}
title={text}
onPress={() => selectItem(menuIndex)}
focused={focusedIndex === menuIndex}
Expand Down Expand Up @@ -362,7 +366,7 @@ function PopoverMenu({
restoreFocusType={restoreFocusType}
innerContainerStyle={innerContainerStyle}
shouldUseModalPaddingStyle={shouldUseModalPaddingStyle}
testID={testID}
testID={testIDProp}
>
<FocusTrapForModal active={isVisible}>
<View style={[isSmallScreenWidth ? {maxHeight: windowHeight - 250} : styles.createMenuContainer, containerStyles]}>
Expand Down
15 changes: 9 additions & 6 deletions src/components/Pressable/GenericPressable/index.e2e.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import React, {forwardRef, useEffect} from 'react';
import {DeviceEventEmitter} from 'react-native';
import GenericPressable from './implementation';
import type {PressableRef} from './types';
import type PressableProps from './types';

const pressableRegistry = new Map<string, PressableProps>();

function getPressableProps(nativeID: string): PressableProps | undefined {
return pressableRegistry.get(nativeID);
function getPressableProps(testId: string): PressableProps | undefined {
return pressableRegistry.get(testId);
}

function E2EGenericPressableWrapper(props: PressableProps, ref: PressableRef) {
useEffect(() => {
const nativeId = props.nativeID;
if (!nativeId) {
const testId = props.testID;
if (!testId) {
return;
}
console.debug(`[E2E] E2EGenericPressableWrapper: Registering pressable with nativeID: ${nativeId}`);
pressableRegistry.set(nativeId, props);
console.debug(`[E2E] E2EGenericPressableWrapper: Registering pressable with testID: ${testId}`);
pressableRegistry.set(testId, props);

DeviceEventEmitter.emit('onBecameVisible', testId);
}, [props]);

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/Search/SearchRouter/SearchButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function SearchButton({style}: SearchButtonProps) {
<Tooltip text={translate('common.search')}>
<PressableWithoutFeedback
ref={pressableRef}
nativeID="searchButton"
testID="searchButton"
accessibilityLabel={translate('common.search')}
style={[styles.flexRow, styles.touchableButtonImage, style]}
// eslint-disable-next-line react-compiler/react-compiler
Expand Down
2 changes: 2 additions & 0 deletions src/components/SelectionList/BaseListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function BaseListItem<TItem extends ListItem>({
onFocus = () => {},
hoverStyle,
onLongPressRow,
testID,
}: BaseListItemProps<TItem>) {
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -107,6 +108,7 @@ function BaseListItem<TItem extends ListItem>({
onMouseLeave={handleMouseLeave}
tabIndex={item.tabIndex}
wrapperStyle={pressableWrapperStyle}
testID={testID}
>
<View
testID={`${CONST.BASE_LIST_ITEM_TEST_ID}${item.keyForList}`}
Expand Down
1 change: 1 addition & 0 deletions src/components/SelectionList/InviteMemberListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function InviteMemberListItem<TItem extends ListItem>({
onFocus={onFocus}
shouldSyncFocus={shouldSyncFocus}
shouldDisplayRBR={!shouldShowCheckBox}
testID={item.text}
>
{(hovered?: boolean) => (
<>
Expand Down
2 changes: 2 additions & 0 deletions src/components/SelectionList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ type BaseListItemProps<TItem extends ListItem> = CommonListItemProps<TItem> & {
hoverStyle?: StyleProp<ViewStyle>;
/** Errors that this user may contain */
shouldDisplayRBR?: boolean;
/** Test ID of the component. Used to locate this view in end-to-end tests. */
testID?: string;
};

type UserListItemProps<TItem extends ListItem> = ListItemProps<TItem> & {
Expand Down
6 changes: 4 additions & 2 deletions src/components/TabSelector/TabSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ type TabSelectorProps = MaterialTopTabBarProps & {
type IconAndTitle = {
icon: IconAsset;
title: string;
testID?: string;
};

function getIconAndTitle(route: string, translate: LocaleContextProps['translate']): IconAndTitle {
switch (route) {
case CONST.TAB_REQUEST.MANUAL:
return {icon: Expensicons.Pencil, title: translate('tabSelector.manual')};
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there another way we could do this? I don't love updating this function only in this certain case...

Copy link
Contributor

Choose a reason for hiding this comment

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

Let me check it

Copy link
Contributor

Choose a reason for hiding this comment

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

We need to mark the elements we're waiting for before rendering so we can manipulate them further.
Instead of hardcoding a testID for just one case, we could generate it dynamically based on the route, but that would add unnecessary complexity and feel wrong.
Since we'll likely be adding more E2E tests, this generic function, which creates components for multiple screens, will also assign an ID to each element

Copy link
Contributor

Choose a reason for hiding this comment

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

can we maybe just update the function to getIconTitleAndTestID and have it return a testID (even if unused) for all options? I think that would make me feel better haha

Copy link
Contributor

Choose a reason for hiding this comment

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

It makes sense, I'll add this right now. Thanks!

return {icon: Expensicons.Pencil, title: translate('tabSelector.manual'), testID: 'manual'};
case CONST.TAB_REQUEST.SCAN:
return {icon: Expensicons.ReceiptScan, title: translate('tabSelector.scan')};
case CONST.TAB.NEW_CHAT:
Expand Down Expand Up @@ -70,7 +71,7 @@ function TabSelector({state, navigation, onTabPress = () => {}, position, onFocu
const activeOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: true, affectedTabs: affectedAnimatedTabs, position, isActive});
const inactiveOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: false, affectedTabs: affectedAnimatedTabs, position, isActive});
const backgroundColor = getBackgroundColor({routesLength: state.routes.length, tabIndex: index, affectedTabs: affectedAnimatedTabs, theme, position, isActive});
const {icon, title} = getIconAndTitle(route.name, translate);
const {icon, title, testID} = getIconAndTitle(route.name, translate);

const onPress = () => {
if (isActive) {
Expand Down Expand Up @@ -103,6 +104,7 @@ function TabSelector({state, navigation, onTabPress = () => {}, position, onFocu
inactiveOpacity={inactiveOpacity}
backgroundColor={backgroundColor}
isActive={isActive}
testID={testID}
shouldShowLabelWhenInactive={shouldShowLabelWhenInactive}
/>
);
Expand Down
5 changes: 5 additions & 0 deletions src/components/TabSelector/TabSelectorItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ type TabSelectorItemProps = {

/** Whether to show the label when the tab is inactive */
shouldShowLabelWhenInactive?: boolean;

/** Test identifier used to find elements in unit and e2e tests */
testID?: string;
};

function TabSelectorItem({
Expand All @@ -46,6 +49,7 @@ function TabSelectorItem({
inactiveOpacity = 1,
isActive = false,
shouldShowLabelWhenInactive = true,
testID,
}: TabSelectorItemProps) {
const styles = useThemeStyles();
const [isHovered, setIsHovered] = useState(false);
Expand All @@ -64,6 +68,7 @@ function TabSelectorItem({
onHoverOut={() => setIsHovered(false)}
role={CONST.ROLE.BUTTON}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
testID={testID}
>
<TabIcon
icon={icon}
Expand Down
Loading
Loading