升级React18/Next.js13后Cypress点击测试突发失败
解决React 18 + Next.js 13升级后Cypress测试的DOM元素脱离问题
问题背景
项目升级React 18、Next.js 13后,开启React严格模式的开发环境下,Cypress测试持续抛出element has detached from the DOM错误,核心问题集中在MUI 5组件的交互上:
- 对话框内的MUI复选框执行
click()后无报错,但实际未选中,添加cy.wait()可临时生效但不优雅 - MUI Card组件的链接点击直接失败,添加等待后测试变得不稳定,还影响其他原本正常的测试
测试代码参考
// 测试代码 cy.getBySel('more-filters-button').click(); // 打开MUI对话框模态框 cy.get('input[name="condition"][value="New"]').click(); // 获取Checkbox组件并点击 cy.getBySel('save-filter-modal').click(); // 点击按钮关闭模态框 cy.getBySel('vehicle-card-link').first().click(); // 获取首个MUI Card并点击链接 cy.getBySel('vehicle-name').should('exist'); // 验证新页面的指定元素已加载 // commands.js 自定义命令 Cypress.Commands.add('getBySel', (selector, args, operator = '') => cy.get(`[data-cy${operator}=${selector}]`, { ...args }));
关键信息
- 仅升级分支出现问题,其他PR测试稳定无异常
- 仅部分MUI组件测试失败,同类型其他组件测试正常
- 疑似与React 18严格模式的双重渲染/卸载重挂载机制有关
解决方案
1. 确保操作最新DOM元素,避免缓存失效
React严格模式下组件会被卸载后重新挂载,Cypress之前获取的元素会直接失效。建议给MUI组件添加专属data-cy标记,每次操作前重新查询并验证元素状态:
// 给MUI Checkbox组件添加data-cy="condition-new-checkbox" cy.getBySel('more-filters-button').click(); // 先验证元素可见,确保获取最新DOM节点 cy.getBySel('condition-new-checkbox').should('be.visible').click(); cy.getBySel('save-filter-modal').click(); // Card链接点击:强制点击+前置状态验证 cy.getBySel('vehicle-card-link') .first() .should('be.visible') .click({ force: true }); // 强制点击可绕过部分DOM状态检测问题
2. 临时关闭React严格模式定位问题
在Next.js 13的next.config.js中关闭严格模式,验证是否为双重渲染导致的问题:
module.exports = { reactStrictMode: false, };
注意:此方法仅用于调试定位,生产环境建议保持严格模式以检测潜在问题。
3. 使用真实浏览器点击替代模拟事件
Cypress原生click()是模拟DOM事件,对React重渲染后的元素兼容性较差。可以使用cypress-real-events插件触发真实浏览器点击:
- 安装插件:
npm install cypress-real-events --save-dev
- 在
cypress/support/e2e.js中导入:
import 'cypress-real-events/support';
- 修改测试代码:
cy.get('input[name="condition"][value="New"]').realClick(); cy.getBySel('vehicle-card-link').first().realClick();
4. 等待组件状态稳定后再操作
针对模态框关闭后的DOM更新,等待列表重新渲染完成再执行后续操作:
cy.getBySel('save-filter-modal').click(); // 等待筛选后的车辆列表加载完成(根据实际业务调整断言) cy.getBySel('vehicle-card-link').should('have.length.greaterThan', 0).first().click();
原理说明
React 18严格模式在开发环境下会双重执行组件挂载、更新逻辑,并主动卸载后重新挂载组件,导致Cypress缓存的DOM节点被标记为“脱离DOM”。此时需要确保每次操作前获取最新的DOM节点,或使用更贴近真实用户交互的事件触发方式。
内容的提问来源于stack exchange,提问作者Tarush Roy
相关产品推荐
相关产品推荐

