如何从赛普拉斯的测试文件中抽象出通用功能
How to abstract common function out from the test file in Cypress
我刚从 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 篮子完成的:
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 未处理,因此前后的值始终为 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文件。在这里,您可以创建一个命令来包装您希望重用的逻辑。根据代码的 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()
})
})
我刚从 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 篮子完成的:
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 未处理,因此前后的值始终为 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文件。在这里,您可以创建一个命令来包装您希望重用的逻辑。根据代码的 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()
})
})