Как абстрагировать общую функцию из тестового файла в 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)
})

})

Это то, что я хочу сделать с помощью класса 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 не обрабатывается, поэтому значения до и после всегда равны 0. Любая подсказка или помощь будут оценены.


person surajnew55    schedule 11.10.2018    source источник
comment
Я посмотрю, но мне интересно, есть ли лучший способ проверить это. вы можете добавить функцию в command.js или вы можете просто добавить функцию в свой код js и вызвать ее, но я предполагаю, что вы знаете это, и вы спрашиваете что-то еще, и я не понимаю, что вы пытаетесь выполнить. Позвольте мне взглянуть на ваш код более внимательно.   -  person Maccurt    schedule 11.10.2018
comment
@Maccurt Я пытаюсь добавить функцию добавления в код js и вызвать ее, но не смог этого сделать. Можете ли вы показать один пример с ним.   -  person surajnew55    schedule 12.10.2018
comment
Я понимаю, что это не связано с вашим вопросом, но мне действительно любопытно. Каково было решение перейти от того, что поддерживает многие браузеры, к чему-то, что поддерживает только Chrome, и что такого лучшего в Cypress? Я работал над проектом Courgette с открытым исходным кодом github.com/canvaspixels/courgette и мне было интересно какие особенности привлекают всех к Cypress   -  person alexrogers    schedule 11.11.2018
comment
Когда вы впервые смотрите на Cypress, кажется, что он с другой планеты, например: команда cy — это асинхронная функция, но она не является чистой асинхронностью. Они приправлены повторными попытками и тайм-аутом. Суть кипариса в том, что он ставит вас в такое положение, когда отказ от написания ненадежных тестов становится нормой. Ваша озабоченность по поводу поддержки нескольких браузеров в стадии реализации, и в моем случае хрома более чем достаточно. Я сделал несколько проектов в TestCafe, которые поддерживают все браузеры, но мой опыт был не таким гладким, как у Cypress. На данный момент я думаю, что на данный момент нет лучшего инструмента, чем Cypress для тестирования JS.   -  person surajnew55    schedule 13.11.2018


Ответы (1)


Метод, который вы используете, не рекомендуется кипарисом и считается анти-шаблоном. 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, я предполагаю, что это запускается в командной строке. Существуют пользовательские команды для консоли, а также для использования в пользовательском интерфейсе.

для этой части вам, возможно, придется добавить эту пользовательскую команду

// 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).

Например, у меня были проблемы со входом в систему, и все мои тесты имели функции входа в систему через пользовательский интерфейс, но я хотел начать свои тесты на правильной странице, а не на странице входа. Я добавил это в файл command.js в папке поддержки:

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

И теперь я могу добавить 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()


    })
 })
person Phillipe Bojorquez    schedule 18.10.2018