We are using detox to write E2E testing of a react native app where we have a case which needs to test if a modal appears after a button tap.
But detox was not able to identify modal with the given testID thought the modal opens as expected. Is there a different way test modal in reactnative using detox?
Below is the modal JSX
<Modal
testID="loadingModal"
animationType="none"
transparent
visible={loading}
onRequestClose={() => {}}
>
<View style={styles.modalContainer}>
<View style={styles.loginModal}>
<ActivityIndicator
animating
size="large"
color="#00e0ff"
/>
<Text style={styles.login}>Logging in...</Text>
</View>
</View>
</Modal>
And below is the code to test the visibility of modal
it('should have welcome screen', async () => {
....
await element(by.text('CONTINUE')).tap();
await waitFor(element(by.id('loadingModal'))).toBeVisible().withTimeout(5000);
await expect(element(by.id('loadingModal'))).toBeVisible(); // this always fails
});
React Native's Modal component creates a view controller which manages the rendering of child views on the native level. Unfortunately, it doesn't pass down testID, so the best way I've found is to wrap the contents of the modal in a <View>, and pass the testID prop to that component. In your case, you could do:
<Modal
animationType="none"
transparent
visible={loading}
onRequestClose={() => {}}
>
<View
style={styles.modalContainer}
testID="loadingModal" // Just move the testID to this element
>
<View style={styles.loginModal}>
<ActivityIndicator
animating
size="large"
color="#00e0ff"
/>
<Text style={styles.login}>Logging in...</Text>
</View>
</View>
Related
I did a custom select but I have the problem to close it if I press outside the select or options. basically the "button" is a TouchableOpacity and when I click on it there appears the list of options. But now I can close it only by choosing one option or clicking back on the select button. Is there a way to check whether I click outside the TouchableOpacity or not? In simple react you can give an Id to the component and check it onClick event to see what you have clicked. Or you can use react's useRef hook which doesn't seem to work with react-native. I have this code (simplified):
const [isOpen, setIsOpen] = useState(false)
const toggle = () => { setIsOpen(!isOpen)}
//...
return (<View>
<TouchableOpacity onPress={toggle}>
<Text>Open select</Text>
</TouchableOpacity>
<View>
{isOpen && options.map(({value, label}) => <View key={value} onPress={toggle}>{label}</View>)}
</View>
</View>)
As you can see you can call toggle only if you press the select button or an option. I want to call setIsOpen(false) when I click outside the TouchableOpacity box.
Is there a way or library to do it?
First of all correct usage for toggle function is
setIsOpen(prevIsOpen => !prevIsOpen);
And regarding your question. Just wrap all screen into touchable component without any feedback.
const close = () => isOpen && setIsOpen(false);
return (
<TouchableWithoutFeedback onPress={close} style={{ flex: 1 }}>
<View>
<TouchableOpacity onPress={toggle}>
<Text>Open select</Text>
</TouchableOpacity>
<View>
{isOpen && options.map(({value, label}) => <View key={value} onPress={toggle}>{label}</View>)}
</View>
</View>
</TouchableWithoutFeedback>
);
you can use TouchableWithoutFeedback
i am trying to change flash mode on expo camera but it's not working and i can't find any documentation for that, here is some code snippets:
-the hook i am using for the flash mode:
const [flash, setFlash] = useState(Camera.Constants.FlashMode.off);
-and here is the function i am using:
<TouchableWithoutFeedback style={styles.flash}
onPress={() => {
setFlash(
flash === Camera.Constants.FlashMode.off
? Camera.Constants.FlashMode.torch
: Camera.Constants.FlashMode.off);
}}>
<MaterialCommunityIcons
style={styles.flash}
name="flash"
color={"#9c1937"}
size={50}
/>
</TouchableWithoutFeedback>
i cant change the flash mode using this (def: off), however changing front and back cameras is achieved using exactly the same way so please help, (i am using functional components).
Add the following to your camera component.
<Camera
flashMode={flash}
/>
Here's a basic code for toggling flash on expo-camera.
<Camera
type={this.state.type}
style={{flex: 1,}}
ref={(ref) => { this.camera = ref }}
flashMode={this.state.flashMode? Camera.Constants.FlashMode.torch : Camera.Constants.FlashMode.off}
>
<View>
<TouchableOpacity onPress={() => this.setState({flashMode: !this.state.flashMode})}>
<FontAwesome
name="flash"
size={40}
color={"#fff"}
/>
</TouchableOpacity>
</View>
</Camera>
How can I set focus to the first (or any given) TouchableHighlight component inside the modal when it's opened?
I'm using D-pad/kayboard/TV Remote
Let's use the fragment of the react-native documentation modal example:
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<TouchableHighlight>
<Text>Button 1</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text>Button 2</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
Navigation with D-pad works, but when the modal is opened, the first TouchableHighlight (button 1) is not focused, focus remains on the "Show Modal" button
Or, How can I set focus on the "Button 2" TouchableHighlight programatically?
TextInput for example has autoFocus, but TouchableHighlight no, if we are using only Touchable components inside a modal, I don;t know how to autoFocus them, or set implicitely it
Best Regards
Add hasTVPreferredFocus: true to the TouchableHighlight you want focused.
It is implemented on Android even though the documentation states that hasTVPreferredFocus is iOS-only.
Programmatically you can also force the focus by calling:
yourElementRef.setNativeProps({ hasTVPreferredFocus: true })
#mtkopone . is there any way to focus View component, i have a list which is inside View and i want to do some function calls when user focus on that View (onFocus,onBlur)
initialRef.current.setNativeProps({hasTVPreferredFocus: true});
I have FlatList and I want to open each FlatList Item in Modal to see details. In this example I am trying to click on {rowData.data.display_name} to see {rowData.data.display_name} inside of Modal. I get data from API and when I open Modal it's not the same item that I clicked on. I am not sure how would I set up item id to see the same item inside of Modal? Any help would be appreciated!
Here is my code:
<FlatList
data={this.state._data}
renderItem={({item: rowData}) => {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this.openModal}>
<Text style={styles.title}>
{rowData.data.display_name}
</Text>
</TouchableOpacity>
<Modal
style={styles.modal}
ref={(modal) => this.modal = modal}
coverScreen={true}
swipeToClose={this.state.swipeToClose}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>
{rowData.data.display_name}
</Text>
</Modal>
</View>
);
}}
keyExtractor={(item, index) => index}
/>
In my opinion you should put the Modal outside the FlatList. The way you codded it you're overwritting the "this.modal" every time a new Item from the list is created.
Then you would just accept changing the text of the Modal (probably via state) on your openModal function inside the Modal component, and on your renderItem, change the onPress to pass the infos from the container you want the modal to show.
onPress={()=> this.openModal(rowData.data)}>
In my scenario there are two Views.
While load the component i need to none second view after while click
on TextInput need to open the second view after selecting the value
from the second view selected value should be populate in the first
view TextInput after that secondView should be closed.I can acheieve
the same effect using react.js but the same effect i am unable to do
using react native .
var ViewDisplay = React.createClass({
componentDidMount(){
this.refs.secondView.getDOMNode().style.display="none";
},
clickHandler:function(){
this.refs.secondView.getDOMNode().style.display="block";
},
populateValue:function(){
this.refs.secondView.getDOMNode().style.display="none";
},
render:function(){
return(<View>
<View ref={firstView}>
<TextInput style={styles.textInput} placeholder= {enter value} onEndEditing={this.clickHandler}/>
</View>
<View ref={secondView}>
<TouchableHighlight underlayColor="#ffa456" onPress={this.populateValue}>
<Text ref={key}>first</Text>
</TouchableHighlight>
<TouchableHighlight underlayColor="#ffa456" onPress={this.populatevalue}>
<Text>Second</Text>
</TouchableHighlight>
<TouchableHighlight underlayColor="#ffa456" onPress={this.populatevalue}>
<Text>third</Text>
</TouchableHighlight>
</View>
</View>)
}
})
Try setting a flag in your component state with the click handler, then use that to determine which view should be rendered
render() !this.state.clicked ? <View ref={firstView}> ... </View> : <View ref={secondView}> ... </View>