react-testing-library 中的父节点

Kev*_*ton 18 html jestjs react-testing-library

我测试的组件呈现出以下内容:

<div>Text<span>span text</span></div>
Run Code Online (Sandbox Code Playgroud)

事实证明,为了测试我拥有的唯一可靠文本是“跨度文本”,但我想获得<div>. 使用 Jest 和 react-testing-library 我可以

await screen.findByText(spanText)
Run Code Online (Sandbox Code Playgroud)

这将返回一个 HTMLElement,但它似乎受到限制,因为我没有任何围绕该元素的上下文。例如,像 parentNode 和 previousSibling 这样的 HTML 方法返回 null 或 undefined。理想情况下,我想获取 parent 的文本内容<div>。知道如何使用 Jest 或 react-testing-library 做到这一点吗?

小智 31

一个很好的解决方案是closest函数。在closest功能描述中写道:Returns the first (starting at element) including ancestor that matches selectors, and null otherwise.

解决方案如下所示:

screen.getByText("span text").closest("div")
Run Code Online (Sandbox Code Playgroud)

  • @JakobJanKamminga 还有什么其他方法? (10认同)
  • 正如旁注:“getByText()”返回一个 DOM“Element”。所以 `closest()` 是一个标准的 js 函数(而不是测试库的一部分):https://developer.mozilla.org/en-US/docs/Web/API/Element/closest (8认同)
  • 使用直接节点访问不是最佳实践。TL 有一条 eslint 规则是这么说的。“避免直接节点访问。更喜欢使用测试库中的方法”。还有其他方法可以做到这一点。 (6认同)

Jak*_*nga 16

诚然,测试库并没有清楚地传达如何做到这一点。它包括一条 eslint 规则 no-direct-node-access ,表示“避免直接节点访问。更喜欢使用测试库中的方法”。这给人的印象是 TL 公开了针对这种情况的方法,但目前还没有。

您可能不想使用.closest(),因为您的项目强制执行 eslint 规则,或者因为它并不总是可靠的选择器。我找到了两种替代方法来解决您所描述的情况。

  1. within():如果您的元素位于可以通过测试库方法选择的另一个元素内例如footer具有唯一文本的 或 元素),则可以使用inside(),例如:
within(screen.getByRole('footer')).getByText('Text');
Run Code Online (Sandbox Code Playgroud)
  1. find()在具有自定义函数的元素内:
screen.getAllByText('Text').find(div => div.innerHTML.includes('span text'));
Run Code Online (Sandbox Code Playgroud)

看起来不太漂亮,但是你可以传递任何你想要的JS函数,所以它非常灵活可控。

诗。如果您根据您的 TypeScript 配置使用我的第二个选项,您可能需要在使用测试库的expect(...).toBeDefined().

  • 有趣的是,Kent 建议我不要启用相关的 eslint 规则(是的,TL 本身包含的规则)。OP 的情况是一个很好的情况,其中直接访问 DOM 节点是非常有必要的,因为 TL 不直接为您提供执行此操作的工具。我会相应地更新我的答案。 (3认同)
  • 我有点困惑。您说不使用本机 DOM 节点,但随后在本机 DOM 节点上访问“div.innerHTML”。`innerHTML` 可以,但是 `closest` 不只是因为 `innerHTML` 不遍历 DOM 树吗?(可以说,它仍然如此,只是它的字符串化版本)。据我了解,RTL 也不希望您触及 `innerHTML`,对吧? (2认同)

Ema*_*oun 9

但我用了很多HTML方法,还没有出现问题。HTML 方法有什么问题?

你可以试试这个代码。

const spanElement = screen.getElementByText('span text');
const parentDiv = spanElement.parentElement as HTMLElement;
within(parentDiv).getElementByText('...');
Run Code Online (Sandbox Code Playgroud)