在Jest中测试无状态子组件中的父方法 [英] Testing parent methods in stateless child component in Jest

查看:359
本文介绍了在Jest中测试无状态子组件中的父方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I currently have a react component with an onChange method.

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

I want to test the onChange method like if someone were to type in, or paste things in. The problem is the handleChange is dependent on the parent components using it. What's the best way to test for the simulation? Do I need to reference the parent component's handleChange method and simulate that?

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

CodeSandbox (i didn't add the tests here)

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

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

I know I'm getting this error because the value is coming out of the formfields. Is there a way I can extract the target field out?

推荐答案

我认为您对测试方法有些困惑.当您实际拥有的是一个单独的可重用的TextBox子组件,而没有父和子组件的组件/集成测试(操纵父类字段以更新子代的value道具)时,您要尝试做的是家长,需要进行单元测试.

I think you're a little confused about your testing methods. What you're trying to do is a component/integration test with a parent and child component (manipulating a parent class field to update a child's value prop), when what you actually have is an isolated reusable TextBox child component without a parent, which requires a unit test.

因此,您有两个选择:

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

Option 1: Mount the parent component and manipulate its class fields to update this child component (and/or manipulate the child's event handler props which then updates the parent's state... and so on). This will test synchronicity between a parent and its child for that ONE particular component. This is especially useful for testing a component (like a form) that manages state and allocates it to some children (form elements) components.

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

Option 2: Shallow/Mount the child component and manipulate its event handlers to trigger jest mocked parent props (like manipulating an input's onChange prop and expecting it to call a mocked parent handleChange prop with a value). It doesn't actually update the child but simulates it. This is especially useful for testing SHARED reusable child components that can have many different parent components.

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

Which option to choose will vary from dev to dev and project to project. But in an ideal world, your testing suites will follow something similar to the "testing pyramid":

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

In your case, I'd recommend that if this child component is shared with many parent components across your app, then do both parent integration tests and a child unit test (this will cause some overlapping tests, but ensures compatibility across the app if either a parent or the child were to change or be updated). If this component is only being reused within a single parent component, then just do a single parent integration test. That said, this just my recommendation -- not a rule!

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

On a separate note, your TextBox component doesn't utilize state, so instead of using a class, you can simply use a stateless function:

const TextBox = ({ value, type, handleChange }) => (
  <Form.Control
    type={type}
    value={value}
    onChange={handleChange}
  />
);


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

一些注意事项: 您的TextBox本质上是第三方组件,大概已经由react-bootstrap维护人员进行了测试.因此,从实际的角度来看,为此子组件创建测试是多余的.相反,我建议测试父组件,并期望当此子TextBox的input更改后,父组件的状态会更新.但是,codesandbox包含针对TextBoxForm组件的测试. 关于为何使用多个道具调用handleChange模拟函数的原因……是使用合成事件,这很正常(我的大脑屁没有考虑到这一点).也就是说,您可以通过遍历两个遍历对象使用 expect.objectContaining 来对合成事件进行断言 mockedFn.mock.calls 数组,或者通过对mockedFn本身(都包含在TextBox测试中).

Some notes: Your TextBox is essentially a third party component that has already, presumably, been tested by the react-bootstrap maintainers. So from a practical standpoint, creating a test for this child component is redundant. Instead, I'd recommend testing the parent component and expecting the parent's state to update when this child TextBox's input has been changed. Nevertheless, the codesandbox includes tests for both a TextBox and a Form component. In regards to why your handleChange mocked function was being called with multiple props... it's being called with a Synthetic Event, which is normal (my brain fart for not taking this into account). That said, you can assert against the Synthetic Event by using expect.objectContaining by either traversing the mockedFn.mock.calls arrays or by asserting against the mockedFn itself (both are included in the TextBox tests).

这篇关于在Jest中测试无状态子组件中的父方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆