表单提交聚焦首个错误字段时Vendor.js报charAt未定义错误排查
解决方案:表单聚焦错误字段测试报错「Cannot read property 'charAt' of undefined」
核心问题分析
手动测试正常但测试用例报错,核心原因是异步逻辑的竞态条件或DOM元素状态不一致:测试环境中代码执行顺序、DOM生命周期和手动操作存在差异,触发了polyfill中未被覆盖的边界情况。
具体修复步骤
- 替换原生setTimeout为Ember运行循环方法
原生setTimeout脱离Ember运行循环,测试时可能出现DOM元素已销毁但仍执行focus的情况。改用Ember的run.later确保逻辑在框架生命周期内执行:
import { run } from '@ember/runloop'; focusFirstErrorInForm(element) { const parentForm = this.gettingParticularForm(element); if (parentForm) { // 替换原生setTimeout run.later(() => { const errorContainer = this.gettingErrorContainer(parentForm); if (errorContainer && errorContainer.length > 0) { let firstInput = this.gettingFirstErrorFromContainer(errorContainer); // 修正判断逻辑 if (firstInput) { // 额外检查元素是否仍在DOM中 if (document.contains(firstInput)) { firstInput.focus(); } } } else { this.getErrorKcContainer(parentForm); } }, 100); } }
修正firstInput的判断逻辑
原代码if (firstInput !== null || firstInput !== undefined)逻辑错误——无论firstInput是null还是undefined,条件永远为真,会导致对不存在的元素调用focus(),触发polyfill报错。改成if (firstInput)即可同时排除null和undefined。测试用例中等待错误元素渲染完成
在测试用例里,确保错误元素已经渲染后再执行断言或触发后续逻辑,避免竞态:
// 示例测试代码 test('更新提交后聚焦首个错误字段', async function(assert) { // 模拟表单提交触发错误 await this.fillIn('input[name="field"]', '无效值'); await this.click('button[type="submit"]'); // 等待错误元素出现 await this.waitFor('.error-container .error-input'); // 断言聚焦状态 const focusedElement = document.activeElement; assert.ok(focusedElement.classList.contains('error-input')); });
- 调整Mirage响应时机
确保Mirage返回错误响应的时机和真实场景一致,避免表单还未完成错误渲染就执行focus逻辑。可以在Mirage路由中添加微小延迟模拟真实网络情况:
// mirage/config.js this.post('/api/forms', function(schema, request) { // 模拟延迟,确保表单有足够时间处理状态 return new Promise(resolve => { setTimeout(() => { resolve(new Response(400, {}, { errors: [...] })); }, 50); }); });
内容的提问来源于stack exchange,提问作者Himanshu Javiya
相关产品推荐
相关产品推荐

