在Jest中测试无状态子组件中的父方法

时间:2019-12-09 20:45:16

标签: reactjs testing jestjs

我目前有一个使用onChange方法的react组件。

我想测试onChange方法,例如是否有人键入或粘贴内容。问题是handleChange依赖于使用它的父组件。测试模拟的最佳方法是什么?我是否需要引用父组件的handleChange方法并进行模拟?

CodeSandbox(我没有在此处添加测试)

https://codesandbox.io/s/react-basic-example-cwdh1?from-embed

更新的当前测试:

const handleChange = jest.fn();

const initProps = {
  name: "Title",
  label: "Body",
  type: "text",
  value: "",
  handleChange
};

describe("TextBox", () => {
    let wrapper;
    beforeEach(() => {
      wrapper = mount(<TextBox {...props} />);
    });

    afterEach(() => {
      // resets the mocked fn after each test
      handleChange.mockClear();
    });

    it("should call handleChange with a new value", () => {
      const value = "testing input";
      wrapper.find("input").simulate("change", { target: { value } });

      expect(handleChange).toHaveBeenCalledWith(value);
    });
  });

错误:

Expected: "testing input"
Received: {"_dispatchInstances": null, "_dispatchListeners": null,
 "_targetInst": ......more fields... "nativeEvent": {"target": <input … />,
 "type": "change"}, "target": {"value": "testing input"}, "timeStamp":
 1576040322012, "type": "change"}

我知道我收到此错误,因为该值来自表单域。有什么方法可以提取目标字段?

1 个答案:

答案 0 :(得分:1)

我认为您对测试方法有些困惑。当您实际拥有的是一个单独的可重用{{1}时,您要尝试的是使用父子组件进行组件/集成测试(操纵父类字段以更新孩子的value道具)。 }没有父级的子级组件,需要进行单元测试。

因此,您有两种选择:

选项1:安装父组件并操纵其类字段以更新此子组件(和/或操纵子事件处理程序道具,然后再更新父组件的状态...,依此类推)。这将测试 ONE 特定组件的父代与子代之间的同步性。这对于测试管理TextBox并将其分配给某些子(form)组件的组件(例如state)特别有用。

选项2:浅入/挂接子组件并操纵其事件处理程序以触发开玩笑的模拟父项(例如,操纵输入的form elements道具并期望它以a调用模拟父项onChange道具。 handleChange)。它实际上并没有更新子级,而是对其进行了模拟。这对于测试可以具有许多不同父组件的 SHARED 可重用子组件特别有用。

可供选择的选项会因开发人员和项目以及项目而异。但是在理想情况下,您的测试套件将遵循类似于“测试金字塔”的内容: enter image description here

对于您而言,我建议如果该子组件与您的应用程序中的许多父组件共享,那么请同时进行父集成测试和子单元测试(这将导致一些重叠的测试,但要确保跨子组件的兼容性)应用程序(如果父母或孩子要更改或更新)。如果仅在单个父组件中重用此组件,则只需执行单个父集成测试。就是说,这只是我的建议-不规则!


另外,您的value组件不使用状态,因此您可以简单地使用无状态函数来代替类,而无需使用类:

TextBox

以下是如何测试此组件的示例

Edit React - Basic Example

一些注意事项: 您的const TextBox = ({ value, type, handleChange }) => ( <Form.Control type={type} value={value} onChange={handleChange} /> ); 本质上是第三方组件,大概已经由TextBox维护人员进行了测试。因此,从实际的角度来看,为此子组件创建测试是多余的。相反,我建议测试父组件,并期望在更改此子TextBox的react-bootstrap时更新父组件的状态。但是,codeandbox包含针对inputTextBox组件的测试。 关于为什么您的Form模拟函数被多个道具调用的原因……它被Synthetic Event调用,这是正常现象(我的大脑屁没有考虑到这一点)。就是说,您可以通过遍历expect.objectContaining数组或通过针对handleChange本身断言来使用mockedFn.mock.calls来断言mockedFn测试中的全部事件。 )。