找到多个元素时如何过滤 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*
查询在匹配项为零个或多于一个时都会抛出错误。
该错误表明您应该使用 getAllBy*
查询之一,其中 return 匹配数组,并且仅在未找到匹配项时抛出错误。
解决方案
由于您想要使用 id="transferFunds_to"
属性定位特定的 input
元素,您至少有几个选择:
在输入中添加一个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");
});
使用 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
如何过滤 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*
查询在匹配项为零个或多于一个时都会抛出错误。
该错误表明您应该使用 getAllBy*
查询之一,其中 return 匹配数组,并且仅在未找到匹配项时抛出错误。
解决方案
由于您想要使用 id="transferFunds_to"
属性定位特定的 input
元素,您至少有几个选择:
在输入中添加一个
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"); });
使用 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