React测试中无法修改<input type="date">值的问题求助
日期输入框测试无法修改值的问题解决
我尝试了多种方法与日期输入框交互,但均未成功。有时默认日期保持不变,有时会变成空字符串,始终无法将值修改为新日期。
尝试过的方法
- 使用
fireEvent.change:
const startDate = screen.getByLabelText('from'); act(() => { fireEvent.change(startDate, {target: {value: '2019-10-08'}}); });
操作后值变为空字符串。
- 使用
userEvent.type(v13.5.2):
act(() => { userEvent.type(startDate, '08102019'); // 以及带横杠、斜杠或年份在前的所有变体 });
此操作对值无影响。
- 使用最新版
userEvent(v14+):
const user = userEvent.setup(); await act(async () => { await user.type(startDate, '08102019'); });
操作仍无效果。
- 其他尝试:
fireEvent点击、userEvent点击、userEvent.keyboard等组合,均无效。
复现代码
DateComp.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; import DateComp from './DateComp'; import '@testing-library/jest-dom'; test('changing date value works', async () => { render(<DateInput onChange={()=>{return;}} className="" />); const startDate = screen.getByLabelText('from'); const endDate = screen.getByLabelText('to'); act(() => { fireEvent.change(startDate, {target: {value: '2019-10-08'}}); }); act(() => { fireEvent.change(endDate, {target: {value: '2020-10-08'}}); }); expect(startDate.getAttribute('value')).toEqual('2019-10-08'); expect(endDate.getAttribute('value')).toEqual('2020-10-08'); });
DateComp.tsx
import { useState, useEffect } from 'react'; interface IProps { onChange: CallableFunction, className: string, } const DateComp = ({ onChange, className }: IProps): JSX.Element => { // Default dates const dateFrom = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().substring(0, 10); // 7 days ago const dateTo = new Date().toISOString().substring(0, 10); // today const [selectedFrom, setSelectedFrom] = useState(dateFrom); const [selectedTo, setSelectedTo] = useState(dateTo); const handleFrom = (e: React.ChangeEvent<HTMLInputElement>) => { setSelectedFrom(e.target.value); }; const handleTo = (e: React.ChangeEvent<HTMLInputElement>) => { setSelectedTo(e.target.value); }; return ( <div className={className}> <label htmlFor='date_inputs'>Period</label> <div id='date_inputs' className='date-inputs'> <label htmlFor='date_from' className='screen-reader-only'>from</label> <input id='date_from' type='date' defaultValue={dateFrom} onChange={handleFrom} /> <label htmlFor='date_to'>to</label> <input id='date_to' type='date' defaultValue={dateTo} onChange={handleTo} /> </div> </div> ); }; export default DateComp;
package.json
{ ..., "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "./node_modules/.bin/react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, ..., "devDependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^14.4.3", "@types/jest": "^27.5.2", "@types/node": "^16.18.24", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "msw": "^1.2.3", "react-scripts": "5.0.1" }, "jest": { "transformIgnorePatterns": [ "node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)" ] } }
问题原因及解决办法
1. 输入框未绑定状态值
你的input标签使用了defaultValue,但未将value属性绑定到selectedFrom/selectedTo状态,导致状态更新后输入框显示值不同步。修改DateComp.tsx中的输入框:
<input id='date_from' type='date' value={selectedFrom} onChange={handleFrom} /> <input id='date_to' type='date' value={selectedTo} onChange={handleTo} />
去掉defaultValue,改用value绑定状态,确保输入框与状态同步。
2. 测试组件名称错误
测试代码中渲染的<DateInput />是错误的,实际组件是DateComp,修正为:
render(<DateComp onChange={()=>{}} className="" />);
3. 测试断言方式错误
对于受控组件,应通过screen.getByDisplayValue断言,而非getAttribute('value')。修改测试断言:
expect(screen.getByDisplayValue('2019-10-08')).toBeInTheDocument(); expect(screen.getByDisplayValue('2020-10-08')).toBeInTheDocument();
4. React 18+测试代码优化
React 18中render和fireEvent已自动包裹在act中,无需手动调用,简化后的测试代码:
test('changing date value works', async () => { render(<DateComp onChange={()=>{}} className="" />); const startDate = screen.getByLabelText('from'); const endDate = screen.getByLabelText('to'); fireEvent.change(startDate, {target: {value: '2019-10-08'}}); fireEvent.change(endDate, {target: {value: '2020-10-08'}}); expect(screen.getByDisplayValue('2019-10-08')).toBeInTheDocument(); expect(screen.getByDisplayValue('2020-10-08')).toBeInTheDocument(); });
5. userEvent正确使用方式
使用userEvent时需传入ISO格式日期字符串,先清空输入框再输入:
test('changing date value with userEvent', async () => { const user = userEvent.setup(); render(<DateComp onChange={()=>{}} className="" />); const startDate = screen.getByLabelText('from'); await user.clear(startDate); await user.type(startDate, '2019-10-08'); expect(screen.getByDisplayValue('2019-10-08')).toBeInTheDocument(); });
内容的提问来源于stack exchange,提问作者Matthias
相关产品推荐
相关产品推荐

