javascript - 如何从赛普拉斯的测试文件中抽象出常用功能
问题描述
我刚从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)
})
})
这就是我想用 class 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
在最初创建的文件夹结构中,可以在 support 文件夹下找到 commands.js 文件。在这里,您可以创建一个包含您希望重用的逻辑的命令。根据代码的 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(name, callbackFn)
所以你可以潜在地创造类似的东西
Cypress.Commands.add(allNameBeforeInput, (options, options) => {
//custom logic goes here
})
然后你可以通过调用 cy.allNameBeforeInput(options, options) 来使用它。
例如,我在登录时遇到了困难,我的所有测试都具有通过 UI 登录的登录功能,但我想在正确的页面而不是登录页面上开始我的测试。我将此添加到支持文件夹中的 command.js 文件中:
Cypress.Commands.add('login',(username="notsharingmyusernam@stackexchange.com",
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()
})
})
推荐阅读
- hibernate - 为什么在将记录插入表时休眠不为主键列选择数据库序列?
- java - 具有删除功能的单链表无法访问的 If 语句
- google-app-engine - GAE 在本地运行但上传时出现 403 错误
- sqlite - 是否有一个 SQLite 函数只返回一个子字符串/部分值
- r - 如何获取数据表中选择的行数(r,闪亮)
- asp.net-core - 策略设计模式和 EF Core
- r - r: sym() 函数失败 [无法将字符串转换为符号]
- python - accessing help functions and auto-suggesting arguments in python (jupyter lab)
- rust - Simplest way to match multiple fields of a struct against `None`
- java - Add all values of an instance of an object to a List