I'm trying to do unit tests using react-test-renderer and I can't seem to make the test pass even though the underlying component I'm testing works. Can someone tell me what I'm doing wrong
This is the code for the component
import React, { useState } from "react";
import styles from "./styles";
import { View, Pressable, Animated } from "react-native";
import Text from "components/Text/";
import { t } from "services/i18n";
import Form, { Checkbox } from "components/Form";
import WarrantyDetails from "components/WarrantyDetails";
import Icons from "icons";
import { Color } from "theme";
import animation from "./animation";
const WarrantyToggle = ({ checked = false, price = 0, onUpdate = () => { }, disabled = false }) => {
const [detailsVisible, setDetailsVisible] = useState(false);
const [isChecked, setIsChecked] = useState(checked);
const [opacity, scale] = animation(isChecked);
const onChange = (value) => {
onUpdate(value);
setIsChecked(value);
};
return (
<View style={styles.container}>
<Form
style={styles.form}
initialValues={{ warranty: checked }}>
<Checkbox
id="warranty"
name="warranty"
onChange={onChange}
disabled={disabled}
testID="boxcheck"
style={styles.checkbox}
contentStyle={styles.priceRow}
checkbox={() => (
<View style={styles.heartCheckbox}>
<Icons.Warranty size={28} color={Color.dark} strokeWidth={3} />
<Animated.View style={[styles.heart, { opacity: opacity, transform: [{ scale: scale }] }]} >
<Icons.WarrantySelected size={28} color={Color.red} strokeWidth={3} />
</Animated.View>
</View>
)}
label={() => (<Text size="3" font="bold">{t("common:add-protection-plan")}</Text>)}>
<Text style={[styles.price, { opacity: isChecked ? 1 : 0.6 }]}>{`$${price?.toFixed(2)}`}</Text>
<Pressable testID="pressdetails" size={2.5} underline onPress={() => setDetailsVisible(true)}><Text underline style={styles.details}>{t("common:details")}</Text></Pressable>
</Checkbox>
</Form>
<WarrantyDetails
testID = "warrantydetailshigher"
selected={isChecked}
setSelected={setIsChecked}
visible={detailsVisible}
onClose={() => setDetailsVisible(false)}
onChange={onChange}
price={price}
/>
</View>
);
};
export default WarrantyToggle;
This is the code for the test
import React from "react";
import renderer from "react-test-renderer";
import WarrantyToggle from "../../../src/components/WarrantyToggle";
const tree = renderer.create(<WarrantyToggle/>)
test(" Perfect lib error screen renders correctly", () => {
const tree1 = renderer
.create(
<WarrantyToggle name="hello test" />
)
.toJSON();
expect(tree1).toMatchSnapshot();
});
test('box checked' ,() =>{
const warrantycheck = tree.root.findByProps({testID:'boxcheck'})
const detailstate = tree.root.findByProps({testID:'warrantydetailshigher'})
if(detailstate.selected == true){
renderer.act(() => warrantycheck.onChange());
expect(detailstate.selected).toEqual(true)
}
else{
renderer.act(() => warrantycheck.onChange());
expect(detailstate.selected).toEqual(false)
}
});
test('press details' ,() =>{
const warrantypress = tree.root.findByProps({testID:'pressdetails'})
const detailstate = tree.root.findByProps({testID:'warrantydetailshigher'})
renderer.act(() => warrantypress.onPress());
expect(detailstate.visible).toEqual(true)
});
These are the errors I'm getting
FAIL __tests__/components/WarrantyToggle/WarrantyToggle.test.js
● Console
console.error
The above error occurred in the <WarrantyToggle> component:
at WarrantyToggle (/Users/robertbeit/Documents/sally2/app-mobile-sally-reactnative/src/components/WarrantyToggle/index.js:3777:35)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
at logCapturedError (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10989:23)
at update.callback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:11022:5)
at callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:3662:12)
at commitUpdateQueue (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:3683:9)
at commitLifeCycles (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:11855:11)
at commitLayoutEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14443:7)
at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:11391:14)
at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
● Perfect lib error screen renders correctly
TypeError: Cannot read properties of undefined (reading 'current')
at iconAnimation (src/components/WarrantyToggle/animation.js:411:83)
at WarrantyToggle (src/components/WarrantyToggle/index.js:3847:54)
at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6016:18)
at mountIndeterminateComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8744:13)
at beginWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9966:16)
at performUnitOfWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13800:12)
at workLoopSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13728:5)
at renderRootSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13691:7)
at performSyncWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13404:18)
at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2537:26
at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:468:12)
at runWithPriority (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2486:10)
at flushSyncCallbackQueueImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2532:9)
at flushSyncCallbackQueue (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2519:3)
at scheduleUpdateOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13004:9)
at updateContainer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16454:3)
at Object.create (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:17149:3)
at Object.<anonymous> (__tests__/components/WarrantyToggle/WarrantyToggle.test.js:8:3)
I tried running yarn test but it fails.
Edit here is the code for the animation file
import { useRef, useEffect, useCallback } from "react";
import { Animated, Easing } from "react-native";
const iconAnimation = (selected) => {
const opacityValue = useRef(new Animated.Value(0)).current;
const scaleValue = useRef(new Animated.Value(0)).current;
const animateOpacityValue = useCallback(
() => {
Animated.timing(opacityValue, {
toValue: selected ? 1 : 0,
easing: Easing.inOut(Easing.quad),
duration: 300,
useNativeDriver: true,
isInteraction: false
}).start();
Animated.timing(scaleValue, {
toValue: selected ? 1.1 : 1,
easing: selected ? Easing.out(Easing.back(25)) : Easing.inOut(Easing.quad),
duration: 500,
useNativeDriver: true,
isInteraction: false
}).start();
},
[selected],
);
useEffect(() => {
animateOpacityValue();
}, [animateOpacityValue]);
return [opacityValue, scaleValue];
};
export default iconAnimation;```
this is from the index.js form file
import React, { useRef, Fragment, useEffect } from "react";
import { View } from "react-native";
import styles from "./style";
import { Formik } from "formik";
function Row({ children, getRef = () => { }, nextElement = () => { }, values, onUpdate, onPressHandler, style }) {
children = children.filter(function (element) {
return element !== undefined;
});
return (
<View style={[styles.row, style]}>
{
React.Children.map(children, (child, index) => {
if (!child || child.props === undefined) {
return <View />;
}
const id = child.props.id;
return (
<Fragment key={`row-${index}`}>
{
React.cloneElement(child, {
containerStyle: styles.rowItem,
getRef: getRef,
value: (values && values[id]) ? values[id] : "",
values: values,
flex: child.props.flex ? child.props.flex : 1,
onUpdate: onUpdate,
onPressHandler: onPressHandler ?? child.props.onPress,
nextElement: nextElement,
})
}
{
index < children.length - 1 &&
<View style={styles.gutter} />
}
</Fragment>
);
})
}
</View>
);
}
function Form({
formRef,
children,
values,
onUpdate,
initialValues,
initialTouched,
validationSchema,
onSubmitHandler,
fieldValueRef,
resetForm = false,
style = {},
gutterStyle = {}
}) {
const internalFormRef = React.createRef(undefined);
useEffect(() => {
if ((formRef && formRef.current) && resetForm) {
formRef.current.resetForm();
} else if ((internalFormRef && internalFormRef.current) && resetForm) {
internalFormRef.current.resetForm();
}
}, [resetForm, formRef, internalFormRef]);
const inputRefs = useRef([]);
const focusNextElement = (event) => {
const index = inputRefs.current.indexOf(event.target);
if (index !== -1) {
const nextElement = inputRefs.current[index + 1];
if (nextElement) {
nextElement.focus();
}
}
};
const getRef = (element, name) => {
if (element && !inputRefs?.current?.includes(element)) {
inputRefs.current.push(element);
}
};
return (
<View style={[styles.formContainer, style]}>
<Formik
innerRef={formRef ?? internalFormRef}
initialValues={initialValues}
initialTouched={initialTouched}
enableReinitialize={true}
validateOnBlur={true}
validateOnChange
validationSchema={validationSchema}
onSubmit={onSubmitHandler}
>
{({ handleSubmit, setFieldValue }) => {
if (fieldValueRef) {
fieldValueRef.current = setFieldValue;
}
return (
<>
{
React.Children.map(children, (child, index) => {
if (!child || child.props === undefined) {
return <View />;
}
return (
<Fragment>
{
React.cloneElement(child, {
nextElement: focusNextElement,
getRef: getRef,
value: (values && values[child.props.id]) ? values[child.props.id] : "",
values: values,
onUpdate: onUpdate,
onPress: child.props.willHandleSubmit ? handleSubmit : child.props.onPress
})
}
{
index < children.length - 1 &&
<View style={[styles.gutter, gutterStyle]} />
}
</Fragment>
);
})
}
</>
);
}}
</Formik>
</View>
);
}
export default Form;
export { Row };
export { default as FormValidationSchema } from "./formValidationSchemas";
export { default as Button } from "./Button";
export { default as Link } from "./Link";
export { default as NumberInput } from "./NumberInput";
export { default as LoadingIndicator } from "./LoadingIndicator";
export { default as Checkbox } from "./Checkbox";
export { default as PLPCheckbox } from "./PLPCheckbox";
export { default as Modal } from "./Modal";
export { default as RadioGroup, RadioButton } from "./RadioGroup";
export { default as SelectInput } from "./SelectInput";
export { default as TextInput } from "./TextInput";
export { default as GooglePlacesInput } from "./GooglePlacesInput";
export { default as DatePicker } from "./DatePicker";
export { default as TextInputButton } from "./TextInputButton";
I think the problem is in animation.js file. Last error line point to animation.js file. Can you share animation.js file
iconAnimation (src/components/WarrantyToggle/animation.js:411:83)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.