Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
支援類似 jQuery 的鍊式調用:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
隻是有一點需要特别注意:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
而 Cypress 的異步操作,導緻待讀取的元素真正可用時,其結果才會被作為參數,傳入回調函數:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
也就是說,Cypress 内部幫我們封裝了 retry 和 timeout 重試機制。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
如果想回歸到 jQuery 那種同步讀取元素的風格,使用 Cypress.$ 即可。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 提供了一種叫做 aliasing 的機制,能将元素引用儲存下來,以備将來之用。
看一個例子:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
使用 then 來對前一個指令 yield 的目标進行操作
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的異步執行特性
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
正确的做法,把 html 元素 evaluation 的代碼放在 then 的callback裡:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Each Cypress command (and chain of commands) returns immediately
每個 Cypress 指令(包含指令鍊)調用後立即傳回,不會阻塞住以達到同步運作的效果。
Having only been appended to a queue of commands to be executed at a later time.
這些 command 隻是被添加到一個指令隊列裡,等待 Cypress 架構稍後統一排程執行。
You purposefully cannot do anything useful with the return value from a command. Commands are enqueued and managed entirely behind the scenes.
We’ve designed our API this way because the DOM is a highly mutable object that constantly goes stale. For Cypress to prevent flake, and know when to proceed, we manage commands in a highly controlled deterministic way.
Cypress API 如此設計的原因是,DOM 是一種易變對象,随着使用者操作或者互動,狀态經常會 go stale. 為了避免出現 flake 情形,Cypress 遵循了上文描述的思路,以一種高度可控,确定性的方式來管理指令執行。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
原因就是:在 while 循環裡迅速将巨量的 get command 插入到任務隊列(準确的說是 test chain)裡,而根本沒有機會得到執行。
The above test keeps adding more cy.get(’#result’) commands to the test chain without executing any!
上面的代碼,起到的效果就是,在 while 循環裡,不斷地将 cy.get 指令,加入到 test chain裡,但是任何一個指令,都不會有得到執行的機會!
The chain of commands keeps growing, but never executes - since the test function never finishes running.
指令隊列裡的元素個數持續增長,但是永遠得不到執行的機會,因為 Cypress 代碼本身一直在 while 循環裡,沒有執行完畢。
The while loop never allows Cypress to start executing even the very first cy.get(…) command.
即使是任務隊列裡第一個 cy.get 語句,因為 while 循環,也得不到執行的機會。
正确的寫法:
利用遞歸
在 callback 裡書寫找到 7 之後 return 的邏輯。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
command 執行過程中背後發生的事情
下列這段代碼,包含了 5 部分邏輯:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
This is the big secret of Cypress: we’ve taken our favorite pattern for composing JavaScript code, Promises, and built them right into the fabric of Cypress. Above, when we say we’re enqueuing actions to be taken later, we could restate that as “adding Promises to a chain of Promises”.
Cypress 在 promise 程式設計模式的基礎上,增添了 retry 機制。
下列這段代碼:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
翻譯成 promise 風格的 JavaScript 代碼為:
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Without retry-ability, assertions would randomly fail. This would lead to flaky, inconsistent results. This is also why we cannot use new JS features like async / await.
You can think of Cypress as “queueing” every command. Eventually they’ll get run and in the exact order they were used, 100% of the time.
Cypress 的指令執行順序和其被插入 test chain 隊列的順序完全一緻。
How do I create conditional control flow, using if/else? So that if an element does (or doesn’t) exist, I choose what to do?
有的開發人員可能會産生疑問,如何編寫條件式控制流,比如在 IF / ELSE 分支裡,執行不同的測試邏輯?
The problem with this question is that this type of conditional control flow ends up being non-deterministic. This means it’s impossible for a script (or robot), to follow it 100% consistently.
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
翻譯成自然語言就是:
After clicking on this , I expect its class to eventually be active.
注意其中的eventually.
This above test will pass even if the .active class is applied to the button asynchronously - or after a indeterminate period of time.
Cypress 會不斷重試上述的 assertion,直至 .active class 被添加到 button 上,不管是通過異步添加,還是在一段未知長度的時間段後。
What makes Cypress unique from other testing tools is that commands automatically retry their assertions. In fact, they will look “downstream” at what you’re expressing and modify their behavior to make your assertions pass.
You should think of assertions as guards.
Use your guards to describe what your application should look like, and Cypress will automatically block, wait, and retry until it reaches that state.
Cypress 指令預設的 assertion 機制
With Cypress, you don’t have to assert to have a useful test. Even without assertions, a few lines of Cypress can ensure thousands of lines of code are working properly across the client and server!
This is because many commands have a built in Default Assertion which offer you a high level of guarantee.
很多 cy 指令都有預設的 assertion 機制。
cy.visit() expects the page to send text/html content with a 200 status code. 確定 頁面發出 text/html 内容後,收到200 的狀态碼。
cy.request() expects the remote server to exist and provide a response.
確定遠端系統存在,并且提供響應。
cy.contains() expects the element with content to eventually exist in the DOM.
確定制訂的 content 最終在 DOM 中存在。
cy.get() expects the element to eventually exist in the DOM.
確定請求的 element 最終在 DOM 中存在。
.find() also expects the element to eventually exist in the DOM. - 同 cy.get
.type() expects the element to eventually be in a typeable state.
確定元素處于可輸入狀态。
.click() expects the element to eventually be in an actionable state.
確定元素處于可點選狀态。
.its() expects to eventually find a property on the current subject.
確定目前對象上能夠找到對應的 property
All DOM based commands automatically wait for their elements to exist in the DOM.
所有基于 DOM 的指令,都會自動阻塞,直至其元素存在于 DOM 樹為止。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Cypress 的學習筆記使用 then 來對前一個指令 yield 的目标進行操作Cypress 的異步執行特性command 執行過程中背後發生的事情Cypress 指令自帶的逾時設定Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。
Queries for the element .mobile-nav, 然後停頓 4 秒,直至元素出現在 DOM 裡。