【问题标题】:In Enzyme, how to get a function from the props of a functional component?在 Enzyme 中,如何从函数组件的 props 中获取函数?
【发布时间】:2021-01-06 10:26:18
【问题描述】:

我正在使用 Jest 和 Enzyme 为我的 react 项目编写单元测试。

如下图,我通过props将一个名为updateUser的函数传递给待测组件EditCard

describe('The EditCard screen', () => {
  let wrapper;

  beforeEach(() => {
    const defaultProps: Partial<EditCardProps> = {
      toggleEditing: jest.fn(),
      user: mockUsers[0],
      updateUser: jest.fn(),      // passes this function to the "EditCard" component via props
      showSnackbar: jest.fn(),
    };
    wrapper = shallow(<EditCard {...(defaultProps as EditCardProps)} />);
  });

那我想测试一下模拟点击按钮后被调用了多少次。

  it('should match the snapshot when the "Name" textfield is not filled and the "submit" button is clicked', () => {
    wrapper.find('#Name').simulate('change', { target: { value: null } });
    wrapper.find('#submit').simulate('click');
    
    // Try to get the "updateUser" function from the props, but get "undefined". 
    expect(wrapper.prop('updateUser')).toHaveBeenCalledTimes(0);
  });

但是我得到了如下所示的错误:

    Matcher error: received value must be a mock or spy function

    Received has value: undefined

      24 |     wrapper.find('#Name').simulate('change', { target: { value: null } });
      25 |     wrapper.find('#submit').simulate('click');
    > 26 |     expect(wrapper.prop('updateUser')).toHaveBeenCalledTimes(0);

谁能告诉我哪里做错了?为什么我无法从 props 中获取函数并且返回了undefined

提前致谢!

【问题讨论】:

    标签: javascript reactjs jestjs enzyme


    【解决方案1】:

    对您的代码进行一些调整应该可以使其正常工作...

    import * as React from "react";
    import { mount, ReactWrapper } from "enzyme";
    import EditCard from "../path/to/EditCard";
    
    /* 
      I'd recommend defining jest fns here to make them easier to reference anywhere
      within the tests below; otherwise, it'll have to referenced via 
      'defaultProps.updateUser', 'defaultProps.showSnackbar', ...etc. 
      Using 'const' here allows us to define these variables within the 
      module's closure -- in short, only accessible within these tests and NOT 
      globally accessible (from other file tests).
    */
    const showSnackbar = jest.fn();
    const toggleEditing = jest.fn();
    const updateUser = jest.fn();
    
    /* 
      if the EditCard component is properly typed, then you shouldn't need to
      add types to this 'defaultProps' object
    */
    const defaultProps = {
      showSnackbar,
      toggleEditing,
      updateUser,
      user: mockUsers[0]
    };
    
    describe('The EditCard screen', () => {
      let wrapper: ReactWrapper;
      beforeEach(() => {
        /* 
          I'd recommend mount over shallow because child components can be 
          deeply nested and require multiple .dive calls; however, if 
          you know the child components of "EditCard" are just simple JSX elements, 
          then shallow will be fine
        */
        wrapper = mount(<EditCard {...defaultProps} />);
      });
    
      it("should not call 'updateUser' when the form is submitted with an empty '#Name' field", () => {
        /*
          I'm not sure what simulating "null" does for this input, but assuming this
          input is required you should at least pass a string value -- assuming
          "#Name" input is of type 'text' | 'password' | 'email' => string and 
          not a number. On a related note, if it's required, then simply remove this 
          code as it doesn't do much for the test.
        */
        // wrapper.find('#Name').simulate('change', { target: { value: "" } });
    
        /*
          I'm assuming this then simulates a form submit. Unfortunately,
          pressing the submit button won't work. Instead you'll have to 
          simulate a form submit. This is a limitation of Enzyme and last I 
          checked hasn't been/can't be fixed.
        */
        wrapper.find('form').simulate('submit');
        
        /*
         it should then NOT call the jest.fn() "updateUser" when submitted since 
         '#Name' is empty. Notice that we're referencing 'updateUser' -- the jest fn
         defined above -- and not the wrapper.prop fn.
        */ 
        expect(updateUser).not.toHaveBeenCalled();
      });
      
      // include other tests...
    });
    
    

    这是一个工作示例(单击 Tests 选项卡运行测试):

    【讨论】:

    • 非常感谢!我想关键是在defaultProps 之外定义函数,这样我就不必从props中获取它们来检查它们被调用的次数,因为在使用shallow时这是不可行的。我认为使用shallow 时无法从道具中获取功能。我试过mount,它奏效了。但是如果我必须坚持使用shallow,我必须在defaultProps之外定义它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 2022-11-30
    • 1970-01-01
    • 2021-11-25
    • 2021-03-22
    • 2021-06-16
    相关资源
    最近更新 更多