Tips for Cypress End-to-End Testing

Jayson Chiang
5 min readMar 22, 2022
Cypress不難,但我起手實在怎麼寫怎麼苦。

Cypress不難,但我起手實在怎麼寫怎麼苦。

他寫起來像 jQuery,但不能用jQuery的思維。寫起來像同步,但全部都是非同步。他長得像Promise,但不是Promise。他有自動 retry 機制,但又不如我所預期的retry。總之在我浪費了一堆時間後,看了文件,才知道我自以為是。

如果你像我一樣從jQuery時代當前端工程師,強烈建議寫Cypress自動化測試前,先讀過 https://docs.cypress.io/guides/core-concepts/introduction-to-cypress

這邊僅紀錄我跌倒過的筆記,Cypress的官方文件絕對夠強大,值得一讀再讀。

  1. 不指派變數Variables (即不使用 constlet )
// ❌ 不會也不能出現這種語法
const button = cy.get('button')
button.click() // 此行無效
// ✅ 以下才是正確的寫法
cy.get('button').then($btn => {
$btn.click()
})

取代 變數的方法是使用 別名Alias .as()

// 存值(1)
cy.get('button').invoke('text').as('myTxt')
// 取值,注意,需要包在 function(){}, 而不是()=>{}
this.myTxT
// 存值(2):wrap
cy.wrap('my value').as('myValue');
// 取值
cy.get('@myValue').should('equal', 'my value');
// 存元素
cy.get('button').as('myBtn')
// 取元素
cy.get('@myBtn').click()

2. 使用 intercept, as, wait 等待 Ajax

cy.intercept('GET', '/my-profile').as('apiMyProfile')cy.wait('@apiMyProfile').then((res) => {
expect(res.status).should('equal', 200)
})

3. Cypress 會不斷的 Retry comment 和 assertion

我認為這是Cypress最偉大的機制,因為我們再不用去猜Ajax或是前端框架state變化,而浪費時間去 wait

cy.get('ul li') 
.should('have.length', 4)

情境 1:如果 Cypress執行到cy.get('ul li')且取不到元素時,會Retry取元素;直到取到元素才會繼續走下一步; 或是直到 Timeout ,才會測試失敗。

情境 2:如果 Cypress執行到cy.get('ul li')且有取得元素時,就會繼續進行 .should('have.length', 4)

情境 2.a:進行到.should('have.length', 4) 時,如果長度為 4,那麼立刻測試成功,結束這測試。

情境 2.b:進行到.should('have.length', 4) 時,如果長度不為 4,不會馬上測試失敗。Cypress 會 Retry,直到長度變成4的時侯,測試成功。或是真的Retry到Timeout,才會確定測試失敗。

4. 事件不會 Retry

這是另一個大坑,文件只讀一半很容易死在這點

// 案例說明: click button後,會顯示 popup
cy.get('button').click();
cy.get('.popup').should('be.visible');

情境1:如果 Cypress執行到cy.get('button')且取不到元素時,會Retry取元素;直到取到元素才會繼續走下一步; 或是直到 Timeout ,才會測試失敗。

情境2:如果 Cypress執行到cy.get('button')且有元素時,會走下一步 .click()

情境 2.a:進行到.click() 時,如果該元素有click事件且可以點擊,則會觸發事件。以上例來說,會看到 popup 元素,測試成功。

情境 2.b:進行到.click() 時,如果該元素的雖然有click事件,但狀態為不可點擊(例disabled),則Cypress不會觸發事件,且不Retry,直接走下一步;以上例來說,就看不到popup 元素,測試失敗。

為了避免 click的當元素是可點擊的狀態,故測試案例應可調整為:

cy.get('button').should('not.be.disabled').click();
cy.get('.popup').should('be.visible');

如果 button原本的狀態是disable的話,Cypress會Retry到沒有disabled才會報行 click()

除了上述的筆記,我覺得Cypress真的是超級大推廌的測試工具。

  1. 以Selenium過來人的經驗來說,寫E2E測試不難,但安裝測試環境就煩死了; 而Cypress只要簡單的 npm install cypress ,也不用煩惱Dependency
  2. Cypress的文件和案例真的非常非常豐富,少數看文件比google 還快找到答案的工具
  3. Cypress的更新真的很快速,雖然然我們都害怕升級,但Cypress的幾次升級,確實提供了很棒而且用得到的API
  4. 最後當然還是因為他主要的語言是JavaScript,讓前端開發者可以無痛開發測試案例,專心在程式邏輯,而不是花時間在學習新的語言或怎麼操作工具。

--

--