@jmargolisvt 是正确的,如果您将.click() 操作更改为赛普拉斯命令,您应该得到正确的操作顺序。
命令执行顺序和测试循环
可以这样想——上面的测试代码像普通的javascript一样运行,每个cy.X()命令都会将一个命令放入队列中。命令保证按队列顺序顺序运行,但不与测试代码同步。
所以,cy.wait(2000) 并没有减慢 for 循环,而是暂停了队列执行。
等待断言
还要注意,命令具有内置的等待断言,因此在这种情况下您可能不需要cy.wait() 或cy.waitUntil()。您可以使用timeout 选项控制最大等待时间。
循环
如果您将内部部分转换为命令,for 循环将正常工作,但您也可以将循环本身转换为 IMO 更简洁的 cy.get().each() 命令。
测试异步内容
最后,在等待异步内容时,首选cy.contains('mySelector', 'myContent') 命令而不是cy.get('mySelector').contains('myContent') 命令。
原因是cy.get('mySelector').contains('myContent') 只等待元素mySelector,但它已经在DOM 中。如果内容是异步变化的,这个命令会立即测试旧的内容(假设为空)并且测试失败。
const tbodySelector = '#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody';
const buttonSelector = 'td:nth-child(7) > div > button.ant-btn.ant-btn-primary.ant-btn-sm';
const spanSelector = 'td:nth-child(3) > span'
cy.get('.instances__action').each(($el, i) => {
cy.get(`${tbodySelector} > tr:nth-child(${i+1}) > ${buttonSelector}`)
.click();
cy.contains(
`${tbodySelector} > tr:nth-child(${i+1}) > ${spanSelector}`,
'Finished',
{ timeout: 2000 } // increase timeout if a longer wait is required
);
});
注意 jQuery 的 :nth-child(index) 选择器从索引 1 开始,但 .each(($el, i) => 具有从零开始的索引,因此必须在这些选择器中使用 i+1。
这是我用来测试的模拟 DOM。在一个干净的 Cypress 项目中,将其放入文件夹 <project root>/app。
<table>
<tbody>
<tr class="instances__action">
<td>
<button id="myBtn1"></button>
</td>
<td>
<span id="mySpan1"></span>
</td>
</tr>
<tr class="instances__action">
<td>
<button id="myBtn2"></button>
</td>
<td>
<span id="mySpan2"></span>
</td>
</tr>
</tbody>
</table>
<script>
document.getElementById("myBtn1").addEventListener("click", function() {
setTimeout(() => {
document.getElementById("mySpan1").innerHTML = "Finished";
}, 1000)
});
document.getElementById("myBtn2").addEventListener("click", function() {
setTimeout(() => {
document.getElementById("mySpan2").innerHTML = "Finished";
}, 500)
});
</script>
注意上面的嵌套是简化的,所以我适当地改变了选择器内容。
测试上面的 HTML 片段
it('clicks buttons and waits for finished flag', () => {
cy.visit('app/iterate-table-buttons.html')
const tbodySelector = 'tbody';
const buttonSelector = 'td:nth-child(1) > button';
const spanSelector = 'td:nth-child(2) > span'
cy.get('.instances__action').each(($el, i) => {
console.log(`starting #${i}`)
cy.get(`${tbodySelector} > tr:nth-child(${i+1}) > ${buttonSelector}`)
.then(() => console.log(`clicking #${i}`))
.click();
cy.contains(
`${tbodySelector} > tr:nth-child(${i+1}) > ${spanSelector}`,
'Finished',
{ timeout: 2000 } // increase timeout if a longer wait is required
)
.then(() => console.log(`asserting #${i}`))
});
})
赛普拉斯日志
这就是赛普拉斯日志的样子。
全部为绿色,并且只有在 Finished 文本出现后才能看到点击。
- 访问 app/iterate-table-buttons.html
- GET .instances__action
- 获取 tbody > tr:nth-child(1) > td:nth-child(1) > 按钮
- 点击
- 包含 tbody > tr:nth-child(1) > td:nth-child(2) > span,已完成
- 获取 tbody > tr:nth-child(2) > td:nth-child(1) > 按钮
- 点击
- 包含 tbody > tr:nth-child(2) > td:nth-child(2) > span,已完成
控制台日志
这就是控制台日志的样子。
循环在命令队列开始之前执行完成,但这没关系,因为命令仍在以正确的顺序执行。
从#0开始
开始 #1
点击 #0
断言 #0
点击 #1
断言 #1