[英]Cypress wait for an element to be loaded inside a foor loop
我有一个数组,其中的项目是一堆按钮元素。 我想调用一个按钮,然后等待一个元素(在 dom 中)被加载。
加载该元素后,只有我想进入下一次迭代(单击下一个按钮/元素)
在我当前的实现中,一次单击所有按钮。 但我希望一次单击一个按钮。
cy.document().then(document => {
const arra = [...document.querySelectorAll('.instances__action')];
for (let i = 1; i <= arra.length; i++) {
let state = document.querySelector(
`#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody > tr:nth-child(${i}) > td:nth-child(3) > span`
).innerText;
document
.querySelector(
`#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody > tr:nth-child(${i}) > td:nth-child(7) > div > button.ant-btn.ant-btn-primary.ant-btn-sm`
)
.click();
cy.wait(2000);
cy.waitUntil(() => {
cy.get(
`#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody > tr:nth-child(${i +
1}) > td:nth-child(3) > span`
).contains('Finished');
});
}
});
});
@jmargolisvt 是正确的,如果您将 .click .click()
操作更改为 Cypress 命令,您应该获得正确的操作序列。
命令执行顺序和测试循环
可以这样想——上面的测试代码像普通的 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}`))
});
})
柏树日志
这就是 Cypress 日志的样子。
全部为绿色,并且只有在完成文本出现后才能看到点击。
控制台日志
这就是控制台日志的样子。
循环在命令队列开始之前执行到完成,但没关系,因为命令仍在以正确的顺序执行。
开始#0
开始#1
点击#0
断言#0
点击#1
断言#1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.