javascript - 如何从 Cypress 的测试文件中抽象出公共(public)功能

标签 javascript async-await e2e-testing cypress testcafe

我刚刚从 TestCafe 迁移到 Cypress,但找不到抽象常用方法的解决方案。在下面的示例中,cy.document().then(doc).. 使用了两次,但是我相信这些类型的函数必须抽象为可重用函数。

it('Test the input text field and submit button list the basket items', () => {
const allNameBeforeInput = []
const allNameAfterInput = []
cy.document().then((doc) => {
    const elements = doc.querySelector('#items').querySelectorAll('.row-style > :nth-child(1)')
    for (let i = 0; i <= elements.length - 1; i++) {
        const basketName = elements[i].textContent
        if (basketName && basketName !== '') {
            allNameBeforeInput.push(`${basketName}`)
        }
        console.log(allNameBeforeInput.length) //this gives 0
    }
})
cy.get(basket.itemInputField)
    .type('Suraj')
cy.get(basket.submitInputButtonField)
    .click()
cy.get(basket.itemInputField)
    .type('Suraj')
cy.get(basket.submitInputButtonField)
    .click()
cy.get(basket.itemInputField)
    .type('Suraj')
cy.get(basket.submitInputButtonField)
    .click()
cy.get('#items').children('.row-style').children('.list-item')
    .contains('Suraj')
cy.document().then((doc) => {
    const elements = doc.querySelector('#items').querySelectorAll('.row-style > :nth-child(1)')
    for (let i = 0; i <= elements.length - 1; i++) {
        const basketName = elements[i].textContent
        if (basketName && basketName !== '') {
            allNameAfterInput.push(`${basketName}`)
        }
    }
    console.log(allNameAfterInput.length) //this gives 3 
    expect(allNameBeforeInput.length).equal(0)
    expect(allNameAfterInput.length).equal(3)
    expect(allNameBeforeInput.length).is.lt(allNameAfterInput.length)
})

})

这就是我想通过 Basket 类实现的目标:

getAllBasketName() {
    cy.document().then((doc) => {
        const allName = []
        const elements = doc.querySelector('#items').querySelectorAll('.row-style > :nth-child(1)')
        for (let i = 0; i <= elements.length - 1; i++) {
            const basketName = elements[i].textContent
            if (basketName && basketName !== '') {
                allName.push(`${basketName}`)
            }
        }
        return allName
    })
}

现在我应该可以使用

    const getAllBasketNamesBefore = basket.getAllBasketName()
cy.get(basket.itemInputField)
        .type('Suraj')
    cy.get(basket.submitInputButtonField)
        .click()
    cy.get(basket.itemInputField)
        .type('Suraj')
    cy.get(basket.submitInputButtonField)
        .click()
    cy.get(basket.itemInputField)
        .type('Suraj')
    cy.get(basket.submitInputButtonField)
        .click()
    const getAllBasketNamesAfter = basket.getAllBasketName()
{Assertion goes here}

这不起作用,因为 async/await 未处理,因此 before 和 after 的值始终为 0。任何线索或帮助将不胜感激。

最佳答案

您使用的方法不是 cypress 推荐的,并且被认为是反模式。 https://docs.cypress.io/guides/references/best-practices.html#Assigning-Return-Values

Cypress 建议您添加自定义命令。 https://docs.cypress.io/api/cypress-api/custom-commands.html#Syntax

在最初创建的文件夹结构中,commands.js 文件可以在 support 文件夹下找到。在这里,您可以创建一个命令来封装您希望重用的逻辑。根据代码的 console.log 部分,我假设这是在命令行上运行的。有针对控制台以及 UI 中使用的自定义命令。

对于该部分,您可能需要添加此自定义命令

// not a super useful custom command
// but demonstrates how subject is passed
// and how the arguments are shifted
Cypress.Commands.add('console', {
  prevSubject: true
}, (subject, method) => {
  // the previous subject is automatically received
  // and the commands arguments are shifted

  // allow us to change the console method used
  method = method || 'log'

  // log the subject to the console
  console[method]('The subject is', subject)

  // whatever we return becomes the new subject
  //
  // we don't want to change the subject so
  // we return whatever was passed in
  return subject
})

对于其他功能,创建命令非常简单,基本模式是:

Cypress.Commands.add(名称,callbackFn)

所以你可以创建类似的东西

Cypress.Commands.add(allNameBeforeInput, (options, options) => {
 //custom logic goes here

})

然后您可以通过调用 cy.allNameBeforeInput(options, options) 来使用它。

例如,我在登录方面遇到了困难,我的所有测试都具有通过 UI 登录的登录功能,但我想在正确的页面而不是登录页面上开始测试。我将其添加到支持文件夹中的 command.js 文件中:

Cypress.Commands.add('login',(username="<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8de3e2f9fee5ecffe4e3eae0f4f8fee8ffe3ece0cdfef9eceee6e8f5eee5ece3eae8a3eee2e0" rel="noreferrer noopener nofollow">[email protected]</a>", 
password="somesecurepasswordshhh") => {
 cy.request({
   method: "POST",
   url: "/api/public/login",
   body: `{:person/email "${username}", :person/password "${password}"}`,
   headers: {
     "Accept": "application/edn",
     "Content-Type": "application/edn"
   }
 })
})

现在我可以在测试开始时添加 cy.login 和 beforeEach 函数。在每个命令之前向服务器发出请求并等待登录请求和 cy.login 自定义命令,以确保我可以仅通过一个 cy 命令使用该捆绑逻辑。

describe('Test suite for page traverse', () => {
    beforeEach(() => {
        cy.server()
        cy.route("POST","/api/graphql").as("graphql")
        Cypress.Cookies.preserveOnce("company_jwt_qa") 
    })

     it('traverses all subnav items', () => {
        cy.login()
            cy.visit('/index.html')
            cy.wait("@graphql")
        cy.get('[data-tag-component="subnav-group"]')
            cy.get('[data-tag-component="subnav-title"]').eq(1).click()


    })
 })

关于javascript - 如何从 Cypress 的测试文件中抽象出公共(public)功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52754690/

相关文章:

c# - 对正确使用 Async/Await 的困惑

testing - 如何减慢 TestCafe 中的测试执行速度?

javascript - Cypress 如何获取文本长度

javascript - 在 php 中使用 GET 时要包含的 Bootstrap-select 下拉选项

javascript - 固定元素在 WKWebkit 上移动

javascript - Node.JS Airtable - Await 不等待 promise 被解决

javascript - 防止代码在 forEach 之后执行

javascript - 调试生产 JavaScript 的最佳实践是什么?

javascript - JavaScript 中奇怪的意外标记非法

testing - UI 测试应该在构建服务器上运行还是在部署后运行?