代码之家  ›  专栏  ›  技术社区  ›  Vishal

测试自定义钩子时,setup函数返回undefined

  •  -1
  • Vishal  · 技术社区  · 5 年前

    我从网上的某个地方得到了可以使用的代码。usePrevious的代码如下所示:

    export const usePrevious = (value) => {
      const ref = useRef();
      useEffect(() => {
        ref.current = value;
      }, [value]);
      return ref.current;
    };
    

    现在,我正在学习如何用笑话和酶来测试反应。所以,我试图测试usePrevious,但遇到了一些问题。以下是我的测试用例:

    import React from 'react';
    import { render } from 'enzyme';
    
    import { usePrevious } from './customHooks';
    
    const Component = ({ children, value }) => children(usePrevious(value));
    const setup = (value) => {
      let returnVal = '';
      render(
        <Component value={value}>
          {
            (val) => {
              returnVal = val;
              return null;
            }
          }
        </Component>,
      );
      return returnVal;
    };
    
    describe('usePrevious', () => {
      it('returns something', () => {
        const test1 = setup('test');
        const test2 = setup(test1);
        expect(test2).toBe('test');
      });
    });
    

    当测试执行完成时,我得到以下错误:

    Expected: 'test', Received: undefined
    

    谁能告诉我为什么我没有定义,这是在react中测试定制Hoook的正确方法吗?

    在@Dmitrii G的评论中提出建议后,我更改了代码以重新呈现该组件(之前我正在重新安装该组件)。

    以下是更新后的代码:

    import React from 'react';
    import PropTypes from 'prop-types';
    import { shallow } from 'enzyme';
    
    import { usePrevious } from './customHooks';
    
    const Component = ({ value }) => {
      const hookResult = usePrevious(value);
      return (
        <div>
          <span>{hookResult}</span>
          <span>{value}</span>
        </div>
      );
    };
    
    Component.propTypes = {
      value: PropTypes.string,
    };
    
    Component.defaultProps = {
      value: '',
    };
    
    
    describe('usePrevious', () => {
      it('returns something', () => {
        const wrapper = shallow(<Component value="test" />);
        console.log('>>>>> first time', wrapper.find('div').childAt(1).text());
        expect(wrapper.find('div').childAt(0).text()).toBe('');
    
        // Test second render and effect
        wrapper.setProps({ value: 'test2' });
        console.log('>>>>> second time', wrapper.find('div').childAt(1).text());
        expect(wrapper.find('div').childAt(0).text()).toBe('test');
      });
    });
    

    但我还是犯了同样的错误

    Expected: "test", Received: ""
    

    引入settimeout时,测试通过:

    import React from 'react';
    import PropTypes from 'prop-types';
    import { shallow } from 'enzyme';
    
    import { usePrevious } from './customHooks';
    
    const Component = ({ value }) => {
      const hookResult = usePrevious(value);
      return <span>{hookResult}</span>;
    };
    
    Component.propTypes = {
      value: PropTypes.string,
    };
    
    Component.defaultProps = {
      value: '',
    };
    
    
    describe('usePrevious', () => {
      it('returns empty string when component is rendered first time', () => {
        const wrapper = shallow(<Component value="test" />);
        setTimeout(() => {
          expect(wrapper.find('span').text()).toBe('');
        }, 0);
      });
      it('returns previous value when component is re-rendered', () => {
        const wrapper = shallow(<Component value="test" />);
        wrapper.setProps({ value: 'test2' });
        setTimeout(() => {
          expect(wrapper.find('span').text()).toBe('test');
        }, 0);
      });
    });
    

    我不太喜欢使用settimeout,所以我觉得我可能犯了一些错误。如果有人知道一个不使用settimeout的解决方案,请随时在这里发布。非常感谢。

    0 回复  |  直到 5 年前
        1
  •  1
  •   skyboyer    5 年前

    引擎盖旁的酶利用React的浅渲染器。它已经做到了 issue with running effects .不确定是否很快就能修好。 解决方法 setTimeout 对我来说是一个惊喜,我不知道它是有效的。不幸的是,这不是通用的方法,因为您需要在案例重新呈现的任何更改上使用它。真的很脆弱。

    作为一种解决方案,您可以使用 mount() 相反

    此外,还可以使用模拟浅层渲染 山() 通过模拟每个嵌套组件:

    jest.mock("../MySomeComponent.jsx", () =>
      (props) => <span {...props}></span>
    );