React Testing Library与Jest测试单选按钮无法匹配名称问题
React单选按钮无障碍测试问题
问题场景
开发音乐合成器时用单选按钮切换波形,Jest测试中,统计单选按钮数量的断言能通过,但通过名称定位单选按钮的断言失败。
测试代码
import '@testing-library/jest-dom'; import {cleanup, getByTestId, render, screen, waitFor} from '@testing-library/react'; import Carrier from './carrier'; import Settings from './settings.json' beforeEach(()=>{ cleanup(); }) describe(`Rendering`, ()=>{ it(`renders waveform type radio buttons`,()=>{ render(<Carrier settings={Settings}/>); expect(screen.getAllByRole(`radio`).length).toBe(4); }); it(`checks radio buttons label match waveform types`,()=>{ render(<Carrier settings={Settings}/>); expect(screen.getByRole(`button`,{name:`sine`})).toBeInTheDocument(); }); });
测试输出
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "sine" Here are the accessible roles: group: Name "Waveform": <fieldset /> -------------------------------------------------- radio: Name "": <input data-testid="sine" name="sine" type="radio" /> Name "": <input name="triangle" type="radio" /> Name "": <input name="square" type="radio" /> Name "": <input name="sawtooth" type="radio" />
组件代码
const Carrier = ({settings}) =>{ return( <> <fieldset> <legend>Waveform</legend> <label htmlFor='sine'>sine</label> <input data-testid='sine' name='sine' type='radio'/> <label htmlFor='triangle'>triangle</label> <input name='triangle' type='radio'/> <label htmlFor='square'>square</label> <input name='square' type='radio'/> <label htmlFor='sawtooth'>sawtooth</label> <input name='sawtooth' type='radio'/> </fieldset> </> ); } export default Carrier;
已尝试的解决方法
- 测试button元素的类似代码可正常通过
- 在async测试中使用waitFor等待元素加载
- 使用getByTestID可正常定位,但因单选按钮数量多不希望采用该方式
- 移除{name:'sine'}后,控制台提示文档中有多个button元素
疑问
- 为何控制台输出中radio的name为空?按资料
expect(screen.getByRole('radio',{name:'sine'})).toBeInTheDocument();应该可行 - 我的代码中缺少了什么?
解决方案
1. 修正测试代码的role错误
测试里误写了getByRole('button'),目标元素是radio,这是直接报错的原因,应改为getByRole('radio')。
2. 修复单选按钮与label的关联问题
控制台中radio的无障碍名称为空,是因为label的htmlFor属性必须对应input的id属性,你仅给input设置了name,未添加id,导致label和input未正确关联,无障碍树无法识别label文本作为radio的名称。
另外,单选按钮需要相同的name属性实现组内互斥(同一时间只能选一个),当前每个radio的name都不同,不符合单选按钮的逻辑。
修正后的组件代码:
const Carrier = ({settings}) =>{ return( <> <fieldset> <legend>Waveform</legend> <label htmlFor='sine'>sine</label> <input id='sine' name='waveform' type='radio'/> <label htmlFor='triangle'>triangle</label> <input id='triangle' name='waveform' type='radio'/> <label htmlFor='square'>square</label> <input id='square' name='waveform' type='radio'/> <label htmlFor='sawtooth'>sawtooth</label> <input id='sawtooth' name='waveform' type='radio'/> </fieldset> </> ); } export default Carrier;
3. 修正后的测试断言
it(`checks radio buttons label match waveform types`,()=>{ render(<Carrier settings={Settings}/>); expect(screen.getByRole('radio',{name:'sine'})).toBeInTheDocument(); });
关键说明
- 无障碍名称(测试时的
name匹配项)来自关联的label文本,而非input的name属性,input的name是表单提交用的标识。 - 单选按钮必须共享同一个
name属性,才能实现组内互斥选择,这是HTML表单的基础规则。
内容的提问来源于stack exchange,提问作者wavesinaroom
相关产品推荐
相关产品推荐

