admin管理员组

文章数量:1387312

I just moved from TestCafe to Cypress and couldn't find a solution to abstract a mon frequently used method. In this example below cy.document().then(doc).. is used twice, however I believe that these types of function must be abstracted to reusable function.

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)
})

})

This is what I want to acplished with 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
    })
}

Now I should be able to use

    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}

This is not working because of async/await is not handled so the value of before and after are alway 0. Any clue or help will be appreciated.

I just moved from TestCafe to Cypress and couldn't find a solution to abstract a mon frequently used method. In this example below cy.document().then(doc).. is used twice, however I believe that these types of function must be abstracted to reusable function.

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)
})

})

This is what I want to acplished with 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
    })
}

Now I should be able to use

    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}

This is not working because of async/await is not handled so the value of before and after are alway 0. Any clue or help will be appreciated.

Share Improve this question asked Oct 11, 2018 at 7:34 surajsuraj 5933 gold badges11 silver badges25 bronze badges 4
  • I will take a look, but I am wondering if there is a better way to test this. you can add a function in mand.js or you could just add a function in your js code and call it, but I assume you know that and you are asking something else and I don't understand that you are trying to acplish. Let me look at your code harder. – Maccurt Commented Oct 11, 2018 at 12:31
  • @Maccurt I am trying to do the add function in js code and call it, but couldn't acplish it. Can you show one example with it. – suraj Commented Oct 12, 2018 at 8:25
  • I realise this isn't related to your question but I am really curious. What was the decision to move from something that supports many browsers to something that just supports Chrome and what's so much better about Cypress? I've been working on the Open-source project Courgette github./canvaspixels/courgette and was wondering what features are drawing everybody to Cypress – alexrogers Commented Nov 11, 2018 at 9:20
  • When you first look Cypress it looks like from the other planet, for example: the cy mand are async function but they are not pure async. They are spiced with retry-and-time out. The basic of cypress is it puts you in such a position where avoid writing flaky test bees the norms. Your concern about multiple browser support is under way and in my case chrome is more than enough. I have done couple of project in TestCafe which support all the browser but my experience was not as smooth as Cypress. At the moment I think there is no better tools than Cypress for JS testing at the moment. – suraj Commented Nov 13, 2018 at 8:30
Add a ment  | 

1 Answer 1

Reset to default 4

The method you are using is not remended by cypress and is considered an anti-pattern. https://docs.cypress.io/guides/references/best-practices.html#Assigning-Return-Values

Cypress remends that you add custom mands. https://docs.cypress.io/api/cypress-api/custom-mands.html#Syntax

In the initially created folder structure, the mands.js file can be found under the support folder. Here you are able to create a mand that wraps up the logic you wish to reuse. Based on the console.log portion of your code I assume this is run on the mand line. There are custom mands for the console as well as for use in the UI.

for that portion you may have to add this custom mand

// not a super useful custom mand
// 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 mands 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 bees the new subject
  //
  // we don't want to change the subject so
  // we return whatever was passed in
  return subject
})

For the other functionality creating mands is pretty simple, the basic pattern is:

Cypress.Commands.add(name, callbackFn)

so you can potentially create something like

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

})

Then you can use it by calling cy.allNameBeforeInput(options, options).

For instance, I was struggling with login and all my tests had login functions to log in through the UI but I wanted to start my tests on the correct page instead of the the log in page. I added this to the mand.js file in the support folder:

Cypress.Commands.add('login',(username="[email protected]", 
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"
   }
 })
})

And now I can add the cy.login and a beforeEach function at the beginning of my tests. The before each to make the request to the server and wait for the request for login and the cy.login custom mand to ensure that I can use that bundled up logic with just one cy mand.

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

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


    })
 })

本文标签: javascriptHow to abstract common function out from the test file in CypressStack Overflow