如何使用react-testing-library和jest测试功能组件内的状态

发布于 2025-01-10 15:45:03 字数 1723 浏览 0 评论 0原文

我有一个正在尝试测试的组件 -

export const Block = ({ title }) => {
      const [isSmall, setIsSmall] = useState(false);
      

      reutrn (

            <BlockContainer
                  onBlockContainerResize={(width: number) => (width < 180 ? setIsSmall(true) : setIsSmall(false))}
            >
                  <div className={isSmall ? 'title--small' : 'title'} data-testid={isSmall ? 'isSmall' : ''}>
                        {title}
                  </div>
                  <div className={isSmall ? 'desc--small' : 'desc'}>
                        {desc}
                  </div>
            </BlockContainer>
      )
}

我添加了一个数据测试ID,因为我想避免测试类名,因为这违背了反应测试库原则。我只是想确保如果容器低于 180px,则 isSmall 设置为 true。

对于我的测试,我使用 div 作为容器而不是父组件 BlockContainer -

test('should set isSmall to true if container width is below 180px', () => {
  render(
      <div style={{ width: '170px' }}>
        <Block
          title="test title"
          desc="test description"
        />
      </div>
  );

  expect(within(screen.getByTestId('isSmall')).queryByText('test title')).toBeInTheDocument();
});

但是,在尝试此操作时,isSmall 未设置为 true,因此未设置 datatest-id。我很困惑为什么会发生这种情况?

这是 BlockContainer 实现 -

export const BlockContainer: FunctionComponent<BlockContainerProps> = ({
  children,
  onBlockContainerResize,
}) => {
  const blockRef = useRef<HTMLDivElement>(null);

  useResizeObserver(blockRef, (entry) => onBlockContainerResize?.(entry.contentRect.width));

  return (
    <div
      ref={blockRef}
    >
      {children}
    </div>
  );
};

I have a component which I am trying to test -

export const Block = ({ title }) => {
      const [isSmall, setIsSmall] = useState(false);
      

      reutrn (

            <BlockContainer
                  onBlockContainerResize={(width: number) => (width < 180 ? setIsSmall(true) : setIsSmall(false))}
            >
                  <div className={isSmall ? 'title--small' : 'title'} data-testid={isSmall ? 'isSmall' : ''}>
                        {title}
                  </div>
                  <div className={isSmall ? 'desc--small' : 'desc'}>
                        {desc}
                  </div>
            </BlockContainer>
      )
}

I added a data-testid as I want to avoid testing classNames as this goes against react-testing-library principles. I just want to make sure that if the container is below 180px, then isSmall is set to true.

For my test I am using a div as the container rather than the parent component BlockContainer -

test('should set isSmall to true if container width is below 180px', () => {
  render(
      <div style={{ width: '170px' }}>
        <Block
          title="test title"
          desc="test description"
        />
      </div>
  );

  expect(within(screen.getByTestId('isSmall')).queryByText('test title')).toBeInTheDocument();
});

However when trying this, isSmall is not being set to true and so the datatest-id is not being set. I am confused as to why this is happening?

Here is the BlockContainer implementation -

export const BlockContainer: FunctionComponent<BlockContainerProps> = ({
  children,
  onBlockContainerResize,
}) => {
  const blockRef = useRef<HTMLDivElement>(null);

  useResizeObserver(blockRef, (entry) => onBlockContainerResize?.(entry.contentRect.width));

  return (
    <div
      ref={blockRef}
    >
      {children}
    </div>
  );
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

-黛色若梦 2025-01-17 15:45:03

使用 React 测试库进行测试时,了解其他组件的作用非常重要。例如,您将 isSmall 状态初始化为 false,并且仅在 onBlockContainerResize 的回调中将其设置为 true,但您没有执行任何操作来实现此目的。您需要触发该回调才能进行更改。

据说,在 RTL 中,主要目标是测试最终用户看到的内容并模拟最终用户所做的事情。这意味着要触发该回调,您需要模仿用户行为(例如,调整容器大小)。因此,我们需要知道用户如何做到这一点(在 BlockContainer 组件内),然后在渲染组件之后和断言组件之前使用 RTL 中的 fireEvent 触发该操作。

此外,我不会将 data-testid 属性放入 div 中并根据状态呈现它。这将您的测试与组件的实现结合起来。我会获取该 div,并检查其大小,这就是最终用户要做的事情,因为用户不知道内部状态。

希望这些提示有所帮助。如果没有,我们将需要一个 BlockContainer 的实现示例来了解如何触发此事件。

When testing with React Testing Library, it is important to know what other components do. For example, you are initializing the isSmall state to false, and only setting it to true on the callback of onBlockContainerResize, but you are not making any action to make this happen. You need to trigger that callback to make the change.

Said that, in RTL the main objective is to test what the final user sees and mock what the final user does. That means that to trigger that callback, you would need to mimic the user behaviour (for instance, resizing the container). So we need to know how does de user do that (inside the BlockContainer component), and then trigger that with a fireEvent from RTL, after rendering the component and before asserting it.

Furthermore, I wouldn't put a data-testid property in a div and render it depending on the state. That couples your test to the implementation of the component. I would take that div, and check its size, which is what the final user would do, as a user does not know about internal states.

Hope these tips help. If not, we will need an example of the implementation of BlockContainer to see how this event can be triggered.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文