React Testing Library测试问题:点击时event.target.href自动拼接域名
问题原因与解决方案
你遇到的问题是因为JSDOM(React Testing Library 依赖的模拟浏览器环境)会自动将 <a> 标签的 href 属性解析为绝对 URL。你测试里 mock 的 target.href 不会生效——fireEvent 触发点击时,事件对象的 target 是真实渲染的 <a> DOM 元素,它的 href 已经被 JSDOM 处理成了基于默认测试域名(https://www.example.com/)的绝对路径,所以实际传入 onLinkClick 的是解析后的完整 URL,而非你 mock 的 foo.com。
两种解决思路
思路一:修改组件,获取原始 href 属性值
如果你的需求是传递 <a> 标签上设置的原始 href 值(而非浏览器解析后的绝对 URL),可以把组件里的 e.target.href 替换为 e.currentTarget.getAttribute('href'):
const MyButton = ({ onLinkClick }) => { const handleClick = e => { e.preventDefault() // getAttribute 会返回标签上设置的原始属性值,不会被解析为绝对 URL onLinkClick({ href: e.currentTarget.getAttribute('href'), foo: 'bar', baz: 'quz' }) } return ( <a href='some-url' onClick={handleClick}>Click me</a> ) }
对应的测试可以直接断言原始值:
expect(props.onLinkClick).toHaveBeenCalledWith({ href: 'some-url', foo: 'bar', baz: 'quz', })
思路二:在测试中使用解析后的绝对 URL
如果你确实需要传递浏览器解析后的绝对 URL,测试里的期望值要和 JSDOM 生成的结果一致:
// 计算 JSDOM 会生成的绝对 URL const expectedHref = new URL('foo.com', 'https://www.example.com/').href; expect(props.onLinkClick).toHaveBeenCalledWith({ href: expectedHref, // 对应 "https://www.example.com/foo.com" foo: 'bar', baz: 'quz', })
另外,你测试里的 mockEvent 其实没有作用,因为 fireEvent 的事件对象 target 是真实 DOM 元素。如果要修改 <a> 的 href 属性,应该在渲染后直接操作 DOM:
const link = screen.getByRole('link'); // 修改 DOM 元素的 href 属性 link.href = 'foo.com'; fireEvent.click(link); expect(props.onLinkClick).toHaveBeenCalledWith({ href: new URL('foo.com', 'https://www.example.com/').href, foo: 'bar', baz: 'quz', })
内容的提问来源于stack exchange,提问作者noblerare
相关产品推荐
相关产品推荐

