简体   繁体   中英

react-test-renderer test failing TypeError: Cannot read properties of undefined (reading 'current')

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM