如何在Jest和Testing Library中测试工具提示标题

28

我想测试工具提示标题是否等于特定文本。 这是我的antd工具提示,我想为它编写一个测试:

<Tooltip
  title={
     this.props.connection ? "Connected" : "Disconnected (Try again)"
         }>
  <Badge status="default" data-testid="connection-sign" />
</Tooltip>

这是我在 Jest 中的测试:

 test("Show error title in tooltip", async () => {
    baseDom = render(cardComponent);
    fireEvent.mouseMove(await baseDom.findByTestId("connection-sign")); //To hover element and show tooltip
    expect(
      baseDom.getByTitle(
        "Disconnected (Try again)"
      )
    ).toBeInTheDocument();
  });

但是这个测试失败了,无法找到具有该标题的元素。我该如何测试我的工具提示是否包含“已断开连接(请重试)”?


Tooltip 组件来自哪里?是自定义的还是来自 material-ui 或其他地方? - Rostyslav
这是来自 antd 的内容。我敢打赌提示框正在渲染,因为我可以通过 data-testid 找到它。但我想获取标题文本并检查其文本是否等于“断开连接”,这是我的问题。 - Zahra Talebi
6个回答

38

你的测试中有多个错误。

  1. 将组件类型而不是组件实例传递给render
// this is wrong, passing component type
baseDom = render(cardComponent);

// this is right, passing component instance created with JSX
baseDom = render(<cardComponent />);
  1. 使用 mouseMove 事件代替 mouseOver 事件

  2. 通过标题搜索元素并传递文本,而不是通过文本搜索元素

// wrong, because, the prop on the Tooltip is called 'title'
// but it is actually text as 'getByTitle' looks for HTML
// title attribute
baseDom.getByTitle("Disconnected (Try again)");

// right, because you are actually looking for text not
// HTML title attribute (but wrong see (4))
baseDom.getByText("Disconnected (Try again)");
  1. 使用同步方法而非异步方法进行工具提示搜索
// wrong, because, Tooltip is added dynamically to the DOM
baseDom.getByText("Disconnected (Try again)");

// right
await baseDom.findByText("Disconnected (Try again)");

总之,在修复所有错误后,测试应该如下所示:
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import App from "./App";

test("Show error title in tooltip", async () => {
  const baseDom = render(<cardComponent />);

  fireEvent.mouseOver(baseDom.getByTestId("connection-sign"));

  expect(
    await baseDom.findByText("Disconnected (Try again)")
  ).toBeInTheDocument();
});


谢谢。已完成并清晰 :) 实际上重点是“mouseOver”。 - Zahra Talebi
@Rostyslav 我想在取消悬停工具提示后检查工具提示内容是否不在文档中。我发现内容元素仍然存在于DOM中。如何处理这种情况? - Subrato Pattanaik
@Subro,你可以尝试waitFor这个工具提示消失。这是链接。否则,我将不得不查看代码,因为很难判断。 - Rostyslav
想简要了解waitForawait之间的区别。我将尝试使用waitFor - Subrato Pattanaik

5
我尝试了很多方法,但都没有成功,因此我尝试使用鼠标进入(mouse enter)而不是mouseOver或mouseMove,这对我起作用了。下面是一个测试工具提示内容的解决方案,例如:
import { render, cleanup, waitFor, fireEvent, screen } from '@testing-library/react';

// Timeline component should render correctly with tool-tip
test('renders TimeLine component with mouse over(tool-tip)', async () => {

  const { getByTestId, getByText, getByRole } = render(
        <TimeLine
          items={timeLineItems()}
          currentItem={currentTimeLineItem()}
          onTimeLineItemChange={() => {}}
        />
    );

  const courseTitle = "Course collection-3";

  fireEvent.mouseEnter(getByRole('button'));

  await waitFor(() => getByText(courseTitle));
  expect(screen.getByText(courseTitle)).toBeInTheDocument();
});

4

我发现这是最新的方法。你必须在测试中使用async(),然后等待findByRole,因为它不是即时的!

    render(<LogoBar />);
    fireEvent.mouseEnter(screen.getByLabelText('DaLabel'));
    await screen.findByRole(/tooltip/);
    expect(screen.getByRole(/tooltip/)).toBeInTheDocument();

4
除了接受的答案外,确保如果您为Antd工具提示设置getPopupContainer属性,则弹出窗口可能对React测试库不可见非常重要,因为在测试组件时特别是单元测试时,设置的DOM容器可能不可用于主体中。 例如:
在我的情况下,我有
<Popover
   getPopupContainer={() => document.getElementById('post--component-drawer')}
   content={<h1>Hello world</h1>}>
      <span data-testid="symbol-input--color-input">Click me</span>
</Popover>

在该单元测试中,post--component-drawer div 不可用。因此,我必须模拟 Popover,以确保我覆盖了 prop getPopupContainer 为 null,这样弹出窗口才能显示。

所以在我的测试文件开始时,我模拟了 Popover

jest.mock('antd', () => {
  const antd = jest.requireActual('antd');

  /** We need to mock Popover in order to override getPopupContainer to null. getPopContainer
   * sets the DOM container and if this prop is set, the popup div may not be available in the body
   */
  const Popover = (props) => {
    return <antd.Popover {...props} getPopupContainer={null} />;
  };

  return {
    __esModule: true,
    ...antd,
    Popover,
  };
});


test('popver works', async () => {
  render(<MyComponent/>);
  fireEvent.mouseOver(screen.getByTestId('symbol-input--color-input'));

  await waitFor(() => {
    expect(screen.getByRole('heading', {level: 1})).toBeInTheDocument();
  });
});

0
这是对Akshay Pal解决方案的轻微修改:

import { render, cleanup, waitFor, fireEvent, screen } from '@testing-library/react';

// Timeline component should render correctly with tool-tip
test('renders TimeLine component with mouse over(tool-tip)', async () => {

  render(
        <TimeLine
          items={timeLineItems()}
          currentItem={currentTimeLineItem()}
          onTimeLineItemChange={() => {}}
        />
    );

  const courseTitle = "Course collection-3";

  fireEvent.mouseEnter(screen.getByRole('button'));

  expect(await screen.getByText(courseTitle)).toBeTruthy();
});


0
我在处理类似的代码和React的Testing Library时遇到了困难,尤其是在使用外部组件时。对我来说,解决问题的关键是使用了...
fireEvent.focus(...component...)

希望这对一些人有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接