У нас есть приложение, которое периодически опрашивает сервер, пока задача не будет выполнена. Мы запускаем глобальное событие, чтобы Cypress мог поймать и узнать, завершена ли задача, но у нас возникли проблемы с использованием document.addEventListener
на Cypress. Вот что мы делаем:
document.addEventListener('queryEnd', () => {
cy.get('.chart').should('be.visible')
cy.get('.table').should('be.visible')
})
Однако; когда мы используем его в спецификации, он не работает ожидаемо, и мы не можем его отловить. Кроме того, Cypress не ждет теста и запускается afterEach
, не дожидаясь выполнения обратного вызова.
Причина, по которой ваш код не работает так, как вы ожидаете, заключается в том, что в Cypress ваши тесты выполняются в отдельном фрейме, чем тестируемое приложение (AUT). Событие, которого вы ждете, никогда не произойдет внутри document
Cypress.
Чтобы получить document
AUT, используйте cy.document()
следующим образом:
cy.document()
.then($document => {
// now $document is a reference to the AUT Document
$document.addEventListener(...)
})
Чтобы Cypress дождался вашего события, прежде чем продолжить, вы можете просто заключить его в Cypress.Promise
. В документации Cypress есть пример ожидание завершения обещания. Для вашего мероприятия queryEnd
это будет выглядеть примерно так:
cy.document() // get a handle for the document
.then($document => {
return new Cypress.Promise(resolve => { // Cypress will wait for this Promise to resolve
const onQueryEnd = () => {
$document.removeEventListener('queryEnd', onQueryEnd) // cleanup
resolve() // resolve and allow Cypress to continue
}
$document.addEventListener('queryEnd', onQueryEnd)
})
})
.then(() => {
cy.get('.chart').should('be.visible')
cy.get('.table').should('be.visible')
})
@AdamB да, так и должно быть
Кажется сложным избежать условий гонки, потому что прослушиватель событий добавляется после cy.visit
, может возникнуть риск того, что к тому времени событие уже будет запущено. Использование cy.window()
кажется более надежным, потому что объект window
доступен намного раньше, чем window.document
.
@EricBurel Отличный момент. Было бы лучше добавить это как обратный вызов cy.visit
onBeforeLoad
, а не как cy.document().then
или cy.window().then
, по причине, которую вы описываете: docs.cypress.io/api/commands/…
Еще лучше добавить прослушиватель для события, явно вызывая это событие (например, с cy.click()), а затем подтверждая, что оно произошло. Никаких условий гонки, если вы можете заказать такие действия своего приложения. Но это может быть сложно для вещей, которые происходят только при нагрузке.
Вы должны опубликовать onBeforeLoad
в качестве ответа, я думаю, что это может быть лучшим подходом. У вас есть доступ к материалам cy.
в этом обратном вызове? Если нет, мы все равно можем использовать его, чтобы установить глобальную переменную, например, когда событие запускается, и проверить эту переменную позже. Проблема с запуском события вручную заключается в том, что это не всегда возможно (здесь я хочу сказать, когда на странице выполняется рендеринг WebGL, поэтому он запускается немедленно)
Сделал попытку onBeforeLoad
: работает нормально, однако вы должны быть осторожны, потому что он не будет ждать вопреки обычным командам cy.*
. Так что, если вы сделаете cy.visit("/foobar", onBeforeLoad: (win) => { win.addEventListener("foobar", () => { cy.expect(true).toBe(true)}) } })
, cy.expect
не будет ждать. Таким образом, вам все еще нужна дополнительная команда для ожидания события перед выходом.
Открыт запрос функции: github.com/cypress-io/cypress/issues/16793
Должно ли это работать для события
shiny:value
, описанного здесь shining.rstudio.com/articles/js-events.html?