在react-testing-library中通过id查找元素

117

我正在使用react-testing-library来测试我的React应用程序。由于某些原因,我需要能够通过id而不是data-testid找到元素。文档中没有办法实现这一点。

有没有办法实现这个功能?

我有如下渲染的输出:

const dom = render(<App />);

我正在寻找类似于以下内容的东西:

const input = dom.getElementById('firstinput');
//or 
const input = dom.getById('firstinput');

2
这对我有用:document.getElementById('firstinput') - James Gentes
7个回答

129

我觉得没有一个答案真正给出了完整的解决方案,所以这里是:

const result = render(<SomeComponent />);
const someElement = result.container.querySelector('#some-id');

3
对我没有起作用。但是当我登录 result.debug(),我可以清楚地看到具有该ID的元素。 :( - hashbytes
1
最初这对我没有起作用,因为id在react组件上,在组件中我忽略了id。我将其更改为组件包装在具有id的div中,然后它就起作用了! - matttm

82

我找到了一种方法来做这件事。

import App from './App';
import { render, queryByAttribute } from 'react-testing-library';

const getById = queryByAttribute.bind(null, 'id');

const dom = render(<App />);
const table = getById(dom.container, 'directory-table');

我希望这可以帮到你。


46
为什么他们默认没有这个??我简直不敢相信。 - Victor
18
直接使用 document.getElementById 会更加简单。但元素的ID是一个实现细节,我建议不要使用它。 - kentcdodds
3
相信吧,用户并不是通过ID来填写表单元素的,因此测试也不应该这样做(至少根据react-testing-library的理念如此)。他们是根据标签或占位文本等方式来填写表单的,所以在测试中,你应该以与用户相同的方式来查找元素:通过标签或占位文本等方式。 - lmat - Reinstate Monica
3
@Imat - Reinstate Monica,嗯,我讨论了一些情况,其中#id解决方案可能是理想的解决方案。一切都取决于情况。一个简单的例子:当使用第三方库(如Kendo)构建其元素时,可以通过提供的#id创建依赖于id来访问元素的测试。使用#id将保持与第三方库的新版本兼容,并且它也不会用data-test-id污染我们的代码。我在这里更详细地解释了这个问题:https://github.com/testing-library/react-testing-library/issues/683#issuecomment-643392223 - Victor
2
请继续向下滚动,直到@Liran H回答。 - Alejandro Maguey

28

看起来你将DOM节点本身作为一个容器。因此,你应该能够使用它来调用.querySelector('#firstinput')


1
是的,这个方法可以工作,但唯一的问题是现在我无法在返回的节点上使用 react-testing-library 的辅助函数。 - aks
2
如果你不需要它们,不使用辅助工具也没有问题。 - Gio Polvara
2
我无法在返回的节点上使用react-testing-library助手。这是不正确的。你说的是哪些助手?所有助手都处理常规DOM节点,因此找到它的方式并不重要。但无论如何,通过ID查找元素不包括在库中,因为那是实现细节。请使用内置查询之一。 - kentcdodds
Liran H的回答更好。有些人可能不明白你的意思。在我看来,像他那样给出完整的例子会更好。 - ajpieri
这是最快和最简单的实现方式。祝好。 - Nkoro Joseph Ahamefula

20

5
我认为您无法在容器上使用getElementById。 - djsoteric
26
这是正确的答案。(我是测试库的作者。) - kentcdodds
尝试记录“容器”,我猜它不是你要找的东西。 - Gio Polvara
4
@kentcdodds 我的意思是,如果能像(1.)那样工作就好了,但我得到的仅是TS2339:类型“HTMLElement”上不存在属性'getElementById'。 - pbialy
“getElementById”在RTL文档中甚至不存在“-”。对我来说,正确的方法是使用这个工具:https://chrome.google.com/webstore/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano 我再也不用花时间添加/查找ID了。 - Lucas Andrade
“getElementById”不在文档中,因为它不是RTL的API,而是由所有浏览器支持的DOM API。@pbialy 和 @mihai-zamfir 遇到的错误是 TypeScript 错误,与 RTL 无关。 - Gio Polvara

10

您可以在配置中使用testIdAttribute进行设置。

configure({ testIdAttribute: 'id' })

https://testing-library.com/docs/dom-testing-library/api-configuration


这种设置有利有弊。它的好处是可以为多个用途设置id。(测试id、营销分析、标签管理器等)你不必同时添加id和test-id,这样有助于代码的简洁性。

但要小心,可能会意外地在同一页上的两个不同组件中设置相同的id。请记得为列表项的组件id添加索引或标识。


testIdAttribute: getByTestId和相关查询使用的属性。默认为data-testid - Norman Lin
2
这是一个不好的想法,因为id应该是唯一的,只用于整个页面上的单个元素,而测试id可以用于多个元素(例如列表项)。 - Lokua
是的,你可能是对的。但如果我们需要使用id进行多种用途(例如标签管理器),设置中也有一些好处。 - Norman Lin

4

我的建议是:停止通过id添加和搜索元素,因为这样做通常需要花费大量时间和精力,因为你需要添加id(有时还要添加测试id),然后找到最佳的查询元素方法。但即使你真的需要一个id,在屏幕上查找任何DOM元素的最佳方法可以节省你很多时间,这个工具会帮助你: Testing Playground


1
如果您使用TypeScript,并且想要获得一个非null的结果,这里有一个方便的函数:
function getById<T extends Element>(container: HTMLElement, id: string): T {
  const element = container.querySelector<T>(`#${id}`);
  assert(element !== null, `Unable to find an element with ID #${id}.`)
  return element;
}

然后您可以像这样使用它:

import { render } from '@testing-library/react';

const { container } = render(<App />);
const myInputElement = getById<HTMLInputElement>(container, 'myInputElement');

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