Cypress 分页处理

Cypress pagination handling

提问人:automation-ninja 提问时间:10/30/2023 最后编辑:automation-ninja 更新时间:10/31/2023 访问量:78

问:

我想首先获取当前页面上完整元素列表的 #product_list,然后找到此列表中的每个元素 如果元素 .ajax_block_product.col-xs-12.col-sm-4.col-md-3[data-id-product='22578'] 在第一页中,请单击它,否则单击页面底部的 #pagination_next_bottom 按钮,然后在其他页面中再次搜索以查找 #product_list 元素中存在的元素

我尝试使用此功能,但它只找到每个页面并在不单击所需元素的情况下进行导航。

// findItem("Printer Brother MFP Laser HL1222WEYJ1");

      // function findItem(value) {
      //   let found = false;
      //   let attempts = 0;
      //   const maxAttempts = 20; // Define a maximum number of attempts
      
      //   function clickNext() {
      //     cy.get("#pagination_next_bottom").click()
      //     cy.wait(5000);
      //   }
      
      //   function findInPage() {
      //     if (found || attempts >= maxAttempts) {
      //       return; // If item found or max attempts reached, exit
      //     }
      
      //     cy.get("#product_list li div.produkti h5").each(itemNameEl => {
      //       const itemText = itemNameEl.text();
      //       console.log(itemText);
      //       if (itemText === value) {
      //         found = true;
      //         cy.get(itemNameEl).should('be.visible').click(); // Click the parent element of the product
      //         return false;
      //       }
      //     });
      
      //     if (!found) {
      //       clickNext(); // Click the "Next" button
      //       attempts++; // Increment attempts
      //       findInPage(); // Continue searching on the next page
      //     }
      //   }
      
      //   findInPage();
      // }
JavaScript 方法 分页 自动测试 Cypress

评论


答:

0赞 agoff 10/30/2023 #1

代码中的问题是,检查是否找到对象的行 () 是同步的,并且在 Cypress 执行(异步)之前运行,并可能更新 的值。因为您是在同步函数中执行 Cypress 命令,所以我建议使用 Cypress 自定义命令来处理您的递归。if (!found)found

Cypress.Commands.add("findItem", (value, attempt) => {
  let currAttempt = attempt ?? 0;
  const maxAttempts = 20;

  if (attempt < maxAttempts) {
    let found = false;
    cy.get("#product_list li div.produkti h5")
      .each(($item) => {
        const itemText = $item.text();
        console.log(itemText);
        if (itemText === value) {
          found = true;
          return false;
        }
      })
      .then(() => {
        if (!found) {
          cy.get("#pagination_next_bottom").click();
          cy.wait(5000);
          cy.findItem(value, currAttempt++);
        } else {
          cy.wrap($item).should("be.visible").click(); // Click the parent element of the product
        }
      });
  } else {
    expect(true === false); // placeholder assertion to fail if too many attempts are made
  }
});

此外,将行移动到块可以使块完全同步,并且不会与任何 Cypress 命令竞争执行时间。cy.wrap($item)....then().each()

2赞 Big Mo 10/31/2023 #2

有两件事可能是问题(因为没有发生点击)

  • itemText === value这可能需要不精确匹配,例如由于空格字符itemText.includes(value)

  • cy.get('itemNameEl')也许需要,虽然我不相信这一点cy.wrap('itemNameEl')

2赞 TesterDick 10/31/2023 #3

递归代码看起来不错,但请记住 Cypress 命令是异步的,因此您需要等待它们完成,然后再进行 .get/eachif (!found)

这适用于两个地方

  • 之前if (!found)clickNext()
  • 在顶部if (found || attempts >= maxAttempts)

您不需要,只需检查变量并允许函数删除并完成(如果已设置)。returnfoundfound

用包装器做这两件事。cy.then()

let found = false;
let attempts = 0;
const maxAttempts = 20;

function clickNext() {
  cy.get("#pagination_next_bottom").click()
  cy.get("#product_list li div.produkti h5", {timeout:5000})
    .should('have.length.gt', 0) 
}

function findInPage() {

  cy.then(() => {         // to exit when found wrap this check 

    if (!found && attempts < maxAttempts) {
      cy.get("#product_list li div.produkti h5").each(itemNameEl => {
        if (itemNameEl.text() === value) {
          found = true;
          cy.get(itemNameEl)
            .parent()                         // NOTE <h5> parent
            .should('be.visible').click(); 
          return false;
        }
      })

      cy.then(() => { // wrap this check to allow get/each to complete
        if (!found) {
          clickNext();
          attempts++; 
          findInPage(); 
        }
      })
    }
  })
}

您可以将 替换为检查页数,或者检查页码元素。cy.wait(5000)cy.get("#product_list li div.produkti h5").should('have.length.gt', 0)

Timeout 总是比 好。cy.wait()


也许还可以为找到的元素添加别名,并在搜索完成后单击它。

通常,应尝试将查询代码与操作代码分开,因为操作可能会更改 DOM 并使已运行的查询无效。

function findInPage(value) {
 ...
      if (itemText === value) {
        found = true;
        cy.get(itemNameEl).parent().as('product')
}

findInPage();

cy.get('@product').should('be.visible').click()
3赞 Aladin Spaz 10/31/2023 #4

如果您对递归感到有点沮丧,请尝试使用 cypress-recurse 插件。

最简单的代码如下:

const itemsSelector = '#product_list li div.produkti'  // leaving off h5
const nextPageSelector = '#pagination_next_bottom'
const value = 'Printer Brother MFP Laser HL1222WEYJ1'

recurse(
  () => cy.get(itemsSelector),
  (items) => expect(items).to.contain(value),
  {
    post: () => cy.get(nextPageSelector).click()
  }
)
.contains(value)   // filter down to one item
.click()

笔记:

  • 这个 recurse() 返回页面上的所有项目,所以用.contains()
  • 它之所以有效,是因为您的值非常独特,但如果它可以部分出现在其他项目中,则必须使用expect(items).to.contain(value).each()