Cypress中动态DOM重渲染场景下重复测试逻辑的正确方法
问题:Cypress测试React表格批量删除时DOM重渲染导致失败
测试React应用的表格所有项删除功能时,删除操作会触发DOM重渲染,DOM结构如下:
<table> <tr><td>Item 1</td><td><button>Delete</button></td></tr> <tr><td>Item 2</td><td><button>Delete</button></td></tr> <tr><td>Item 3</td><td><button>Delete</button></td></tr> /* ... */ </table>
尝试了以下代码:
cy.get('table tr').each(($row) => { cy.wrap($row).find('button').click() });
但运行失败,报错信息:
Timed out retrying after 15000ms: cy.find() failed because the page updated as a result of this command, but you tried to continue the command chain. The subject is no longer attached to the DOM, and Cypress cannot requery the page after commands such as cy.find().
请问在Cypress中处理此类问题的惯用方法是什么?
解决方案
方法1:递归删除第一个元素
每次只操作当前DOM中存在的第一行删除按钮,直到没有行剩余。这种方式避免了操作已失效的DOM节点:
const deleteFirstRow = () => { cy.get('table tr').first().then(($row) => { if ($row.length) { cy.wrap($row).find('button').click(); // 等待DOM更新后继续执行递归 deleteFirstRow(); } }); }; deleteFirstRow();
方法2:基于初始行数循环删除
先获取表格初始行数,然后循环对应次数,每次都重新查询最新的DOM元素:
cy.get('table tr').then(($rows) => { const totalRows = $rows.length; for (let i = 0; i < totalRows; i++) { // 每次重新查询,确保操作的是当前DOM中存在的元素 cy.get('table tr').eq(0).find('button').click(); // 可选:添加断言等待DOM稳定,验证行数减少 cy.get('table tr').should('have.length', totalRows - i - 1); } });
方法3:使用Cypress工具函数循环
借助Cypress内置的_.times函数,结合每次重新查询DOM实现批量删除:
cy.get('table tr').its('length').then((count) => { Cypress._.times(count, () => { cy.get('table tr').first().find('button').click(); }); });
原代码失败原因
原代码中cy.get('table tr').each()会一次性获取所有行的DOM集合,当删除第一行后,React触发DOM重渲染,后续的行节点已被从DOM中移除(列表重新渲染后原节点被替换),此时操作这些已失效的元素就会触发报错。
内容的提问来源于stack exchange,提问作者Nikolai Mavrenkov
相关产品推荐
相关产品推荐

