Javascript Cypress等待在foor循环中加载元素

Javascript Cypress等待在foor循环中加载元素,javascript,for-loop,cypress,browser-automation,ui-testing,Javascript,For Loop,Cypress,Browser Automation,Ui Testing,我有一个数组,其中的项目是一堆按钮元素。我想调用一个按钮,然后等待一个元素(在dom中)被加载 加载该元素后,只有我想转到下一个迭代(单击next按钮/元素) 在我当前的实现中,一次单击所有按钮。但我希望一次只能点击一个按钮 cy.document().then(document => { const arra = [...document.querySelectorAll('.instances__action')]; for (let i = 1; i &

我有一个数组,其中的项目是一堆按钮元素。我想调用一个按钮,然后等待一个元素(在dom中)被加载

加载该元素后,只有我想转到下一个迭代(单击next按钮/元素)

在我当前的实现中,一次单击所有按钮。但我希望一次只能点击一个按钮

  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');
        });
      }
    });
  });
cy.document().then(document=>{
const arra=[…document.querySelectorAll('.instances\uu action');
对于(设i=1;i section>section>main>div>div>section.instances>div>div>div>div>table>tbody>tr:n子项(${i})>td:n子项(3)>span`
).内部文本;
文件
.查询选择器(
`#root>section>section>main>div>div>section.instances>div>div>div>div>table>tbody>tr:nth child(${i})>td:nth child(7)>div>button.ant-btn.ant-btn-primary.ant-btn-sm`
)
。单击();
cy.wait(2000);
cy.waitill(()=>{
赛格(
`#root>section>section>main>div>div>section.instances>div>div>div>div>table>tbody>tr:n个子(${i+
1} )>td:n个孩子(3)>span`
).包含(“完成”);
});
}
});
});

@jmargolisvt是正确的,如果将
.click()
操作更改为Cypress命令,则应获得正确的操作顺序

命令执行顺序和测试循环

可以这样想-上面的测试代码作为普通javascript运行,每个
cy.X()
命令将一个命令放入队列。命令保证按队列顺序顺序运行,但不能与测试代码同步运行

因此,
cy.wait(2000)
并没有减慢for循环,而是暂停队列执行

等待断言

还要注意,命令具有内置的等待断言功能,因此在这种情况下,您可能不需要使用
cy.wait()
cy.waitUntil()
。您可以使用
超时
选项控制等待的最长时间

循环

如果将内部部分转换为命令,for循环将正常工作,但也可以将循环本身转换为IMO更整洁的命令

测试异步内容

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}`))

  });
})
最后,在等待异步内容时,首选
cy.contains('mySelector','myContent')
命令,而不是
cy.get('mySelector')。contains('myContent')
命令

原因是
cy.get('mySelector')。contains('myContent')
只等待元素
mySelector
,但它已经在DOM中。如果内容正在异步更改,此命令将立即测试旧内容(假定为空),并使测试失败

consttbodyselector='#root>section>section>main>div>div>section.instances>div>div>div>div>div>table>tbody';
const buttonSelector='td:n子级(7)>div>button.ant btn.ant btn primary.ant btn sm';
常量span选择器='td:n子项(3)>span'
cy.get('.instances\uu action')。每个($el,i)=>{
cy.get(`${tbodySelector}>tr:n个子(${i+1})>${buttonSelector}`)
。单击();
赛昂(
`${tbodySelector}>tr:n个子(${i+1})>${spanSelector}`,
"完成",,
{timeout:2000}//如果需要更长的等待时间,请增加超时时间
);  
});

注意jQuery的
:第n个子(索引)
选择器从索引1开始,但是
。每个($el,i)=>
都有零基索引,因此必须在这些选择器中使用
i+1


这是我用来测试的模拟DOM。在一个干净的Cypress项目中,将它放在文件夹
/app


document.getElementById(“myBtn1”).addEventListener(“单击”,函数(){
设置超时(()=>{
document.getElementById(“mySpan1”).innerHTML=“完成”;
}, 1000)
});
document.getElementById(“myBtn2”).addEventListener(“单击”,函数(){
设置超时(()=>{
document.getElementById(“mySpan2”).innerHTML=“完成”;
}, 500)
});
注意,上面的嵌套简化了,因此我适当地更改了选择器contants

测试上述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}`))

  });
})
柏树原木

这就是柏树原木的样子。
全部为绿色,只有在显示完成的文本后才能看到单击

  • 访问app/iterate-table-buttons.html
  • GET.instances\u操作
  • 获取tbody>tr:n个孩子(1)>td:n个孩子(1)>按钮
  • 点击
  • 包含tbody>tr:n子项(1)>td:n子项(2)>span,已完成
  • 获取tbody>tr:n个孩子(2)>td:n个孩子(1)>按钮
  • 点击
  • 包含tbody>tr:n子项(2)>td:n子项(2)>span,已完成
  • 控制台日志

    这就是控制台日志的样子

    循环在命令队列开始之前执行到完成,但这没关系,因为命令仍然以正确的顺序执行

    开始#0
    开始#1
    点击#0
    断言#0
    单击#1

    断言#1

    @jmargolisvt是正确的,如果将
    .click()
    操作更改为Cypress命令,则应该获得正确的操作顺序

    命令执行顺序和测试循环

    可以这样想-上面的测试代码作为普通javascript运行,每个
    cy.X()
    命令将一个命令放入队列。命令保证按队列顺序运行,但不同步