首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用React测试库测试文档侦听器

使用React测试库测试文档侦听器
EN

Stack Overflow用户
提问于 2021-04-21 00:47:43
回答 1查看 696关注 0票数 1

我正在尝试测试一个类似以下内容的React组件:

代码语言:javascript
复制
import React, { useState, useEffect, useRef } from "react";

export default function Tooltip({ children }) {
  const [open, setOpen] = useState(false);
  const wrapperRef = useRef(null);

  const handleClickOutside = (event) => {
    if (
      open &&
      wrapperRef.current &&
      !wrapperRef.current.contains(event.target)
    ) {
      setOpen(false);
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClickOutside);

    return () => {
      document.removeEventListener("click", handleClickOutside);
    };
  });

  const className = `tooltip-wrapper${(open && " open") || ""}`;

  return (
    <span ref={wrapperRef} className={className}>
      <button type="button" onClick={() => setOpen(!open)} />
      <span>{children}</span>
      <br />
      <span>DEBUG: className is {className}</span>
    </span>
  );
}

单击工具提示按钮将状态更改为open (更改className),在组件外部再次单击将其更改为closed。

组件工作(使用适当的样式),所有的React Testing Library (使用用户事件)测试工作,除了单击外部。

代码语言:javascript
复制
  it("should close the tooltip on click outside", () => {
    // Arrange
    render(
      <div>
        <p>outside</p>
        <Tooltip>content</Tooltip>
      </div>
    );

    const button = screen.getByRole("button");
    userEvent.click(button);

    // Temporary assertion - passes
    expect(button.parentElement).toHaveClass("open");

    // Act
    const outside = screen.getByText("outside");

    // Gives should be wrapped into act(...) warning otherwise
    act(() => {
      userEvent.click(outside);
    });

    // Assert
    expect(button.parentElement).not.toHaveClass("open"); // FAILS
  });

我不明白为什么我必须在act中包装点击事件--对于React测试库来说,这通常是不必要的。

我也不明白为什么最后的断言会失败。单击处理程序被调用两次,但open两次都为true

有一堆关于React合成事件的局限性的文章,但我不清楚如何将所有这些放在一起。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-20 01:06:35

我终于把它修好了。

代码语言:javascript
复制
  it("should close the tooltip on click outside", async () => {
    // Arrange
    render(
      <div>
        <p data-testid="outside">outside</p>
        <Tooltip>content</Tooltip>
      </div>
    );

    const button = screen.getByRole("button");
    userEvent.click(button);

    // Verify initial state
    expect(button.parentElement).toHaveClass("open");

    const outside = screen.getByTestId("outside");

    // Act
    userEvent.click(outside);

    // Assert
    await waitFor(() => expect(button.parentElement).not.toHaveClass("open"));
  });

关键似乎是要确保所有活动在测试结束之前完成。

比方说,一个测试触发了一个单击事件,该事件反过来设置状态。设置状态通常会导致重新呈现,您的测试需要等待它发生。通常情况下,您可以通过等待显示新状态来完成此操作。

在这种特殊情况下,waitFor是合适的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67183096

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档