react-admin中SimpleForm输入合法内容后SaveButton仍禁用的测试问题
核心问题分析
自定义SaveCancelDeleteToolbar通过useFormContext获取的isValid状态在测试环境未更新,导致组件未重新渲染,SaveButton保持禁用。这通常是由于Form上下文不共享、测试DOM操作方式不当或校验规则未生效导致的。
解决方案步骤
1. 修复FormContextWrapper的上下文冲突
你自定义的FormContextWrapper如果自行创建了useForm实例,会覆盖react-admin SimpleForm内部的FormContext,导致Toolbar和表单无法共享同一表单状态。建议移除自定义Wrapper,直接使用react-admin提供的上下文:
// 测试文件中移除自定义FormContextWrapper const { user } = setup( <ValueList deleted={false} /> );
如果必须保留Wrapper(比如避免测试崩溃),确保它传递的是SimpleForm的上下文而非独立实例:
// 正确的FormContextWrapper实现(复用react-admin上下文) import { FormProvider } from 'react-hook-form'; import { FormContext as RaFormContext } from 'react-admin'; import { useContext } from 'react'; export const FormContextWrapper = ({ children, resource }) => { const formMethods = useContext(RaFormContext); return <FormProvider {...formMethods}>{children}</FormProvider>; };
2. 优化测试中的DOM元素获取方式
避免直接通过children层级获取输入框,改用testing-library的语义化查询方法,更稳定且符合测试最佳实践:
// 替换原有的输入框获取代码 const inputValue = screen.getByRole('textbox', { name: /resources.values.fields.value/i });
3. 简化用户输入操作
使用@testing-library/user-event的type方法,无需手动触发focus和blur,它会模拟真实用户的输入流程:
// 移除fireEvent.focus/blur,直接用user.type await user.type(inputValue, '1');
4. 校验自定义规则noEmptySpace的有效性
检查noEmptySpace校验函数是否正确处理了输入值'1',比如是否误判非空字符串为无效:
// 示例正确的noEmptySpace规则 const noEmptySpace = (value: string) => { if (!value.trim()) { return 'Value cannot be empty or whitespace'; } return undefined; };
5. 给SaveButton添加测试标识
为SaveButton添加data-testid,避免依赖文本查询的不确定性:
// Toolbar组件中修改SaveButton <SaveButton data-testid="save-button" disabled={!isValid} onClick={closeDrawer} /> // 测试中获取按钮 const saveButton = screen.getByTestId('save-button'); expect(saveButton).toBeDisabled(); // 初始状态 await user.type(inputValue, '1'); await waitFor(() => { expect(saveButton).not.toBeDisabled(); });
最终测试代码示例
it('should enable save button when valid input is entered', async () => { const { user } = setup(<ValueList deleted={false} />); // 打开SimpleForm的代码... // 初始状态校验 const saveButton = screen.getByTestId('save-button'); expect(saveButton).toBeDisabled(); const inputValue = screen.getByRole('textbox', { name: /resources.values.fields.value/i }); await user.type(inputValue, '1'); // 等待状态更新 await waitFor(() => { expect(saveButton).not.toBeDisabled(); }); });
内容的提问来源于stack exchange,提问作者Lucas PARISOT
相关产品推荐
相关产品推荐

