Cypress — Как переключаться между элементами в iframe

#javascript #testing #iframe #automated-tests #cypress

#javascript #тестирование #iframe — фрейм #автоматизированные тесты #cypress

Вопрос:

Я пытаюсь взаимодействовать с некоторыми элементами внутри iframe с помощью cypress. Если я использую подход в https://bparkerproductions.com/how-to-interact-with-iframes-using-cypress-io / только для одного элемента в тесте все в порядке.

 # commands.js
Cypress.Commands.add(
    'iframe',
    { prevSubject: 'element' },
    ($iframe) => {
        return new Cypress.Promise(resolve => {
            $iframe.on('load', () => {
                resolve($iframe.contents().find('body'))
            })
        })
    })


# landing_page.spec.js    
cy.get('iframe').iframe().find('#happybutton').should('be.visible')
 

Однако я хочу найти несколько элементов, щелкнуть по ним и проверить, правильно ли они отображаются, но если я присвою содержимое iframe переменной и повторно использую его для поиска другого элемента (например, кнопки), cypress попытается найти второй элемент (например, меню) из первого элемента (кнопка, которая обречена на неудачу, потому что кнопка не содержит меню).

 # landing_page.spec.js  
let iframeContent = cy.get('iframe').iframe()
iframeContent.find('#happybutton').should('be.visible')
iframeContent.find('#myMenu').should('be.visible')
 

Я пытался использовать разные переменные или вызывать напрямую cy.get('iframe').iframe() каждый раз, когда хотел взаимодействовать с разными элементами, но cypress попадает в бесконечный цикл, и тест никогда не заканчивается (но никаких ошибок или предупреждений не выдается).

Кто-нибудь знает способ избежать этого бесконечного цикла? Поскольку я хочу воспроизвести последовательность шагов для создания тестового примера, невозможно изолировать каждое взаимодействие в другом тесте.

Или кто-нибудь знает фреймворк, который больше подходит для работы с фреймами?

Комментарии:

1. Взгляните на cypress-iframe , который использует вложенность для выполнения нескольких команд.

Ответ №1:

Проблема $iframe.on('load', в том, что срабатывает только один раз, поэтому вы не можете вызвать cy.get('iframe').iframe() дважды, что фактически и делают обе .find() команды.

let iframeContent = cy.get('iframe').iframe() не сохраняет тело iframe, оно хранит «цепочку», которая обрабатывается как функция или средство получения.

«Бесконечный цикл» — это Cypress, ожидающий вызова promise resolve() во второй раз, чего никогда не происходит.

Таким образом, вы можете вложить команды следующим образом

 cy.get('iframe').iframe().then(body => {

  cy.wrap(body).find('#happybutton').should('be.visible')
  cy.wrap(body).find('#myMenu').should('be.visible')

});
 

или вы можете улучшить команду, добавив тег при срабатывании события загрузки

 Cypress.Commands.add('iframe', { prevSubject: 'element' }, ($iframe) => {
  return $iframe._hasloaded 
    ? $iframe.contents().find('body')
    : new Cypress.Promise(resolve => {
        $iframe.on('load', () => {
          $iframe._hasloaded = true;
          resolve($iframe.contents().find('body'))
        })
      })
  })
 

Ответ №2:

Благодаря ответу Марион я нашел способ реорганизовать свой код, так что теперь он работает! Примечание: iframe() функция была оставлена нетронутой

 # commands.js
Cypress.Commands.add(
    'iframe',
    { prevSubject: 'element' },
    ($iframe) => {
        return new Cypress.Promise(resolve => {
            $iframe.on('load', () => {
                resolve($iframe.contents().find('body'))
            })
        })
    })


# landing_page.spec.js  
cy.get('iframe').iframe().as('iframeContent')
cy.get('@iframeContent').then((iframeContent) => {
    cy.get(iframeContent).find('#happybutton').click()
    cy.get(iframeContent).find('#myMenu')
    cy.get(iframeContent).find('#anotherElement').should('be.visible')
})
 

Комментарии:

1. Хорошо, это работает, но .as('iframeContent') прямое следование cy.get('@iframeContent') просто изнашивает кончики пальцев.

Ответ №3:

Приведенные выше ответы указали мне правильное направление. Опустив фразу ‘then’ и первый cy.get(‘@iframeContent’), решение Semiramis можно немного упростить и упростить для понимания следующим образом:

 cy.get('iframe').iframe().as('iframeContent')
cy.get('@iframeContent').find('#happybutton').click()
cy.get('@iframeContent').find('#myMenu')
cy.get('@iframeContent').find('#anotherElement').should('be.visible')
 

Для новичков Cypress (таких, как я): переменные и псевдонимы Cypress