找到多个元素时如何过滤 getByLabelText 查询?

How to filter getByLabelText query when found multiple elements?

如何过滤 getByLabelText 查询,如果它抛出类型错误:TestingLibraryElementError: Found multiple elements with the text of: /to/i,我有以下 HTML 结构,其中有一些嵌套标签:

当前HTML结构

<div class="ant-row ant-form-item ant-radio-group-cards" style="row-gap: 0px;">
    <div class="ant-col ant-form-item-label">
        <!-- <label> with "To" text -->
        <label for="transferFunds_to" class="ant-form-item-required" title="To">To</label> 
    </div>
    <div class="ant-col ant-form-item-control">
        <div class="ant-form-item-control-input">
            <div class="ant-form-item-control-input-content">
                <!-- Other <label> with "To" text here -->
                <label class="ant-radio-button-wrapper">
                    <span class="ant-radio-button"><input id="transferFunds_to" type="radio" class="ant-radio-button-input" value="" /><span class="ant-radio-button-inner"></span></span>
                    <span>
                        <li class="ant-list-item">
                            <div class="ant-list-item-meta">
                                <div class="ant-list-item-meta-avatar">
                                    <svg width="1em" height="1em" viewBox="0 0 16 16" fill="none" style="font-size: 48px;"></svg>
                                </div>
                                <div class="ant-list-item-meta-content">
                                    <!-- "To" word here inside a label -->
                                    <h4 class="ant-list-item-meta-title">Account to</h4>
                                    <div class="ant-list-item-meta-description">Choose the account to transfer to</div>
                                </div>
                            </div>
                            <span role="img" class="anticon icon-size-middle" style="align-self: center;">
                                <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false" class=""></svg>
                            </span>
                        </li>
                    </span>
                </label>
            </div>
        </div>
    </div>
</div>

RTL 测试

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

// query applied
screen.getByLabelText(/to/i);

问题

所有 getBy* 查询在匹配项为零个或多于一个时都会抛出错误。

Queries

该错误表明您应该使用 getAllBy* 查询之一,其中 return 匹配数组,并且仅在未找到匹配项时抛出错误。

解决方案

由于您想要使用 id="transferFunds_to" 属性定位特定的 input 元素,您至少有几个选择:

  1. 在输入中添加一个testid并以此查询。

    <input
      id="transferFunds_to"
      data-testid="transferFunds_to" // <-- add a data test id
      type="radio"
      class="ant-radio-button-input"
      value=""
    />
    

    测试

    test("case-sensitive To", () => {
      render(<App />);
      screen.getByTestId("transferFunds_to");
    });
    
  2. 使用 manual query 并按指定的 id 属性定位。

    test("case-sensitive To", () => {
      const { container } = render(<App />);
      container.querySelector("#transferFunds_to")
    });
    

感谢 Cristian 的 codesandbox:https://codesandbox.io/s/trhh8

正如您在问题中指出的,两个标签上的文本匹配存在冲突

在第二个标签内输入“账户”、“选择要转账的账户”

如果您对此感到满意,并且不想更改 html 结构,唯一可用的选择是在 screen.getByLabelText[=19= 中使用更严格的正则表达式]

我分叉了您的示例并将正则表达式更新为 screen.getByLabelText(/^to$/i),它按预期工作,因为所有其他“to”后跟或在其后有 space,例如" to""to ",标签"To"没有pre或postspace,满足正则表达式

最终测试用例为:

import { screen, render } from "@testing-library/react";
import App from "./App";

test("case-sensitive To", () => {
  render(<App />);
  expect(screen.getByLabelText(/^to$/i).id).toBe("transferFunds_to");
});

看看https://codesandbox.io/s/react-testing-library-get-by-label-regex-g8tlx

当然,您也可以更改API并使用.querySelector或更通用的JS api