Jest无法识别React组件中onClick修改的jurisdiction变量值
问题:React地址组件下拉选择未更新jurisdiction值,测试断言失败
我有一个Address React组件,其中包含由{streetAddress, additionalStreetAddress, city, jurisdiction, zipCode}定义的address对象。jurisdiction是一个包含美国所有州的下拉Select组件,代码如下:
<Select id={`${id}-jurisdiction`} name="jurisdiction" placeholderOption=" " labelVisual="State" value={jurisdiction} > {JURISDICTIONS.map((currentJurisdiction) => ( <SelectOption id={`jurisdiction-${currentJurisdiction}`} key={currentJurisdiction} value={currentJurisdiction} onClick={(e) => { jurisdiction = e.currentTarget.value; }} > {currentJurisdiction} </SelectOption> ))} </Select>
我编写了如下测试用例验证该功能,但Jest期望得到'MA',实际却接收到空字符串:
it('should update selected option and updated address jurisdiction when user makes a selection', async () => { const jurisdictionDropDown = screen.getByRole('combobox'); const user = userEvent.setup(); const selectedJurisdiction = 'MA'; await user.selectOptions(jurisdictionDropDown, [selectedJurisdiction]); expect(address.jurisdiction).toEqual('MA'); });
问题原因与修复方案
1. 组件状态更新逻辑错误
你直接通过jurisdiction = e.currentTarget.value修改变量的方式不符合React的状态管理规则:
- 如果
jurisdiction是组件内部状态(比如用useState声明的),直接赋值不会触发组件重渲染,也不会更新状态的实际值,状态仍会保持初始的空字符串。 - 下拉选择的交互逻辑不应该绑定在
SelectOption的onClick事件上,因为用户可能通过键盘导航选择选项,onClick无法覆盖所有交互场景,正确的做法是给Select组件绑定onChange事件(具体事件名需参考你使用的自定义Select组件的API)。
修复组件代码(函数组件示例):
import { useState } from 'react'; function Address({ id }) { // 用useState管理address状态 const [address, setAddress] = useState({ streetAddress: '', additionalStreetAddress: '', city: '', jurisdiction: '', zipCode: '' }); return ( <Select id={`${id}-jurisdiction`} name="jurisdiction" placeholderOption=" " labelVisual="State" value={address.jurisdiction} // 绑定Select的onChange事件更新状态 onChange={(e) => { setAddress(prevAddress => ({ ...prevAddress, jurisdiction: e.target.value })); }} > {JURISDICTIONS.map((currentJurisdiction) => ( <SelectOption id={`jurisdiction-${currentJurisdiction}`} key={currentJurisdiction} value={currentJurisdiction} > {currentJurisdiction} </SelectOption> ))} </Select> ); }
2. 测试断言逻辑错误
如果address是组件内部的状态,测试代码无法直接访问到这个内部变量,你直接断言address.jurisdiction拿到的只是初始值的引用,不会同步组件内部更新后的状态。
修复测试代码的两种方式:
方式一:断言DOM元素的选中值
直接查询下拉框的当前value来验证选择是否生效:
it('should update selected option and updated address jurisdiction when user makes a selection', async () => { render(<Address id="test-address" />); const jurisdictionDropDown = screen.getByRole('combobox'); const user = userEvent.setup(); const selectedJurisdiction = 'MA'; await user.selectOptions(jurisdictionDropDown, [selectedJurisdiction]); // 断言下拉框的当前值为MA expect(jurisdictionDropDown).toHaveValue(selectedJurisdiction); });
方式二:通过回调函数验证状态更新
如果你的Address组件是受控组件(通过props接收address和状态更新回调),可以模拟回调函数来验证:
it('should update selected option and updated address jurisdiction when user makes a selection', async () => { const mockOnAddressChange = jest.fn(); const initialAddress = { streetAddress: '', additionalStreetAddress: '', city: '', jurisdiction: '', zipCode: '' }; render(<Address id="test-address" address={initialAddress} onAddressChange={mockOnAddressChange} />); const jurisdictionDropDown = screen.getByRole('combobox'); const user = userEvent.setup(); const selectedJurisdiction = 'MA'; await user.selectOptions(jurisdictionDropDown, [selectedJurisdiction]); // 断言回调函数被调用,且参数包含正确的jurisdiction值 expect(mockOnAddressChange).toHaveBeenCalledWith(expect.objectContaining({ jurisdiction: selectedJurisdiction })); });
内容的提问来源于stack exchange,提问作者dulongj
相关产品推荐
相关产品推荐

