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

Я пытаюсь взаимодействовать с некоторыми элементами внутри iframe с помощью кипариса. Если я использую подход в 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 переменной и повторно использую его для поиска другого элемента (например, кнопки), кипарис попытается найти второй элемент (например, меню) из первого элемента (кнопки, которая обречена на провал, потому что кнопка не содержит меню).

# 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-iframe, который использует вложение для запуска нескольких команд.

user12697177 10.12.2020 20:12
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
1
3 009
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Проблема в том, что $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'))
        })
      })
  })
Ответ принят как подходящий

Благодаря ответу Марион я нашел способ реорганизовать свой код, так что теперь он работает! Примечание: функция 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')
})

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

user12697177 11.12.2020 00:34

Приведенные выше ответы указали мне правильное направление. Опустив фразу «тогда» и первый 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

Другие вопросы по теме