【问题标题】:setup function returns undefined when testing a custom hook usePrevioussetup 函数在测试自定义钩子 usePrevious 时返回 undefined
【发布时间】:2020-03-25 14:34:39
【问题描述】:

我从互联网上的某个地方获得了 usePrevious 钩子的代码。 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 中测试自定义钩子的正确方法吗?

根据@Dmitrii G cmets 的建议,我更改了代码以重新渲染组件(之前我正在重新安装组件)。

这是更新后的代码:

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 的解决方案,请随时在此处发布。谢谢。

【问题讨论】:

  • 有什么问题?
  • @DmitriiG。我希望我的测试返回“测试”,但它返回未定义
  • 您的 usePrevious 始终返回“上一个”值,在您的原因中该值最初是未定义的。您的代码按预期工作。
  • @DmitriiG.我调用 setup 函数两次,所以我希望值 test 而不是 undefined
  • @DmitriiG.你能告诉我正确的测试方法吗?

标签: javascript reactjs jestjs enzyme react-testing-library


【解决方案1】:

Enzyme by the hood 利用 React 的浅层渲染器。它有issue with running effects。不确定它是否会很快修复。 setTimeout 的解决方法让我感到惊讶,不知道它是否有效。不幸的是,这不是通用方法,因为您需要在案例重新呈现的任何更改上使用它。真的很脆弱。

作为一种解决方案,您可以改用mount()。

您也可以使用 mount() 模拟浅层渲染,并模拟每个嵌套组件:

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

【讨论】:

  • 感谢您将其发布为答案,我认为这可能对将来的某人有所帮助。
猜你喜欢
  • 2021-09-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 2020-01-23
  • 2020-08-20
  • 2020-07-10
  • 1970-01-01
  • 2020-09-18
相关资源
最近更新 更多