React 测试库 - 避免 getBy?

React Testing Library - Avoid getBy?

当使用 React 测试库测试组件时,我发现自己从 getBy* 开始,偶尔需要用 queryBy* 替换它(例如,如果我需要检查不存在一个元素)。我的测试以 getByqueryBy 的混合结束,我最近一直在使用 queryBy 来处理所有事情。

这让我开始思考...是否有理由使用 getBy

像这样的断言会按预期失败,不需要抛出错误:

expect(queryByText('Click me')).toBeInTheDocument();
expect(queryByLabel('Name').value).toBe('George')

如果未找到元素,抛出错误有什么好处?是否有理由不对所有(同步)查询使用 queryBy

编辑: 看起来 queryBy 现在 推荐用于断言某事 不是 文档中:

https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-query-variants-for-anything-except-checking-for-non-existence

文章还建议使用 screen.queryBy/screen.getBy 而不是从 render 解构,这样可以简化从一个函数到另一个函数的更改,因为您不再需要更新解构函数。

如您所述,getBy* 和 queryBy* 之间的区别在于,如果找不到元素,getBy* 会抛出错误,而 queryBy* 不会。对我来说,如果我期望某物在那里,我总是使用 getBy* 并且仅在我断言某物不存在的情况下使用 queryBy*。如果一个元素不存在,我希望它存在,我想在测试中尽早知道它,这是进行 getBy* 调用的地方。

所以我想说抛出错误的好处是你总是确保你的测试失败将指向根本问题(无法找到你期望存在的元素)而不是副作用那个根本问题(稍后在测试中尝试使用那个元素)。

示例测试:

    const { getByTestId, queryByTestId } = render(getComponent());

    const textInput = queryByTestId("textInput");

    fireEvent.change(textInput, { target: { value: "hello" } });
    fireEvent.change(textInput, { target: { value: "hi" } });

使用queryByTestId,测试输出为:

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

      23 |     const textInput = queryByTestId("textInput") as any;
      24 |
    > 25 |     fireEvent.change(textInput, { target: { value: "hello" } });
         |               ^
      26 |     fireEvent.change(textInput, { target: { value: "hi" } });
      27 |

所以它确实表明未找到 textInput。如果我将其更改为 getByTestId,则输出为

Unable to find an element by: [data-testid="textInput"]

    <body>
      <div>
        <div>
          <button
            type="button"
          >
            Show the Text Input!
          </button>
        </div>
      </div>
    </body>

      21 |     const { getByTestId, queryByTestId, rerender } = render(getComponent());
      22 |
    > 23 |     const textInput = getByTestId("textInput") as any;
         |                       ^
      24 |
      25 |     fireEvent.change(textInput, { target: { value: "hello" } });
      26 |     fireEvent.change(textInput, { target: { value: "hi" } });

所以getBy*错误输出在我看来有两个优点:

  1. 它直接指向问题所在的行。不难发现查询 "textInput" 是第一种情况的问题。但是有点不直接。
  2. 当我使用 getBy* 时,它会自动打印出 DOM 的样子。这有助于确定我要查找的内容不存在的原因。一旦 queryBy* 测试失败,这可能是我要采取的第一步,所以它会自动出现,这很好。

这些边际开发体验改进值得我使用 getBy* 变体作为默认变体。通常我只在我的测试中使用 getBy* 并且只在断言某些东西不存在很重要时才使用 queryBy* 。当然,只使用 queryBy* 是可能的,如果您发现使用这两种方法的成本大于收益,您可以自由地这样做。