cypress 的错误消息 - the element has become detached or removed from the dom
這個(gè)錯(cuò)誤消息的分析和解決方案,可以參考 Cypress 的官方文檔。
這個(gè)錯(cuò)誤消息提示我們,我們編寫的 Cypress 代碼正在同一個(gè)“死去”的 DOM 元素交互。
顯然,在真實(shí)的使用場景下,一個(gè)用戶也無法同這種類型的 UI 元素交互。
看個(gè)實(shí)際例子:
<body><div id="parent"><button>delete</button></div> </body>這個(gè) button 被點(diǎn)擊之后,會(huì)將自己從 DOM 樹中移除:
$('button').click(function () {// when the <button> is clicked// we remove the button from the DOM$(this).remove() })下列這行測試代碼會(huì)引起錯(cuò)誤:
cy.get('button').click().parent()當(dāng) cypress 執(zhí)行到下一個(gè) parent 命令時(shí),檢測到施加該命令的 button 已經(jīng)從 DOM 樹中移除了,因此會(huì)報(bào)錯(cuò)。
解決方案:
cy.get('button').click() cy.get('#parent')解決此類問題的指導(dǎo)方針:
Guard Cypress from running commands until a specific condition is met
兩種實(shí)現(xiàn) guard 的方式:
看另一個(gè)例子:
輸入 clem,從結(jié)果列表里選擇 User clementine , 即所謂的 type head search 效果。
測試代碼如下:
it('selects a value by typing and selecting', () => {// spy on the search XHRcy.server()cy.route('https://jsonplaceholder.cypress.io/users?term=clem&_type=query&q=clem').as('user_search')// first open the container, which makes the initial ajax callcy.get('#select2-user-container').click()// then type into the input element to trigger search, and wait for resultscy.get('input[aria-controls="select2-user-results"]').type('clem{enter}')// select a value, again by retrying command// https://on.cypress.io/retry-abilitycy.contains('.select2-results__option', 'Clementine Bauch').should('be.visible').click()// confirm Select2 widget renders the namecy.get('#select2-user-container').should('have.text', 'Clementine Bauch') })要點(diǎn):
使用 cy.route 監(jiān)控某個(gè) XHR, 這里可以監(jiān)控相對路徑嗎?
本地測試通過,在 CI 上運(yùn)行時(shí)會(huì)遇到下列錯(cuò)誤:
如何分析這個(gè)問題呢?可以使用 pause 操作,讓 test runner 暫停。
// first open the container, which makes the initial ajax call cy.get('#select2-user-container').click().pause()當(dāng)我們點(diǎn)擊了 select2 widget 時(shí),會(huì)立即觸發(fā)一個(gè) AJAX call. 而測試代碼并不會(huì)等待 clem 搜索請求的返回。它只是一心查找 “Clementine Bauch” 的 DOM 元素。
// first open the container, which makes the initial ajax call cy.get('#select2-user-container').click()// then type into the input element to trigger search, // and wait for results cy.get('input[aria-controls="select2-user-results"]').type('clem{enter}')cy.contains('.select2-results__option','Clementine Bauch').should('be.visible').click()上面的測試在本地運(yùn)行時(shí)大部分時(shí)間可能會(huì)通過,但在 CI 上它可能會(huì)經(jīng)常失敗,因?yàn)榫W(wǎng)絡(luò)調(diào)用速度較慢,瀏覽器 DOM 更新可能較慢。 以下是測試和應(yīng)用程序如何進(jìn)入導(dǎo)致 “detached element” 錯(cuò)誤的競爭條件。
然后測試搜索可見的選擇“Clementine Bauch” - 并在初始用戶列表中找到它。
然后,測試運(yùn)行器將要單擊找到的元素。注意這里的竟態(tài)條件。當(dāng)?shù)诙€(gè)搜索 Ajax 調(diào)用“term=clem”從服務(wù)器返回時(shí)。 Select2 小部件刪除當(dāng)前的選項(xiàng)列表,只顯示兩個(gè)找到的用戶:“Clementine Bauch”和“Clementina DuBuque”。
然后測試代碼執(zhí)行 Clem 元素的點(diǎn)擊。
Cypress 拋出錯(cuò)誤,因?yàn)樗獑螕舻膸в形谋尽癈lementine Bauch”的 DOM 元素不再鏈接到 HTML 文檔; 它已被應(yīng)用程序從文檔中刪除,而 Cypress 仍然引用了該元素。
這就是問題的根源。
下面這段代碼可以人為地讓這個(gè)竟態(tài)條件總是觸發(fā):
cy.contains('.select2-results__option','Clementine Bauch').should('be.visible').pause().then(($clem) => {// remove the element from the DOM using jQuery method$clem.remove()// pass the element to the clickcy.wrap($clem)}).click()既然了解了竟態(tài)條件觸發(fā)的根源,修正起來就有方向了。
我們希望測試在繼續(xù)之前始終等待應(yīng)用程序完成其操作。
解決方案:
cy.get('#select2-user-container').click()// flake solution: wait for the widget to load the initial set of users cy.get('.select2-results__option').should('have.length.gt', 3)// then type into the input element to trigger search // also avoid typing "enter" as it "locks" the selection cy.get('input[aria-controls="select2-user-results"]').type('clem')我們通過 cy.get(‘XXX’).should(’’) 操作,確保在執(zhí)行 clem 輸入之前,初始的 user list 對應(yīng)的 AJAX 一定回復(fù)到服務(wù)器上了,否則 select2-options 的長度必定小于 3.
當(dāng)測試在搜索框中鍵入“clem”時(shí),應(yīng)用程序?qū)⒂|發(fā) Ajax 調(diào)用,該調(diào)用返回用戶的子集。 因此,測試需要等待顯示新集合 - 否則它將從初始列表中找到“Clementine Bauch”并遇到detached 錯(cuò)誤。我們知道只有兩個(gè)用戶匹配“clem”,因此我們可以再次確認(rèn)顯示的用戶數(shù)以等待應(yīng)用程序。
/ then type into the input element to trigger search, and wait for results cy.get('input[aria-controls="select2-user-results"]').type('clem')// flake solution: wait for the search for "clem" to finish cy.get('.select2-results__option').should('have.length', 2)cy.contains('.select2-results__option', 'Clementine Bauch').should('be.visible').click()// confirm Select2 widget renders the name cy.get('#select2-user-container').should('have.text', 'Clementine Bauch')如果盲目的在 click 調(diào)用里傳入 force:true 的參數(shù),可能會(huì)引入新的問題。
更多Jerry的原創(chuàng)文章,盡在:“汪子熙”:
總結(jié)
以上是生活随笔為你收集整理的cypress 的错误消息 - the element has become detached or removed from the dom的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 心如大海海纳百川的意思
- 下一篇: 浅谈 Orbeon form build