You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用React Testing Library测试React-Bootstrap NavDropdown组件

问题:React Testing Library无法找到React-Bootstrap NavDropdown子元素的data-testid属性

我尝试用React Testing Library测试带有data-testid属性的React-Bootstrap NavDropdown元素,但测试库找不到子元素的data-testid属性。

MyNav.tsx

import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import LOGO from './logo.svg';

const MyNav = (): JSX.Element => (
  <Navbar collapseOnSelect expand="lg" bg="dark" variant="dark">
    <Navbar.Brand href="/">
      <img src={LOGO} width="30" height="30" alt="React Bootstrap logo" />
      BBS
    </Navbar.Brand>
    <Navbar.Toggle aria-controls="responsive-navbar-nav" />
    <Navbar.Collapse id="responsive-navbar-nav">
      <Nav className="mr-auto">
        <NavDropdown
          title="English"
          id="navbarScrollingDropdown"
          data-testid="en-boards"
        >
          <NavDropdown.Item href="#en-news" data-testid="en-news">
            News
          </NavDropdown.Item>
          <NavDropdown.Item href="#en-sensitive-may">
            Politics
          </NavDropdown.Item>
        </NavDropdown>
        <NavDropdown title="日本語" id="navbarScrollingDropdown">
          <NavDropdown.Item href="#ja-news">ニュース</NavDropdown.Item>
          <NavDropdown.Item href="#ja-sensitive-may">政治</NavDropdown.Item>
        </NavDropdown>
      </Nav>
    </Navbar.Collapse>
  </Navbar>
);

export default MyNav;

MyNav.test.tsx

import React from 'react';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyNav from './MyNav';

test('renders nav', async () => {
  const user = userEvent.setup();
  render(<MyNav />);

  const navBarBrandEl = screen.getByText('BBS');
  const navDropDownElEn = screen.getByText('English');
  const navDropDownElJa = screen.getByText('日本語');

  expect(navBarBrandEl).toBeInTheDocument();
  expect(navDropDownElEn).toBeInTheDocument();
  expect(navDropDownElJa).toBeInTheDocument();

  const enBoards = screen.getByTestId('en-boards');
  await user.click(enBoards);
  const enNews = within(enBoards).getByTestId('en-news');

  expect(enNews).toBeInTheDocument();
});

测试结果

TestingLibraryElementError: Unable to find an element by: [data-testid="en-news"]

Ignored nodes: comments, script, style
<div
  class="nav-item dropdown"
  data-testid="en-boards"
>
  <a
    aria-expanded="false"
    class="dropdown-toggle nav-link"
    href="#"
    id="navbarScrollingDropdown"
    role="button"
    tabindex="0"
  >
    English
  </a>
</div>

  18 |   const enBoards = screen.getByTestId('en-boards');
  19 |   await user.click(enBoards);
> 20 |   const enNews = within(enBoards).getByTestId('en-news');
     |                                   ^
  21 |
  22 |   expect(enNews).toBeInTheDocument();
  23 | });

  at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:40:19)
  at node_modules/@testing-library/dom/dist/query-helpers.js:90:38
  at node_modules/@testing-library/dom/dist/query-helpers.js:62:17
  at getByTestId (node_modules/@testing-library/dom/dist/query-helpers.js:111:19)
  at Object.<anonymous> (src/MyNav.test.tsx:20:35)

环境信息

  • macOS 12.5
  • TypeScript 4.8.4
  • React 18.2.0
  • React-Bootstrap 2.5.0
  • testing-library/react 13.4.0

我试过相关方案但没有效果,恳请帮忙解决。


解决方案

核心原因

React-Bootstrap的NavDropdown组件会把下拉菜单渲染到body元素下,而非NavDropdown自身的DOM结构内,导致within(enBoards)无法找到子元素——因为子元素不在这个容器的DOM层级里。

修复方案1:全局异步查找子元素

直接使用screen.findByTestId(异步方法,会自动等待元素渲染)查找下拉子元素,无需局限于父容器:

import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyNav from './MyNav';

test('renders nav and dropdown items', async () => {
  const user = userEvent.setup();
  render(<MyNav />);

  // 验证基础导航元素
  expect(screen.getByText('BBS')).toBeInTheDocument();
  expect(screen.getByText('English')).toBeInTheDocument();
  expect(screen.getByText('日本語')).toBeInTheDocument();

  // 触发下拉菜单展开
  const enBoards = screen.getByTestId('en-boards');
  await user.click(enBoards);

  // 异步等待子元素渲染并查找
  const enNews = await screen.findByTestId('en-news');
  expect(enNews).toBeInTheDocument();
});

修复方案2:给下拉菜单容器添加testid(可选)

通过NavDropdown的menuProps属性,给下拉菜单容器传递data-testid,之后可以用within精准查找:

  1. 修改MyNav.tsx中的NavDropdown:
<NavDropdown
  title="English"
  id="navbarScrollingDropdown"
  data-testid="en-boards"
  menuProps={{ 'data-testid': 'en-boards-menu' }}
>
  {/* 子元素不变 */}
</NavDropdown>
  1. 修改测试代码:
await user.click(enBoards);
// 先等待菜单容器出现
const enBoardsMenu = await screen.findByTestId('en-boards-menu');
// 在菜单容器内查找子元素
const enNews = within(enBoardsMenu).getByTestId('en-news');
expect(enNews).toBeInTheDocument();

内容的提问来源于stack exchange,提问作者ykmr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:50:40