How to test image source in react native - react-native

my test result is number 1 instead of the name of the icon. Do you know how can I test the image source?
Code:
<Image
source={buttonVisibility ? arrowRight : arrowDown}
style={{ width: 20, height: 20 }}
testID="image-source"
/>
My test:
it('icon should be arrowRight', () => {
const wrapper = shallow(<DetailsPageLastPosition bike={bike} buttonVisibility={true} />);
expect(wrapper.find({ testID: 'image-source' }).props().source).toEqual('arrowRight');
});
Test result:
● DetailsPageLastPosition component › icon should be arrowRight
expect(received).toEqual(expected) // deep equality
Expected: "arrowRight"
Received: 1
73 | it('icon should be arrowRight', () => {
74 | const wrapper = shallow(<DetailsPageLastPosition bike={bike} buttonVisibility={true} />);
> 75 | expect(wrapper.find({ testID: 'image-source' }).props().source).toEqual('arrowRight');
| ^
76 | });
77 | });
78 |

Local image assets always resolve to a number (see here in the docs). One easy way around this would be to dynamically assign a test ID based on your conditional.
<Image
source={buttonVisibility ? arrowRight : arrowDown}
style={{ width: 20, height: 20 }}
testID={`image-source-${buttonVisibilty ? 'arrowRight' : 'arrowDown'}`}
/>
// in test
expect(wrapper.find({ testID: 'image-source-arrowRight' }) // etc

Related

React Native Modalize - cannot scroll FlatList inside Modalize

I'm using react-native-modalize with flatListProps but I can't scroll the flatList, I tried panGestureEnabled={false}, or remove the height style but none of them fix it, here is my code:
<Modalize
ref={ref}
children={children}
adjustToContentHeight={true}
onOverlayPress={closeModal}
onClosed={onCloseCallback}
HeaderComponent={renderHeader}
flatListProps={
listData?.length > 0
? {
data: listData,
renderItem: renderListItem,
ItemSeparatorComponent: renderSeparator,
keyExtractor: listKeyExtractor,
contentContainerStyle: dStyles.dataList,
}
: undefined
}
modalStyle={styles.borderRadius}
/>
const dStyles = StyleSheet.create({
dataList: {
height: 400,
},
});
I check the listData and the array has 63 items but the flatList only render the first 9 items.
Fixed by adding to flatListProps these props:
initialNumToRender: 10
maxToRenderPerBatch:10
And add to <Modalize prop disableScrollIfPossible={false}
I'm not sure why but the height is also need to be removed. So this is new code:
<Modalize
ref={ref}
children={children}
adjustToContentHeight={true}
disableScrollIfPossible={false}
onOverlayPress={closeModal}
onClosed={onCloseCallback}
HeaderComponent={renderHeader}
flatListProps={
listData?.length > 0
? {
data: listData,
renderItem: renderListItem,
ItemSeparatorComponent: renderSeparator,
keyExtractor: listKeyExtractor,
initialNumToRender: 10,
maxToRenderPerBatch: 10,
}
: undefined
}
modalStyle={styles.borderRadius}
/>
As I mentioned, I cannot limit the FlatList height, so if the list is long enough, <Modalize will be expanded full screen, that is the limitation of this solution.

Can't customise user menu in react-admin

I'm trying to customise the user menu in react-admin and I've followed the instructions and the example inside the react-admin repo but I'm still getting this error:
Type '{ ref: ForwardedRef<any>; to: string; primaryText: string; leftIcon: Element; onClick: any; sidebarIsOpen: true; }' is missing the following properties from type 'Pick<any, "selected" | "dense" | "className" | "style" | "classes" | "innerRef" | "button" | "slot" | "title" | "key" | "value" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | ... 277 more ... | "ContainerProps">': selected, dense, className, style, and 283 more. TS2740
Here's my code.
import SettingsIcon from '#material-ui/icons/Settings';
import { forwardRef } from 'react';
const ConfigurationMenu = forwardRef<any, any>((props, ref) => (
<MenuItemLink
ref={ref}
to="/metamaskLogin"
primaryText="MetaMask"
leftIcon={<SettingsIcon />}
// onClick={onClick} // close the menu on click
// dense={true}
onClick={props.onClick}
sidebarIsOpen
/>
));
const MyUserMenu = (props: any) => (
<UserMenu {...props}>
<ConfigurationMenu />
</UserMenu>
);
export const MyAppBar = (props: any) => <AppBar {...props} userMenu={<MyUserMenu />} />;
I've tested I can hide the user menu by setting userMenu={false}
the example code can be found here: https://github.com/marmelab/react-admin/blob/master/examples/demo/src/layout/AppBar.tsx
figured it out, just needed to add {...props} to MenuItemLink

React Native conditionally setting state

I have an array of "favorite" listings per user. I want to set a state variable depending on if it is rendering a favorite item or a regular (non-favorite) item. This is a little heart icon that is either filled or unfilled. It is incorrectly setting the state on first render. Correctly sets it after refresh.. I'm doing something wrong and have tried many things to no avail so if someone could just look at this code and tell me if you see any glaring flaws. If not then I will look elsewhere for the problem.
Behavior when app loads: I am doing console.log just after the state is set to show whether it's a favorite or not, and the contents of the favorite state variable (an image url, but in the console it shows it as either 21 for non-fav, or 22 for a fav). I can see that it is correctly pulling the array of favorites, and correctly identifying those that are and are not favorited (1 means its a favorite). It is however not setting the state variable correctly. Furthermore, it IS setting it correctly for only some of the listings. Currently I have all listings marked as a favorite, and it only messes up the first 10. After that they all set right. MORE bizarre, is upon refreshing the screen, it correctly sets all of them.
MainHeader.js (pulling data from db, setting initial array of favorite listings, and passing it to the messagesScreen component)
const [favsArray, setFavsArray] = useState("");
useEffect(() => {
lookupUser()
.then((snapshot) => {
if (snapshot.hasChildren()) {
snapshot.forEach(function(childSnapshot) {
let favs = childSnapshot.child("favorites").val();
setFavsArray(favs);
})
}
})
.catch((error) => {console.error('Error:', error)});
}, []);
return (
<NavigationContainer>
<View style={styles.headerContainer}>
<Image
style={styles.image}
source={require("../assets/newheader4.png")}
/>
</View>
<Tab.Navigator
tabBarOptions={{
activeTintColor: "blue",
inactiveTintColor: "black",
style: {},
tabStyle: {
width: "auto",
backgroundColor: "#e0d5f3",
borderTopWidth: 3,
borderBottomWidth: 3,
borderRightColor: "gray",
},
labelStyle: {
fontSize: 14,
fontWeight: "bold",
},
scrollEnabled: true,
}}
>
<Tab.Screen name="All Deals" children={()=><MessagesScreen favsArray={favsArray} setFavsArray={setFavsArray}/>} />
</Tab.Navigator>
</NavigationContainer>
MessagesScreen, receives favsArray and renders a FlatList with component Card which it feeds favsArray to.
<FlatList
data={messagesShow}
keyExtractor={(messagesShow) => messagesShow.id.toString()}
renderItem={({ item }) => (
<Card
price={item.currentPrice}
title={item.title}
image={item.image}
posted={item.postedDate}
discAmount={item.discountAmount}
discType={item.discType}
expiration={item.expiration}
promoCode={item.promoCode}
affLink={item.amzLink}
indexStore={item.indexStore}
store={item.store}
favsArray = {favsArray}
/>
)}
ItemSeparatorComponent={ListItemSeparator}
contentContainerStyle={styles.messagesList}
refreshing={refreshing}
onRefresh={() =>
db.ref('deals').once('value', (snapshot) =>{
let testData = [];
snapshot.forEach((child)=>{
// if (child.val().hasOwnProperty('title')){
testData.push({
id: child.key,
title: child.val().hasOwnProperty('title') ? child.val().title : 'NA',
currentPrice: child.val().price,
discountAmount: child.val().discAmt,
discType: child.val().discType,
promoCode: child.val().promoCode,
expiration: child.val().expDate,
postedDate: child.val().postDate,
image: { uri: child.val().imageLink},
amzLink: child.val().affLink,
category: child.val().category,
indexStore: child.val().indexStore,
store: child.val().store
})
// }
checkMessages(testData);
})
})
.then()
.catch((error) => {console.error('Error:', error)})
}
/>
Card component, this is in a FlatList where favsArray is passed as a prop (correctly verified by console), along with the individual listing data. If it finds the listing in the fav array, it should set to HeartFilled (1), if not set to HeartEmpty (0).
let test = [];
test = favsArray.split(',');
let isFav = 0;
let found = test.find(function (element) {
return element == indexStore;
});
if (found != undefined){
isFav = 1;
}
const [heartFilled, setHeartFilled] = useState( isFav == 1 ? require('../assets/heartFilled.png') : require('../assets/heartEmpty.png'));
console.log(isFav + ' ' + heartFilled);
Looking at my console, you can see it correctly shows each listing as a favorite, but for the first 10 listings it sets the state to the wrong image (21, shown in red). These should all be 22.

react-native multi select change select text color

I am new to react-native and i am trying to add multi selection component to my app
my code is as follows:
<SectionedMultiSelect
items={this.state.days}
uniqueKey="id"
hideSearch={true}
subKey="day"
selectText="Select Days"
selectToggle={{ color: '#f79334' }}
showDropDowns={true}
readOnlyHeadings={true}
onSelectedItemsChange={this.onSelectedItemsChangeHomeRepair}
selectedItems={this.state.selectedDaysHomeRepair}
showChips={false}
theme = {
{
Colors:{
selectToggleTextColor:'#053075',
text:'#053075'
}
}
}
/>
does anyone know how to apply color to "Select Days" text. thanks
You could use the renderSelectText prop and pass your own text component with your custom styles.
<SectionedMultiSelect
items={this.state.days}
uniqueKey="id"
hideSearch={true}
subKey="day"
renderSelectText={() => <Text style={{ color: 'red', fontSize: 24 }}>Select Days</Text>}
selectToggle={{ color: '#f79334' }}
showDropDowns={true}
readOnlyHeadings={true}
onSelectedItemsChange={this.onSelectedItemsChangeHomeRepair}
selectedItems={this.state.selectedDaysHomeRepair}
showChips={false}
theme = {
{
Colors: {
selectToggleTextColor:'#053075',
text:'#053075'
}
}
}
/>
Have a look at how this can be used in the example here.

How do I pass along SectionList's scrollToLocation to child components?

I'm building a React Native app that has a process guide the user needs to fill out. When the user has selected an option, then I want to scroll him down the screen to where the new options appears.
To achieve that I need SectionList's scrollToLocation function available in my button's onClick.
42 const sectionData = [
43 {
44 data: [
45 {
46 key: "1",
47 program: [
48 <Question
49 key={1}
50 onAnswerSubmit={() => {
51 scrollToLocation(1);
/*
How do I access scrollToLocation from
SectionList and pass it along as a prop here?
*/
52 }}
53 />,
54 <Question
55 key={2}
56 onAnswerSubmit={() => {
57 scrollToLocation(1);
58 }}
130 public render() {
131
132 return (
133 <SectionList
135 sections={ sectionData }
136 renderItem={ renderItem }
137 renderSectionHeader={ sectionHeader }
138 keyExtractor={ keyExtractor }
139 >
140 </SectionList>
Question.tsx
28 public render() {
29 return (
30 <Question
31 {...this.props}
32 onPress={this.props.onAnswerSubmit}
33 />
34 );
You can add ref to SectionList like this
ref = "foo"
and call it
this.refs.foo.scrollToLocation(params);
or
ref = {ref => this.sectionListRef = ref}
and call it
this.sectionListRef.scrollToLocation(params);