-
-
Notifications
You must be signed in to change notification settings - Fork 922
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Version
v5
Reanimated Version
v3
Gesture Handler Version
v2
Platforms
Web
What happened?
I am trying to write a unit test with Jest for component that has @legendapp/list + @gorhom/bottom-sheet.
I am mocking it like so: jest.mock('@gorhom/bottom-sheet', () => require('@gorhom/bottom-sheet/mock'));
I get an error TypeError: (0 , _bottomSheet.useBottomSheetScrollableCreator) is not a function when running the unit test.
Reproduction steps
Use useBottomSheetScrollableCreator in the source code of a component, like so:
LSelect.tsx
import {
ReactElement,
ReactNode,
useImperativeHandle,
useRef,
useState,
} from 'react';
import {Pressable, StyleSheet, TextInput, View} from 'react-native';
import {
BottomSheetBackdrop,
BottomSheetModal,
useBottomSheetScrollableCreator,
} from '@gorhom/bottom-sheet';
import {LegendList} from '@legendapp/list';
import * as Haptics from 'expo-haptics';
import {CaretDownIcon, CaretUpIcon} from 'phosphor-react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {colors} from '@/constants/colors';
import {BottomSheetHandle} from './LBottomSheet';
import {LText} from './LText';
type Props<ItemT> = {
ref?: React.RefObject<TextInput | null>;
onChange?: (item: ItemT | null) => void;
data: readonly ItemT[];
placeholder?: string;
value?: string;
defaultValue?: string;
keyExtractor: (item: ItemT) => string;
getLabel: (item: ItemT) => string;
renderItem: (info: {
item: ItemT;
index: number;
isSelected: boolean;
}) => ReactNode;
getIcon?: (item: ItemT) => ReactElement | null;
enableDynamicSizing?: boolean;
title?: string;
testID?: string;
};
export function LSelect<ItemT>({
ref,
data,
onChange,
placeholder,
value,
defaultValue,
keyExtractor,
getLabel,
renderItem,
getIcon,
enableDynamicSizing = false,
title,
testID,
}: Props<ItemT>) {
const isControlled = value !== undefined;
const insets = useSafeAreaInsets();
const [internalSelected, setInternalSelected] = useState<ItemT | null>(() => {
if (defaultValue) {
return data.find(d => keyExtractor(d) === defaultValue) || null;
}
return null;
});
const selected = isControlled
? data.find(d => keyExtractor(d) === value) || null
: internalSelected;
const bottomSheetRef = useRef<BottomSheetModal>(null);
const [bottomSheetVisible, setBottomSheetVisible] = useState(false);
const handlePress = () => {
console.log('LSelect > handlePress');
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
setBottomSheetVisible(true);
bottomSheetRef.current?.present();
};
const handleItemPress = (item: ItemT) => {
if (!isControlled) {
setInternalSelected(item);
}
onChange?.(item);
bottomSheetRef.current?.dismiss();
};
const handleDismiss = () => {
setBottomSheetVisible(false);
bottomSheetRef.current?.dismiss();
};
const renderBackdrop = (backdropProps: any) => (
<BottomSheetBackdrop
{...backdropProps}
disappearsOnIndex={-1}
appearsOnIndex={0}
/>
);
const wrappedRenderItem = ({item, index}: {item: ItemT; index: number}) => {
const isSelected = Boolean(
selected && keyExtractor(item) === keyExtractor(selected),
);
const content = renderItem({item, index, isSelected});
return (
<Pressable onPress={() => handleItemPress(item)}>{content}</Pressable>
);
};
const BottomSheetLegendListScrollable = useBottomSheetScrollableCreator();
// @ts-expect-error partial implementation
useImperativeHandle(ref, () => ({
focus: () => handlePress(),
blur: () => handleDismiss(),
}));
console.log('LSelect > bottomSheetVisible', bottomSheetVisible);
console.log('LSelect > data', data);
return (
<>
<Pressable style={styles.container} onPress={handlePress} testID={testID}>
<View style={styles.triggerContent}>
{selected && getIcon && (
<View style={styles.iconContainer}>{getIcon(selected)}</View>
)}
<LText style={styles.triggerText}>
{selected ? getLabel(selected) : placeholder}
</LText>
</View>
{bottomSheetVisible ? <CaretUpIcon /> : <CaretDownIcon />}
</Pressable>
<BottomSheetModal
handleComponent={() => (
<BottomSheetHandle header={title ? {title} : undefined} />
)}
enableDynamicSizing={enableDynamicSizing}
onDismiss={handleDismiss}
ref={bottomSheetRef}
topInset={insets.top}
snapPoints={['50%', '75%']}
backdropComponent={renderBackdrop}>
<LText>Hello</LText> {/* TODO: remove this */}
<LegendList
data={data}
renderItem={wrappedRenderItem}
keyExtractor={keyExtractor}
indicatorStyle="black"
ItemSeparatorComponent={() => <View style={styles.separator} />}
contentContainerStyle={[
styles.contentContainer,
enableDynamicSizing ? {paddingBottom: insets.bottom + 16} : null,
]}
maintainVisibleContentPosition
renderScrollComponent={BottomSheetLegendListScrollable}
testID="lselect-legend-list"
/>
</BottomSheetModal>
</>
);
}
const styles = StyleSheet.create({
container: {
borderWidth: 1,
borderColor: colors.black_15,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderRadius: 8,
paddingHorizontal: 16,
height: 56,
gap: 8,
},
triggerContent: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
contentContainer: {
paddingHorizontal: 8,
paddingTop: 8,
},
iconContainer: {
flexShrink: 0,
},
triggerText: {
flex: 1,
},
separator: {
height: 8,
},
});Reproduction sample
Relevant log output
TypeError: (0 , _bottomSheet.useBottomSheetScrollableCreator) is not a function
110 | };
111 |
> 112 | const BottomSheetLegendListScrollable = useBottomSheetScrollableCreator();
| ^
113 |
114 | // @ts-expect-error partial implementation
115 | useImperativeHandle(ref, () => ({
at LSelect (src/components/ui/LSelect.tsx:112:74)
at Object.react-stack-bottom-frame (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13976:20)
at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2866:22)
at updateFunctionComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6006:19)
at beginWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7474:18)
at runWithFiberInDEV (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1574:13)
at performUnitOfWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10972:22)
at workLoopSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10816:41)
at renderRootSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10797:11)
at performWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10384:39)
at performWorkOnRootViaSchedulerTask (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2094:7)
at flushActQueue (node_modules/react/cjs/react.development.js:566:34)
at node_modules/react/cjs/react.development.js:822:21PeKne
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working