赛普拉斯:使用 for 循环的异步函数给出相同的结果

Cypress: Async function using for loop giving same results

我是 cypress 框架的新手,正在尝试使用 cypress 实现以下功能。

我有一个包含 table 行的页面,页眉上有一个下拉菜单。选择该选项后,下拉菜单将关闭,正文内容将根据所选菜单选项 changed/loaded 向上显示。

问题:尽管选项的 table 行计数不同,但顺序选择的所有菜单选项的 table 行的长度相同。

这是我的代码:

it.only('Validate table Row changed length on menu option selection', {defaultCommandTimeout: 10000}, () => {
  // opening the dropdown menu
  page.openDropdownMenu();
  // getting the dropdown options and calculating the length
  cy.get('dropdownOptions').then($options => {
    // calculating the length
    const menuOptionCount = $options.length;
    // closing the dropdown menu
    page.closeDropdownMenu();
    for (let i = 0; i < menuOptionCount; i++) {
      // opening the dropdown menu
      page.openDropdownMenu();
      // clicking the menu option
      $options[i].click();
      // closing the dropdown menu
      page.closeDropdownMenu();
      cy.get("body").then($body => {
        // always getting the same length for the table rows for all selected options
        const rowsLength = $body.find('.table.rows').length;
        cy.log('****************Rows length************', rowsLength);
      });
    }
  });
});

有没有办法在不使用任何外部实用程序的情况下将异步语句写入同步语句(承诺中的等待异步)。正如我之前使用 Protractor 的作业一样,同样的事情可以使用 async await 处理,如下所示。

const elementCount = await element(
  by.css('[title="Locked By"] .med-filter-header-button div')
).count();

您可以将代码压缩成这样的形式。不要使用 for 循环,而是使用 each,这是一种赛普拉斯内置的循环方法。

it.only(
  'Validate table Row changed length on menu option selection',
  {defaultCommandTimeout: 10000},
  () => {
    page.openDropdownMenu()
    cy.get('dropdownOptions').each(($options, index) => {
      cy.wrap($options).eq(index).click()
      page.closeDropdownMenu()
      cy.get('.table.rows')
        .its('length')
        .then((rowsLength) => {
          cy.log('****************Rows length************', rowsLength)
        })
      page.openDropdownMenu()
    })
    page.closeDropdownMenu()
  }
)

click() 之后,应用程序重写了 table,但 Cypress 不知道发生了什么,并在更改发生之前获取了行数。

TLDR - 您需要正确地给赛普拉斯更多信息测试。一般来说,你的测试数据应该是已知的(而不是被测试代码“发现”)。


问题#1

您需要一些方法来等待行更改完成。要么更改某些文本元素(可能是第一行文本),要么在实际行数上添加 .should()

类似

const expectedRowCount = [5, 4, 3, 2]

cy.get('dropdownOptions').each(($option, index) => {

  page.openDropdownMenu()
  $option.click()
  page.closeDropdownMenu()

  cy.get('.table.rows')
    .should('have.length', expectedRowCount[index])  // this will retry until rowsLength changes
    .then(rowsLength => {
      cy.log('****************Rows length************', rowsLength)
    })
})

问题#2

如果”正文内容得到changed/loaded”表示下拉 每次点击都会被重写,然后循环将失败,因为 $options 每次都会刷新。

您可以使用 expectedRowCount 来循环播放

const expectedRowCount = [5, 4, 3, 2]

expectedRowCount.forEach((expectedCount, index) => {

  page.openDropdownMenu()
  cy.get('dropdownOptions').eq(index).click()
  page.closeDropdownMenu()

  cy.get('.table.rows')
    .should('have.length', expectedCount)  // retries until rowsLength changes
    .then(rowsLength => {
      cy.log('****************Rows length************', rowsLength)
    })
})

以上策略并不能真正给你最坚实的考验。

如果可以的话,检查一些每次迭代都会改变的文本,

page.openDropdownMenu()
cy.get('dropdownOptions').then($options => {

  let firstRowText = '';   // to control the loop, waiting for this to change

  const menuOptionCount = $options.length;
  page.closeDropdownMenu();
  for (let i = 0; i < menuOptionCount; i++) {
  
    page.openDropdownMenu();
    cy.get('dropdownOptions').eq(i).click();  // fresh query each time through the loop

    page.closeDropdownMenu();

    cy.get('.table.rows').first().invoke('text')
      .should('not.eq', firstRowText);            // retry until text has changed
      .then(newText => firstRowText = newText);   // save for next loop

    cy.get('.table.rows').then($rows => {
      const rowsLength = $rows.length;
      cy.log('****************Rows length************', rowsLength);
    });
  }
})