【问题标题】:How to fire events on multiple layers of custom components with react unit testing如何使用反应单元测试在多层自定义组件上触发事件
【发布时间】:2022-01-24 18:48:29
【问题描述】:

我正在为我正在单元测试的功能编写测试用例。我想编辑嵌入在多个自定义组件中的文本字段,但我不知道如何访问它:

TestFile.test.tsx

it('should be able to change quantity', () =>{
  //Mock out dependent function with jest
  //Nothing here right now


  //Render with the props you want
  render(        
        <MainComponent /> );

  //Locate screen components for test
  const counter = screen.queryByTestId("counter");

  //Perform user actions
  fireEvent.change(counter, 4);   <--This is the line where I'm trying to access what I want

  //Measure against expect cases
  expect(counter).toBe(4);
});

MainComponent.tsx

这是我试图访问的组件。问题是,`fireEvent.change` 不起作用,因为它是一个自定义组件。至少,我认为这就是它不起作用的原因。
<Counter
  data-testid='counter'    <--data-testid is here right now
  containerMargin={{ marginTop: -5 }}
/>

Counter.tsx

`Counter` 内部是另一个自定义组件,`TextField`
<TextField
     {...props}
/>

TextField.tsx

在 TextField 内部是我要访问的文本输入:
<TextInput
  {...props}
/>

错误信息

当我尝试运行测试时,我收到此错误:
  ●  Test › should be able to change quantity

Unable to fire a "change" event - please provide a DOM element.

  189 |
  190 |     //Perform user actions
> 191 |     fireEvent.change(counter, 4);
      |               ^
  192 |
  193 |     //Measure against expect cases
  194 |     expect(counter).toBe(4);

我不能将data-testid 属性放入TextFieldTextInput 本身,因为在我正在测试的页面的呈现中还有另一个Counter。任何建议或故障排除都会有所帮助,谢谢!

【问题讨论】:

标签: reactjs typescript react-native unit-testing react-testing-library


【解决方案1】:

The getByTestId query is an escape hatch.

本着指导原则的精神,建议仅在其他查询不适用于您的用例之后才使用它。使用 data-testid 属性与您的软件的使用方式不同,应尽可能避免使用。

您的文本字段应该可以访问。并且应该利用accessibility 来访问该元素。

const input = screen.getByRole('textbox', {name: t('priceMultiple')})
// or
const input = screen.getByLabelText(t('priceMultiple'))

Using fireEvent directly is also an escape hatch.

大多数项目都有一些fireEvent 的用例,但大多数时候您可能应该使用@testing-library/user-event

in the user-event docsin this blog post 进一步解释了此建议。

await userEvent.type(input, '4')

请注意,在大多数情况下,建议设置用户事件实例并描述用户在组件上执行的确切工作流程。所以大多数测试应该是这样的。

const user = userEvent.setup()
render(<MyComponent/>)

await user.tripleClick(screen.getByRole('textbox', {name: /some label/}))
await user.keyboard('4')

// ... assert that the component output is correct ...

await user.tab()
await user.keyboard('567') // edit another field

// ... perform more assertions ...

【讨论】:

    【解决方案2】:

    一般来说,你是对的,将data-testid 添加到 React 组件是没有用的,除非你将此 prop 向下传播到 DOM 元素。 幸运的是,&lt;TextField /&gt; 接受 inputProps 并将其传播到 &lt;input /&gt; 元素。

    例如

    export default function BasicTextFields() {
      return (
        <ChildComponent data-testid="counter" />
      );
    }
    
    const ChildComponent = (props) => {
      return (
        <TextField
          inputProps={{ "data-testid": props["data-testid"] }}
          id="outlined-basic"
          label="Outlined"
          variant="outlined"
        />
      );
    };
    

    然后你可以在测试中使用getByTestId

    test("should be able to trigger input change", () => {
      render(<BasicTextFields />);
      const input = screen.getByTestId("counter");
      fireEvent.change(input, { target: { value: "23" } });
      expect(input.value).toBe("23");
    });
    

    https://codesandbox.io/s/flamboyant-joliot-0f49v?file=/src/App.js

    我没有创建您创建的深层层次结构以使我的答案更清晰,但只要您将道具传播到&lt;TextField /&gt;,您应该会很好。您也可以使用Context,但这超出了此答案的范围。

    【讨论】:

    • 所以这需要我使用TextField组件,但是我的框架已经是使用TextInput构建的,如果我尝试更改它会出现太多问题
    • 我刚刚意识到,我有点困惑,因为你提到:react-native 和 react-testing-library 但 react-testing-library 不支持 web。 react-native-testing-library 是测试库的原生反应风格。那是什么?
    • @testing-library/react 是我一直用于测试的包,但 TextInput 来自 'react-native-gesture-handler',因此很难测试。我终于把它弄到了可以定位它的地步,但现在我不能改变它里面的值
    • 你为什么不使用react-native-testing-libraryfireEvent.change 不工作吗?您能否在应用的不同位置触发事件?
    • 抱歉,我花了很长时间才回复。我正在使用包@testing-library/react。不是@testing-library/react-native。 react-native 不允许我在完成的渲染上使用 screen.getBy() 调用。虽然我无法让 fireEvent.change 工作,但我确实让 fireEvent.click 为其他事情工作。
    猜你喜欢
    • 2019-04-12
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 2021-01-02
    相关资源
    最近更新 更多