簡體   English   中英

反應測試渲染器測試失敗類型錯誤:無法讀取未定義的屬性(讀取“當前”)

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

我正在嘗試使用 react-test-renderer 進行單元測試,但我似乎無法通過測試,即使我正在測試的底層組件有效。 有人可以告訴我我做錯了什么

這是組件的代碼


   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;

這是測試代碼

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)
    
   
});

這些是我得到的錯誤

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)

我嘗試運行 yarn test 但它失敗了。

這里編輯的是animation文件的代碼

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";

我認為問題出在 animation.js 文件中。 最后一個錯誤行指向 animation.js 文件。 你能分享 animation.js 文件嗎

iconAnimation (src/components/WarrantyToggle/animation.js:411:83)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM