Merge branch 'appium-v2' of github.com:RocketChat/Rocket.Chat.ReactNative into appium-v2

This commit is contained in:
Diego Mello 2022-04-08 15:05:15 -03:00
commit 31a02d3db3
38 changed files with 113 additions and 61 deletions

View File

@ -18,6 +18,7 @@ import { Handle } from './Handle';
import { IActionSheetItem, Item } from './Item'; import { IActionSheetItem, Item } from './Item';
import { TActionSheetOptions, TActionSheetOptionsItem } from './Provider'; import { TActionSheetOptions, TActionSheetOptionsItem } from './Provider';
import styles, { ITEM_HEIGHT } from './styles'; import styles, { ITEM_HEIGHT } from './styles';
import { testProps } from '../../lib/methods/testProps';
const getItemLayout = (data: TActionSheetOptionsItem[] | null | undefined, index: number) => ({ const getItemLayout = (data: TActionSheetOptionsItem[] | null | undefined, index: number) => ({
length: ITEM_HEIGHT, length: ITEM_HEIGHT,
@ -152,7 +153,7 @@ const ActionSheet = React.memo(
<> <>
<TapGestureHandler onHandlerStateChange={onBackdropPressed}> <TapGestureHandler onHandlerStateChange={onBackdropPressed}>
<Animated.View <Animated.View
testID='action-sheet-backdrop' {...testProps('action-sheet-backdrop')}
style={[ style={[
styles.backdrop, styles.backdrop,
{ {
@ -163,7 +164,7 @@ const ActionSheet = React.memo(
/> />
</TapGestureHandler> </TapGestureHandler>
<ScrollBottomSheet<TActionSheetOptionsItem> <ScrollBottomSheet<TActionSheetOptionsItem>
testID='action-sheet' {...testProps('action-sheet')}
ref={bottomSheetRef} ref={bottomSheetRef}
componentType='FlatList' componentType='FlatList'
snapPoints={snaps} snapPoints={snaps}

View File

@ -4,11 +4,12 @@ import { View } from 'react-native';
import styles from './styles'; import styles from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
export const Handle = React.memo(() => { export const Handle = React.memo(() => {
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<View style={[styles.handle, { backgroundColor: themes[theme].focusedBackground }]} testID='action-sheet-handle'> <View style={[styles.handle, { backgroundColor: themes[theme].focusedBackground }]} {...testProps('action-sheet-handle')}>
<View style={[styles.handleIndicator, { backgroundColor: themes[theme].auxiliaryText }]} /> <View style={[styles.handleIndicator, { backgroundColor: themes[theme].auxiliaryText }]} />
</View> </View>
); );

View File

@ -3,6 +3,7 @@ import { Text, View } from 'react-native';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons'; import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { Button } from './Button'; import { Button } from './Button';
import styles from './styles'; import styles from './styles';
@ -31,7 +32,7 @@ export const Item = React.memo(({ item, hide }: IActionSheetItem) => {
onPress={onPress} onPress={onPress}
style={[styles.item, { backgroundColor: themes[theme].focusedBackground }]} style={[styles.item, { backgroundColor: themes[theme].focusedBackground }]}
theme={theme} theme={theme}
testID={item.testID}> {...testProps(item.testID || '')}>
<CustomIcon name={item.icon} size={20} color={item.danger ? themes[theme].dangerColor : themes[theme].bodyText} /> <CustomIcon name={item.icon} size={20} color={item.danger ? themes[theme].dangerColor : themes[theme].bodyText} />
<View style={styles.titleContainer}> <View style={styles.titleContainer}>
<Text <Text

View File

@ -9,6 +9,7 @@ import { SubscriptionType } from '../../definitions/ISubscription';
import Emoji from '../markdown/Emoji'; import Emoji from '../markdown/Emoji';
import { IAvatar } from './interfaces'; import { IAvatar } from './interfaces';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
const Avatar = React.memo( const Avatar = React.memo(
({ ({
@ -88,7 +89,7 @@ const Avatar = React.memo(
} }
return ( return (
<View style={[avatarStyle, style]} testID='avatar'> <View style={[avatarStyle, style]} {...testProps('avatar')}>
{image} {image}
{children} {children}
</View> </View>

View File

@ -3,6 +3,7 @@ import { ButtonProps, StyleSheet, Text } from 'react-native';
import Touchable from 'react-native-platform-touchable'; import Touchable from 'react-native-platform-touchable';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { testProps } from '../../lib/methods/testProps';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import ActivityIndicator from '../ActivityIndicator'; import ActivityIndicator from '../ActivityIndicator';
@ -49,8 +50,21 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
}; };
render() { render() {
const { title, type, onPress, disabled, backgroundColor, color, loading, style, theme, fontSize, styleText, ...otherProps } = const {
this.props; title,
type,
onPress,
disabled,
backgroundColor,
color,
loading,
style,
theme,
fontSize,
styleText,
testID,
...otherProps
} = this.props;
const isPrimary = type === 'primary'; const isPrimary = type === 'primary';
let textColor = isPrimary ? themes[theme!].buttonText : themes[theme!].bodyText; let textColor = isPrimary ? themes[theme!].buttonText : themes[theme!].bodyText;
@ -70,8 +84,8 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
disabled && styles.disabled, disabled && styles.disabled,
style style
]} ]}
accessibilityLabel={title} {...otherProps}
{...otherProps}> {...testProps((testID || title) as string)}>
{loading ? ( {loading ? (
<ActivityIndicator color={textColor} /> <ActivityIndicator color={textColor} />
) : ( ) : (

View File

@ -7,6 +7,7 @@ import RoomTypeIcon from '../RoomTypeIcon';
import styles, { ROW_HEIGHT } from './styles'; import styles, { ROW_HEIGHT } from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
export { ROW_HEIGHT }; export { ROW_HEIGHT };
@ -49,7 +50,7 @@ const DirectoryItem = ({
}: IDirectoryItem): React.ReactElement => { }: IDirectoryItem): React.ReactElement => {
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<Touch onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }} testID={testID} theme={theme}> <Touch onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }} {...testProps(testID)} theme={theme}>
<View style={[styles.directoryItemContainer, styles.directoryItemButton, style]}> <View style={[styles.directoryItemContainer, styles.directoryItemButton, style]}>
<Avatar text={avatar} size={30} type={type} rid={rid} style={styles.directoryItemAvatar} /> <Avatar text={avatar} size={30} type={type} rid={rid} style={styles.directoryItemAvatar} />
<View style={styles.directoryItemTextContainer}> <View style={styles.directoryItemTextContainer}>

View File

@ -6,6 +6,7 @@ import styles from './styles';
import CustomEmoji from './CustomEmoji'; import CustomEmoji from './CustomEmoji';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { IEmoji, IEmojiCategory } from '../../definitions/IEmoji'; import { IEmoji, IEmojiCategory } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
const EMOJI_SIZE = 50; const EMOJI_SIZE = 50;
@ -34,7 +35,7 @@ class EmojiCategory extends React.Component<Partial<IEmojiCategory>> {
activeOpacity={0.7} activeOpacity={0.7}
key={emoji && emoji.isCustom ? emoji.content : emoji} key={emoji && emoji.isCustom ? emoji.content : emoji}
onPress={() => onEmojiSelected!(emoji)} onPress={() => onEmojiSelected!(emoji)}
testID={`reaction-picker-${emoji && emoji.isCustom ? emoji.content : emoji}`}> {...testProps(`reaction-picker-${emoji && emoji.isCustom ? emoji.content : emoji}`)}>
{renderEmoji(emoji, EMOJI_SIZE, baseUrl!)} {renderEmoji(emoji, EMOJI_SIZE, baseUrl!)}
</TouchableOpacity> </TouchableOpacity>
); );

View File

@ -3,6 +3,7 @@ import { Text, TouchableOpacity, View } from 'react-native';
import styles from './styles'; import styles from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { testProps } from '../../lib/methods/testProps';
interface ITabBarProps { interface ITabBarProps {
goToPage: Function; goToPage: Function;
@ -35,7 +36,7 @@ export default class TabBar extends React.Component<Partial<ITabBarProps>> {
key={tab} key={tab}
onPress={() => goToPage!(i)} onPress={() => goToPage!(i)}
style={styles.tab} style={styles.tab}
testID={`reaction-picker-${tab}`}> {...testProps(`reaction-picker-${tab}`)}>
<Text style={[styles.tabEmoji, tabEmojiStyle]}>{tab}</Text> <Text style={[styles.tabEmoji, tabEmojiStyle]}>{tab}</Text>
{activeTab === i ? ( {activeTab === i ? (
<View style={[styles.activeTabLine, { backgroundColor: themes[theme!].tintColor }]} /> <View style={[styles.activeTabLine, { backgroundColor: themes[theme!].tintColor }]} />

View File

@ -10,6 +10,7 @@ import StatusBar from './StatusBar';
import AppVersion from './AppVersion'; import AppVersion from './AppVersion';
import { isTablet } from '../utils/deviceInfo'; import { isTablet } from '../utils/deviceInfo';
import SafeAreaView from './SafeAreaView'; import SafeAreaView from './SafeAreaView';
import { testProps } from '../lib/methods/testProps';
interface IFormContainer extends ScrollViewProps { interface IFormContainer extends ScrollViewProps {
testID: string; testID: string;
@ -40,7 +41,7 @@ const FormContainer = ({ children, testID, ...props }: IFormContainer) => {
contentContainerStyle={[sharedStyles.containerScrollView, styles.scrollView]} contentContainerStyle={[sharedStyles.containerScrollView, styles.scrollView]}
{...scrollPersistTaps} {...scrollPersistTaps}
{...props}> {...props}>
<SafeAreaView testID={testID} style={{ backgroundColor: themes[theme].backgroundColor }}> <SafeAreaView {...testProps(testID)} style={{ backgroundColor: themes[theme].backgroundColor }}>
{children} {children}
<AppVersion theme={theme} /> <AppVersion theme={theme} />
</SafeAreaView> </SafeAreaView>

View File

@ -4,6 +4,7 @@ import { isIOS } from '../../utils/deviceInfo';
import I18n from '../../i18n'; import I18n from '../../i18n';
import Container from './HeaderButtonContainer'; import Container from './HeaderButtonContainer';
import Item from './HeaderButtonItem'; import Item from './HeaderButtonItem';
import { testProps } from '../../lib/methods/testProps';
interface IHeaderButtonCommon { interface IHeaderButtonCommon {
navigation?: any; // TODO: Evaluate proper type navigation?: any; // TODO: Evaluate proper type
@ -15,7 +16,7 @@ interface IHeaderButtonCommon {
export const Drawer = React.memo( export const Drawer = React.memo(
({ navigation, testID, onPress = () => navigation?.toggleDrawer(), ...props }: IHeaderButtonCommon) => ( ({ navigation, testID, onPress = () => navigation?.toggleDrawer(), ...props }: IHeaderButtonCommon) => (
<Container left> <Container left>
<Item iconName='hamburguer' onPress={onPress} testID={testID} {...props} /> <Item iconName='hamburguer' onPress={onPress} {...testProps(testID as string as string)} {...props} />
</Container> </Container>
) )
); );
@ -23,7 +24,7 @@ export const Drawer = React.memo(
export const CloseModal = React.memo( export const CloseModal = React.memo(
({ navigation, testID, onPress = () => navigation?.pop(), ...props }: IHeaderButtonCommon) => ( ({ navigation, testID, onPress = () => navigation?.pop(), ...props }: IHeaderButtonCommon) => (
<Container left> <Container left>
<Item iconName='close' onPress={onPress} testID={testID} {...props} /> <Item iconName='close' onPress={onPress} {...testProps(testID as string)} {...props} />
</Container> </Container>
) )
); );
@ -31,9 +32,9 @@ export const CloseModal = React.memo(
export const CancelModal = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => ( export const CancelModal = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => (
<Container left> <Container left>
{isIOS ? ( {isIOS ? (
<Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} /> <Item title={I18n.t('Cancel')} onPress={onPress} {...testProps(testID as string)} />
) : ( ) : (
<Item iconName='close' onPress={onPress} testID={testID} /> <Item iconName='close' onPress={onPress} {...testProps(testID as string)} />
)} )}
</Container> </Container>
)); ));
@ -41,24 +42,24 @@ export const CancelModal = React.memo(({ onPress, testID }: Partial<IHeaderButto
// Right // Right
export const More = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => ( export const More = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => (
<Container> <Container>
<Item iconName='kebab' onPress={onPress} testID={testID} /> <Item iconName='kebab' onPress={onPress} {...testProps(testID as string)} />
</Container> </Container>
)); ));
export const Download = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => ( export const Download = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => (
<Container> <Container>
<Item iconName='download' onPress={onPress} testID={testID} {...props} /> <Item iconName='download' onPress={onPress} {...testProps(testID as string)} {...props} />
</Container> </Container>
)); ));
export const Preferences = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => ( export const Preferences = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => (
<Container> <Container>
<Item iconName='settings' onPress={onPress} testID={testID} {...props} /> <Item iconName='settings' onPress={onPress} {...testProps(testID as string)} {...props} />
</Container> </Container>
)); ));
export const Legal = React.memo( export const Legal = React.memo(
({ navigation, testID, onPress = () => navigation?.navigate('LegalView') }: IHeaderButtonCommon) => ( ({ navigation, testID, onPress = () => navigation?.navigate('LegalView') }: IHeaderButtonCommon) => (
<More onPress={onPress} testID={testID} /> <More onPress={onPress} {...testProps(testID as string)} />
) )
); );

View File

@ -6,6 +6,7 @@ import { CustomIcon } from '../../lib/Icons';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import { testProps } from '../../lib/methods/testProps';
interface IHeaderButtonItem { interface IHeaderButtonItem {
title?: string; title?: string;
@ -42,7 +43,7 @@ const styles = StyleSheet.create({
const Item = ({ title, iconName, onPress, testID, badge }: IHeaderButtonItem): React.ReactElement => { const Item = ({ title, iconName, onPress, testID, badge }: IHeaderButtonItem): React.ReactElement => {
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<Touchable onPress={onPress} testID={testID} hitSlop={BUTTON_HIT_SLOP} style={styles.container}> <Touchable onPress={onPress} {...testProps(testID as string)} hitSlop={BUTTON_HIT_SLOP} style={styles.container}>
<> <>
{iconName ? ( {iconName ? (
<CustomIcon name={iconName} size={24} color={themes[theme].headerTintColor} /> <CustomIcon name={iconName} size={24} color={themes[theme].headerTintColor} />

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet } from 'react-native'; import { ScrollView, StyleSheet } from 'react-native';
import { testProps } from '../../lib/methods/testProps';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
@ -19,7 +20,8 @@ const ListContainer = React.memo(({ children, ...props }: IListContainer) => (
contentContainerStyle={styles.container} contentContainerStyle={styles.container}
scrollIndicatorInsets={{ right: 1 }} // https://github.com/facebook/react-native/issues/26610#issuecomment-539843444 scrollIndicatorInsets={{ right: 1 }} // https://github.com/facebook/react-native/issues/26610#issuecomment-539843444
{...scrollPersistTaps} {...scrollPersistTaps}
{...props}> {...props}
{...testProps(props.testID || '')}>
{children} {children}
</ScrollView> </ScrollView>
)); ));

View File

@ -3,6 +3,7 @@ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons'; import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { ICON_SIZE } from './constants'; import { ICON_SIZE } from './constants';
@ -25,7 +26,7 @@ const ListIcon = React.memo(({ name, color, style, testID }: IListIcon) => {
return ( return (
<View style={[styles.icon, style]}> <View style={[styles.icon, style]}>
<CustomIcon name={name} color={color ?? themes[theme].auxiliaryText} size={ICON_SIZE} testID={testID} /> <CustomIcon name={name} color={color ?? themes[theme].auxiliaryText} size={ICON_SIZE} {...testProps(testID || '')} />
</View> </View>
); );
}); });

View File

@ -10,6 +10,7 @@ import { Icon } from '.';
import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants'; import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants';
import { useDimensions } from '../../dimensions'; import { useDimensions } from '../../dimensions';
import { CustomIcon } from '../../lib/Icons'; import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -86,7 +87,9 @@ const Content = React.memo(
const { fontScale } = useDimensions(); const { fontScale } = useDimensions();
return ( return (
<View style={[styles.container, disabled && styles.disabled, { height: BASE_HEIGHT * fontScale }]} testID={testID}> <View
style={[styles.container, disabled && styles.disabled, { height: BASE_HEIGHT * fontScale }]}
{...testProps(testID || '')}>
{left ? <View style={styles.leftContainer}>{left()}</View> : null} {left ? <View style={styles.leftContainer}>{left()}</View> : null}
<View style={styles.textContainer}> <View style={styles.textContainer}>
<View style={styles.textAlertContainer}> <View style={styles.textAlertContainer}>

View File

@ -3,6 +3,7 @@ import { Animated, Modal, StyleSheet, View } from 'react-native';
import { withTheme } from '../theme'; import { withTheme } from '../theme';
import { themes } from '../lib/constants'; import { themes } from '../lib/constants';
import { testProps } from '../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -108,7 +109,7 @@ class Loading extends React.PureComponent<ILoadingProps, ILoadingState> {
return ( return (
<Modal visible={visible} transparent onRequestClose={() => {}}> <Modal visible={visible} transparent onRequestClose={() => {}}>
<View style={styles.container} testID='loading'> <View style={styles.container} {...testProps('loading')}>
<Animated.View <Animated.View
style={[ style={[
{ {

View File

@ -13,6 +13,7 @@ import sharedStyles from '../../views/Styles';
import { TFrequentlyUsedEmojiModel } from '../../definitions/IFrequentlyUsedEmoji'; import { TFrequentlyUsedEmojiModel } from '../../definitions/IFrequentlyUsedEmoji';
import { TAnyMessageModel } from '../../definitions'; import { TAnyMessageModel } from '../../definitions';
import { IEmoji } from '../../definitions/IEmoji'; import { IEmoji } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
type TItem = TFrequentlyUsedEmojiModel | string; type TItem = TFrequentlyUsedEmojiModel | string;
@ -78,7 +79,7 @@ const HeaderItem = ({ item, onReaction, server, theme }: THeaderItem) => {
const emoji = (emojiModel.id ? emojiModel.content : item) as string; const emoji = (emojiModel.id ? emojiModel.content : item) as string;
return ( return (
<Button <Button
testID={`message-actions-emoji-${emoji}`} {...testProps(`message-actions-emoji-${emoji}`)}
onPress={() => onReaction({ emoji: `:${emoji}:` })} onPress={() => onReaction({ emoji: `:${emoji}:` })}
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]} style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
theme={theme}> theme={theme}>
@ -93,7 +94,7 @@ const HeaderItem = ({ item, onReaction, server, theme }: THeaderItem) => {
const HeaderFooter = ({ onReaction, theme }: THeaderFooter) => ( const HeaderFooter = ({ onReaction, theme }: THeaderFooter) => (
<Button <Button
testID='add-reaction' {...testProps('add-reaction')}
onPress={onReaction} onPress={onReaction}
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]} style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
theme={theme}> theme={theme}>

View File

@ -4,6 +4,7 @@ import { TouchableOpacity } from 'react-native';
import { themes } from '../../../lib/constants'; import { themes } from '../../../lib/constants';
import { CustomIcon } from '../../../lib/Icons'; import { CustomIcon } from '../../../lib/Icons';
import { testProps } from '../../../lib/methods/testProps';
import { useTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import ActivityIndicator from '../../ActivityIndicator'; import ActivityIndicator from '../../ActivityIndicator';
import MessageboxContext from '../Context'; import MessageboxContext from '../Context';
@ -27,7 +28,7 @@ const Item = ({ item }: IMessageBoxCommandsPreviewItem) => {
<TouchableOpacity <TouchableOpacity
style={styles.commandPreview} style={styles.commandPreview}
onPress={() => onPressCommandPreview(item)} onPress={() => onPressCommandPreview(item)}
testID={`command-preview-item${item.id}`}> {...testProps(`command-preview-item${item.id}`)}>
{item.type === 'image' ? ( {item.type === 'image' ? (
<FastImage <FastImage
style={styles.commandPreviewImage} style={styles.commandPreviewImage}

View File

@ -7,6 +7,7 @@ import { IPreviewItem } from '../../../definitions';
import { useTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import styles from '../styles'; import styles from '../styles';
import Item from './Item'; import Item from './Item';
import { testProps } from '../../../lib/methods/testProps';
interface IMessageBoxCommandsPreview { interface IMessageBoxCommandsPreview {
commandPreview: IPreviewItem[]; commandPreview: IPreviewItem[];
@ -21,7 +22,7 @@ const CommandsPreview = React.memo(
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<FlatList <FlatList
testID='commandbox-container' {...testProps('commandbox-container')}
style={[styles.mentionList, { backgroundColor: themes[theme].messageboxBackground }]} style={[styles.mentionList, { backgroundColor: themes[theme].messageboxBackground }]}
data={commandPreview} data={commandPreview}
renderItem={({ item }) => <Item item={item} />} renderItem={({ item }) => <Item item={item} />}

View File

@ -8,6 +8,7 @@ import styles from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji'; import { IEmoji } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
interface IMessageBoxEmojiKeyboard { interface IMessageBoxEmojiKeyboard {
theme: string; theme: string;
@ -31,7 +32,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
return ( return (
<View <View
style={[styles.emojiKeyboardContainer, { borderTopColor: themes[theme].borderColor }]} style={[styles.emojiKeyboardContainer, { borderTopColor: themes[theme].borderColor }]}
testID='messagebox-keyboard-emoji'> {...testProps('messagebox-keyboard-emoji')}>
<EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} /> <EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} />
</View> </View>
); );

View File

@ -10,6 +10,7 @@ import MessageboxContext from '../Context';
import styles from '../styles'; import styles from '../styles';
import FixedMentionItem from './FixedMentionItem'; import FixedMentionItem from './FixedMentionItem';
import MentionEmoji from './MentionEmoji'; import MentionEmoji from './MentionEmoji';
import { testProps } from '../../../lib/methods/testProps';
interface IMessageBoxMentionItem { interface IMessageBoxMentionItem {
item: { item: {
@ -95,7 +96,7 @@ const MentionItem = ({ item, trackingType }: IMessageBoxMentionItem) => {
} }
]} ]}
onPress={() => onPressMention(item)} onPress={() => onPressMention(item)}
testID={testID}> {...testProps(testID)}>
<MentionItemContent item={item} trackingType={trackingType} /> <MentionItemContent item={item} trackingType={trackingType} />
</TouchableOpacity> </TouchableOpacity>
); );

View File

@ -7,6 +7,7 @@ import styles from '../styles';
import MentionItem from './MentionItem'; import MentionItem from './MentionItem';
import { themes } from '../../../lib/constants'; import { themes } from '../../../lib/constants';
import { useTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import { testProps } from '../../../lib/methods/testProps';
interface IMessageBoxMentions { interface IMessageBoxMentions {
mentions: any[]; mentions: any[];
@ -21,7 +22,7 @@ const Mentions = React.memo(
} }
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
<View testID='messagebox-container'> <View {...testProps('messagebox-container')}>
<FlatList <FlatList
style={[styles.mentionList, { backgroundColor: themes[theme].auxiliaryBackground }]} style={[styles.mentionList, { backgroundColor: themes[theme].auxiliaryBackground }]}
ListHeaderComponent={() => ( ListHeaderComponent={() => (

View File

@ -10,6 +10,7 @@ import I18n from '../../i18n';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons'; import { CustomIcon } from '../../lib/Icons';
import { events, logEvent } from '../../utils/log'; import { events, logEvent } from '../../utils/log';
import { testProps } from '../../lib/methods/testProps';
interface IMessageBoxRecordAudioProps { interface IMessageBoxRecordAudioProps {
theme: string; theme: string;
@ -197,9 +198,8 @@ export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAu
<BorderlessButton <BorderlessButton
onPress={this.startRecordingAudio} onPress={this.startRecordingAudio}
style={styles.actionButton} style={styles.actionButton}
testID='messagebox-send-audio' {...testProps('messagebox-send-audio')}
// @ts-ignore // @ts-ignore
accessibilityLabel={I18n.t('Send_audio_message')}
accessibilityTraits='button'> accessibilityTraits='button'>
<CustomIcon name='microphone' size={24} color={themes[theme].auxiliaryTintColor} /> <CustomIcon name='microphone' size={24} color={themes[theme].auxiliaryTintColor} />
</BorderlessButton> </BorderlessButton>

View File

@ -2,10 +2,10 @@ import { BorderlessButton } from 'react-native-gesture-handler';
import React from 'react'; import React from 'react';
import styles from '../styles'; import styles from '../styles';
import i18n from '../../../i18n';
import { CustomIcon } from '../../../lib/Icons'; import { CustomIcon } from '../../../lib/Icons';
import { useTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import { themes } from '../../../lib/constants'; import { themes } from '../../../lib/constants';
import { testProps } from '../../../lib/methods/testProps';
interface IBaseButton { interface IBaseButton {
onPress(): void; onPress(): void;
@ -22,8 +22,8 @@ const BaseButton = ({ accessibilityLabel, icon, color, ...props }: Partial<IBase
{...props} {...props}
style={styles.actionButton} style={styles.actionButton}
// @ts-ignore // @ts-ignore
accessibilityLabel={i18n.t(accessibilityLabel)} accessibilityTraits='button'
accessibilityTraits='button'> {...testProps(props.testID)}>
<CustomIcon name={icon} size={24} color={color || themes[theme].auxiliaryTintColor} /> <CustomIcon name={icon} size={24} color={color || themes[theme].auxiliaryTintColor} />
</BorderlessButton> </BorderlessButton>
); );

View File

@ -52,6 +52,7 @@ import { IMessage } from '../../definitions/IMessage';
import { forceJpgExtension } from './forceJpgExtension'; import { forceJpgExtension } from './forceJpgExtension';
import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions'; import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types'; import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
import { testProps } from '../../lib/methods/testProps';
if (isAndroid) { if (isAndroid) {
require('./EmojiKeyboard'); require('./EmojiKeyboard');
@ -1002,7 +1003,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
<TouchableWithoutFeedback <TouchableWithoutFeedback
style={[styles.sendToChannelButton, { backgroundColor: themes[theme].messageboxBackground }]} style={[styles.sendToChannelButton, { backgroundColor: themes[theme].messageboxBackground }]}
onPress={this.onPressSendToChannel} onPress={this.onPressSendToChannel}
testID='messagebox-send-to-channel'> {...testProps('messagebox-send-to-channel')}>
<CustomIcon name={tshow ? 'checkbox-checked' : 'checkbox-unchecked'} size={24} color={themes[theme].auxiliaryText} /> <CustomIcon name={tshow ? 'checkbox-checked' : 'checkbox-unchecked'} size={24} color={themes[theme].auxiliaryText} />
<Text style={[styles.sendToChannelText, { color: themes[theme].auxiliaryText }]}> <Text style={[styles.sendToChannelText, { color: themes[theme].auxiliaryText }]}>
{I18n.t('Messagebox_Send_to_channel')} {I18n.t('Messagebox_Send_to_channel')}
@ -1123,7 +1124,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
{ backgroundColor: themes[theme].messageboxBackground }, { backgroundColor: themes[theme].messageboxBackground },
!recording && editing && { backgroundColor: themes[theme].chatComponentBackground } !recording && editing && { backgroundColor: themes[theme].chatComponentBackground }
]} ]}
testID='messagebox'> {...testProps('messagebox')}>
{textInputAndButtons} {textInputAndButtons}
{recordAudio} {recordAudio}
</View> </View>

View File

@ -8,6 +8,7 @@ import { themes } from '../lib/constants';
import TextInput from '../presentation/TextInput'; import TextInput from '../presentation/TextInput';
import { isIOS, isTablet } from '../utils/deviceInfo'; import { isIOS, isTablet } from '../utils/deviceInfo';
import { useOrientation } from '../dimensions'; import { useOrientation } from '../dimensions';
import { testProps } from '../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -40,7 +41,7 @@ const SearchHeader = ({ onSearchChangeText, testID }: ISearchHeaderProps): JSX.E
placeholder={I18n.t('Search')} placeholder={I18n.t('Search')}
onChangeText={onSearchChangeText} onChangeText={onSearchChangeText}
theme={theme} theme={theme}
testID={testID} {...testProps(testID || '')}
/> />
</View> </View>
); );

View File

@ -7,6 +7,7 @@ import TextInput from '../presentation/TextInput';
import { themes } from '../lib/constants'; import { themes } from '../lib/constants';
import { CustomIcon } from '../lib/Icons'; import { CustomIcon } from '../lib/Icons';
import ActivityIndicator from './ActivityIndicator'; import ActivityIndicator from './ActivityIndicator';
import { testProps } from '../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
error: { error: {
@ -84,7 +85,7 @@ export default class RCTextInput extends React.PureComponent<IRCTextInputProps,
return ( return (
<CustomIcon <CustomIcon
name={iconLeft} name={iconLeft}
testID={testID ? `${testID}-icon-left` : null} {...testProps(testID ? `${testID}-icon-left` : '')}
style={[styles.iconContainer, styles.iconLeft, { color: themes[theme].bodyText }]} style={[styles.iconContainer, styles.iconLeft, { color: themes[theme].bodyText }]}
size={20} size={20}
/> />
@ -107,7 +108,7 @@ export default class RCTextInput extends React.PureComponent<IRCTextInputProps,
<Touchable onPress={this.tooglePassword} style={[styles.iconContainer, styles.iconRight]}> <Touchable onPress={this.tooglePassword} style={[styles.iconContainer, styles.iconRight]}>
<CustomIcon <CustomIcon
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'} name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
testID={testID ? `${testID}-icon-right` : null} {...testProps(testID ? `${testID}-icon-right` : '')}
style={{ color: themes[theme].auxiliaryText }} style={{ color: themes[theme].auxiliaryText }}
size={20} size={20}
/> />
@ -170,7 +171,7 @@ export default class RCTextInput extends React.PureComponent<IRCTextInputProps,
autoCapitalize='none' autoCapitalize='none'
underlineColorAndroid='transparent' underlineColorAndroid='transparent'
secureTextEntry={secureTextEntry && !showPassword} secureTextEntry={secureTextEntry && !showPassword}
testID={testID} {...testProps(testID || '')}
accessibilityLabel={placeholder} accessibilityLabel={placeholder}
placeholder={placeholder} placeholder={placeholder}
theme={theme} theme={theme}

View File

@ -8,6 +8,7 @@ import { formatText } from './formatText';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import styles from './styles'; import styles from './styles';
import { formatHyperlink } from './formatHyperlink'; import { formatHyperlink } from './formatHyperlink';
import { testProps } from '../../lib/methods/testProps';
interface IMarkdownPreview { interface IMarkdownPreview {
msg?: string; msg?: string;
@ -35,7 +36,7 @@ const MarkdownPreview = ({ msg, numberOfLines = 1, testID, style = [] }: IMarkdo
accessibilityLabel={m} accessibilityLabel={m}
style={[styles.text, { color: themes[theme].bodyText }, ...style]} style={[styles.text, { color: themes[theme].bodyText }, ...style]}
numberOfLines={numberOfLines} numberOfLines={numberOfLines}
testID={testID}> {...testProps(testID)}>
{m} {m}
</Text> </Text>
); );

View File

@ -10,6 +10,7 @@ import { themes } from '../../lib/constants';
import MessageContext from './Context'; import MessageContext from './Context';
import { IMessageBroadcast } from './interfaces'; import { IMessageBroadcast } from './interfaces';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
const Broadcast = React.memo(({ author, broadcast }: IMessageBroadcast) => { const Broadcast = React.memo(({ author, broadcast }: IMessageBroadcast) => {
const { user, replyBroadcast } = useContext(MessageContext); const { user, replyBroadcast } = useContext(MessageContext);
@ -24,7 +25,7 @@ const Broadcast = React.memo(({ author, broadcast }: IMessageBroadcast) => {
background={Touchable.Ripple(themes[theme].bannerBackground)} background={Touchable.Ripple(themes[theme].bannerBackground)}
style={[styles.button, { backgroundColor: themes[theme].tintColor }]} style={[styles.button, { backgroundColor: themes[theme].tintColor }]}
hitSlop={BUTTON_HIT_SLOP} hitSlop={BUTTON_HIT_SLOP}
testID='message-broadcast-reply'> {...testProps('message-broadcast-reply')}>
<> <>
<CustomIcon name='arrow-back' size={20} style={styles.buttonIcon} color={themes[theme].buttonText} /> <CustomIcon name='arrow-back' size={20} style={styles.buttonIcon} color={themes[theme].buttonText} />
<Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Reply')}</Text> <Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Reply')}</Text>

View File

@ -13,6 +13,7 @@ import Markdown from '../../../markdown';
import MessageContext from '../../Context'; import MessageContext from '../../Context';
import Touchable from '../../Touchable'; import Touchable from '../../Touchable';
import { BUTTON_HIT_SLOP } from '../../utils'; import { BUTTON_HIT_SLOP } from '../../utils';
import { testProps } from '../../../../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
button: { button: {
@ -90,7 +91,9 @@ const Fields = React.memo(
<> <>
{attachment.fields.map(field => ( {attachment.fields.map(field => (
<View key={field.title} style={[styles.fieldContainer, { width: field.short ? '50%' : '100%' }]}> <View key={field.title} style={[styles.fieldContainer, { width: field.short ? '50%' : '100%' }]}>
<Text testID='collapsibleQuoteTouchableFieldTitle' style={[styles.fieldTitle, { color: themes[theme].bodyText }]}> <Text
{...testProps('collapsibleQuoteTouchableFieldTitle')}
style={[styles.fieldTitle, { color: themes[theme].bodyText }]}>
{field.title} {field.title}
</Text> </Text>
<Markdown <Markdown
@ -144,7 +147,7 @@ const CollapsibleQuote = React.memo(
return ( return (
<> <>
<Touchable <Touchable
testID={`collapsibleQuoteTouchable-${attachment.title}`} {...testProps(`collapsibleQuoteTouchable-${attachment.title}`)}
onPress={onPress} onPress={onPress}
style={[ style={[
styles.button, styles.button,

View File

@ -10,6 +10,7 @@ import { themes } from '../../lib/constants';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import MessageContext from './Context'; import MessageContext from './Context';
import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
interface IReaction { interface IReaction {
_id: string; _id: string;
@ -34,7 +35,7 @@ const AddReaction = React.memo(({ theme }: { theme: string }) => {
<Touchable <Touchable
onPress={reactionInit} onPress={reactionInit}
key='message-add-reaction' key='message-add-reaction'
testID='message-add-reaction' {...testProps('message-add-reaction')}
style={[styles.reactionButton, { backgroundColor: themes[theme].backgroundColor }]} style={[styles.reactionButton, { backgroundColor: themes[theme].backgroundColor }]}
background={Touchable.Ripple(themes[theme].bannerBackground)} background={Touchable.Ripple(themes[theme].bannerBackground)}
hitSlop={BUTTON_HIT_SLOP}> hitSlop={BUTTON_HIT_SLOP}>
@ -53,7 +54,7 @@ const Reaction = React.memo(({ reaction, getCustomEmoji, theme }: IMessageReacti
onPress={() => onReactionPress(reaction.emoji)} onPress={() => onReactionPress(reaction.emoji)}
onLongPress={onReactionLongPress} onLongPress={onReactionLongPress}
key={reaction.emoji} key={reaction.emoji}
testID={`message-reaction-${reaction.emoji}`} {...testProps(`message-reaction-${reaction.emoji}`)}
style={[ style={[
styles.reactionButton, styles.reactionButton,
{ backgroundColor: reacted ? themes[theme].bannerBackground : themes[theme].backgroundColor } { backgroundColor: reacted ? themes[theme].bannerBackground : themes[theme].backgroundColor }

View File

@ -8,6 +8,7 @@ import I18n from '../../i18n';
import { MarkdownPreview } from '../markdown'; import { MarkdownPreview } from '../markdown';
import { IMessageRepliedThread } from './interfaces'; import { IMessageRepliedThread } from './interfaces';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
const RepliedThread = memo(({ tmid, tmsg, isHeader, fetchThreadName, id, isEncrypted }: IMessageRepliedThread) => { const RepliedThread = memo(({ tmid, tmsg, isHeader, fetchThreadName, id, isEncrypted }: IMessageRepliedThread) => {
const { theme } = useTheme(); const { theme } = useTheme();
@ -33,7 +34,7 @@ const RepliedThread = memo(({ tmid, tmsg, isHeader, fetchThreadName, id, isEncry
} }
return ( return (
<View style={styles.repliedThread} testID={`message-thread-replied-on-${msg}`}> <View style={styles.repliedThread} {...testProps(`message-thread-replied-on-${msg}`)}>
<CustomIcon name='threads' size={20} style={styles.repliedThreadIcon} color={themes[theme].tintColor} /> <CustomIcon name='threads' size={20} style={styles.repliedThreadIcon} color={themes[theme].tintColor} />
<MarkdownPreview msg={msg} style={[styles.repliedThreadName, { color: themes[theme].tintColor }]} /> <MarkdownPreview msg={msg} style={[styles.repliedThreadName, { color: themes[theme].tintColor }]} />
<View style={styles.repliedThreadDisclosure}> <View style={styles.repliedThreadDisclosure}>

View File

@ -8,6 +8,7 @@ import ThreadDetails from '../ThreadDetails';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { IMessageThread } from './interfaces'; import { IMessageThread } from './interfaces';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { testProps } from '../../lib/methods/testProps';
const Thread = React.memo( const Thread = React.memo(
({ msg, tcount, tlm, isThreadRoom, id }: IMessageThread) => { ({ msg, tcount, tlm, isThreadRoom, id }: IMessageThread) => {
@ -20,7 +21,9 @@ const Thread = React.memo(
const { threadBadgeColor, toggleFollowThread, user, replies } = useContext(MessageContext); const { threadBadgeColor, toggleFollowThread, user, replies } = useContext(MessageContext);
return ( return (
<View style={styles.buttonContainer}> <View style={styles.buttonContainer}>
<View style={[styles.button, { backgroundColor: themes[theme].tintColor }]} testID={`message-thread-button-${msg}`}> <View
style={[styles.button, { backgroundColor: themes[theme].tintColor }]}
{...testProps(`message-thread-button-${msg}`)}>
<Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Reply')}</Text> <Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Reply')}</Text>
</View> </View>
<ThreadDetails <ThreadDetails

View File

@ -0,0 +1,4 @@
export const testProps = (testID?: string): { testID?: string; accessibilityLabel?: string } => ({
testID,
accessibilityLabel: testID
});

View File

@ -1,4 +0,0 @@
export const withTest = (testID: string): { testID: string; accessibilityLabel: string } => ({
testID,
accessibilityLabel: testID
});

View File

@ -3,6 +3,7 @@ import { I18nManager, StyleProp, StyleSheet, TextInput, TextStyle } from 'react-
import { IRCTextInputProps } from '../containers/TextInput'; import { IRCTextInputProps } from '../containers/TextInput';
import { themes } from '../lib/constants'; import { themes } from '../lib/constants';
import { testProps } from '../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
input: { input: {
@ -22,6 +23,7 @@ const ThemedTextInput = React.forwardRef<TextInput, IThemedTextInput>(({ style,
placeholderTextColor={themes[theme].auxiliaryText} placeholderTextColor={themes[theme].auxiliaryText}
keyboardAppearance={theme === 'light' ? 'light' : 'dark'} keyboardAppearance={theme === 'light' ? 'light' : 'dark'}
{...props} {...props}
{...testProps(props.testID)}
/> />
)); ));

View File

@ -7,7 +7,7 @@ import { themes } from '../../../lib/constants';
import I18n from '../../../i18n'; import I18n from '../../../i18n';
import { TServerHistoryModel } from '../../../definitions/IServerHistory'; import { TServerHistoryModel } from '../../../definitions/IServerHistory';
import Item from './Item'; import Item from './Item';
import { withTest } from '../../../lib/methods/withTest'; import { testProps } from '../../../lib/methods/testProps';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -64,7 +64,7 @@ const ServerInput = ({
theme={theme} theme={theme}
onFocus={() => setFocused(true)} onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)} onBlur={() => setFocused(false)}
{...withTest('new-server-view-input')} {...testProps('new-server-view-input')}
/> />
{focused && serversHistory?.length ? ( {focused && serversHistory?.length ? (
<View <View

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
deviceName: 'iPhone 11 Pro', deviceName: 'iPhone 11 Pro', // pass the udid or device name
platformVersion: '14.5', platformVersion: '14.5', // pass the platform version
app: 'chat.rocket.reactnative' app: 'chat.rocket.reactnative'
}; };

View File

@ -36,7 +36,7 @@ exports.config = {
// and 30 processes will get spawned. The property handles how many capabilities // and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests. // from the same test should run tests.
// //
// maxInstances: 10, maxInstances: 1,
// //
// If you have trouble getting all important capabilities together, check out the // If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities: // Sauce Labs platform configurator - a great tool to configure your capabilities: