如何使用 React 测试库通过包含 html 标签的文本字符串进行查询?

新手上路,请多包涵

当前工作解决方案

使用这个 html:

 <p data-testid="foo">Name: <strong>Bob</strong> <em>(special guest)</em></p>

我可以使用 React 测试库 getByTestId 方法找到 textContent

 expect(getByTestId('foo').textContent).toEqual('Name: Bob (special guest)')

有没有更好的办法?

我想简单地使用这个html:

 <p>Name: <strong>Bob</strong> <em>(special guest)</em></p>

并使用 React Testing LibrarygetByText 方法如下:

 expect(getByText('Name: Bob (special guest)')).toBeTruthy()

但这不起作用。

那么,问题…

有没有更简单的方法来使用 React 测试库来查找带标签的文本内容字符串?

原文由 Beau Smith 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 842
2 个回答

更新 3

按照 下面 forrestDinos 的建议,使用来自 testing-library/jest-domtoHaveTextContent

更新 2

多次使用后,我创建了一个助手。下面是使用此帮助程序的示例测试。

测试助手:

 // withMarkup.ts
import { MatcherFunction } from '@testing-library/react'

type Query = (f: MatcherFunction) => HTMLElement

const withMarkup = (query: Query) => (text: string): HTMLElement =>
  query((content: string, node: HTMLElement) => {
    const hasText = (node: HTMLElement) => node.textContent === text
    const childrenDontHaveText = Array.from(node.children).every(
      child => !hasText(child as HTMLElement)
    )
    return hasText(node) && childrenDontHaveText
  })

export default withMarkup

测试:

 // app.test.tsx
import { render } from '@testing-library/react'
import App from './App'
import withMarkup from '../test/helpers/withMarkup'

it('tests foo and bar', () => {
  const { getByText } = render(<App />)
  const getByTextWithMarkup = withMarkup(getByText)
  getByTextWithMarkup('Name: Bob (special guest)')
})


更新 1

这是一个创建新匹配器 getByTextWithMarkup 的示例。请注意,此函数在测试中扩展了 getByText ,因此必须在此处定义。 (当然可以更新函数以接受 getByText 作为参数。)

 import { render } from "@testing-library/react";
import "jest-dom/extend-expect";

test("pass functions to matchers", () => {
  const Hello = () => (
    <div>
      Hello <span>world</span>
    </div>
  );
  const { getByText } = render(<Hello />);

  const getByTextWithMarkup = (text: string) => {
    getByText((content, node) => {
      const hasText = (node: HTMLElement) => node.textContent === text
      const childrenDontHaveText = Array.from(node.children).every(
        child => !hasText(child as HTMLElement)
      )
      return hasText(node) && childrenDontHaveText
    })
  }

  getByTextWithMarkup('Hello world')


这是 Giorgio Polvara 博客关于测试库的你(可能)不知道的五件事 中的第四个的可靠答案:


查询也接受函数

您可能已经看到过这样的错误:

找不到带有以下文本的元素:Hello world。这可能是因为文本被多个元素分解。在这种情况下,您可以为您的文本匹配器提供一个功能,以使您的匹配器更加灵活。

通常,发生这种情况是因为您的 HTML 如下所示:

 <div>Hello <span>world</span></div>

解决方案包含在错误消息中:“[…] 您可以为文本匹配器提供功能 […]”。

那是怎么回事?事实证明,匹配器接受字符串、正则表达式或函数。

该函数会为您渲染的每个节点调用。它接收两个参数:节点的内容和节点本身。您所要做的就是根据节点是否是您想要的节点返回 true 或 false。

一个例子将澄清它:

 import { render } from "@testing-library/react";
import "jest-dom/extend-expect";

test("pass functions to matchers", () => {
  const Hello = () => (
    <div>
      Hello <span>world</span>
    </div>
  );
  const { getByText } = render(<Hello />);

  // These won't match
  // getByText("Hello world");
  // getByText(/Hello world/);

  getByText((content, node) => {
    const hasText = node => node.textContent === "Hello world";
    const nodeHasText = hasText(node);
    const childrenDontHaveText = Array.from(node.children).every(
      child => !hasText(child)
    );

    return nodeHasText && childrenDontHaveText;
  });
});

我们忽略了 content 参数,因为在这种情况下,它将是“Hello”、“world”或空字符串。

我们正在检查的是当前节点是否具有正确的 textContenthasText 是一个小辅助功能。我宣布它是为了保持清洁。

但这还不是全部。我们的 div 不是我们要查找的文本的唯一节点。例如, body 在这种情况下具有相同的文本。为了避免返回比需要更多的节点,我们确保没有一个子节点与其父节点具有相同的文本。通过这种方式,我们确保我们返回的节点是最小的——换句话说,那个节点靠近我们的 DOM 树的底部。


阅读其余的 关于测试库你(可能)不知道的五件事

原文由 Beau Smith 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您在项目中使用 testing-library/jest-dom 。您也可以使用 toHaveTextContent

 expect(getByTestId('foo')).toHaveTextContent('Name: Bob (special guest)')

如果您需要部分匹配,您还可以使用正则表达式搜索模式

expect(getByTestId('foo')).toHaveTextContent(/Name: Bob/)

这是 的链接

原文由 forrestDinos 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进