Cypress E2E Testing Framework
Features
- No more async hell
Cypress automatically retries the query until the element is found. - Real time reloads
Cypress automatically reloads whenever you make changes to your tests. - Spies, stubs, and clocks
Verify and control the behavior of functions, server responses, or timers. - Run with native browsers
Keep fast, consistent and reliable tests.
運作方式
![Screen Shot 2018-01-27 at 20.34.59.png]({{ site.url }}/assets/images/Cypress-usage-process.png)
基本測試撰寫
1// describe()- Group your test cases.
2describe('ThingsPro', () => {
3
4 // context() - Usage is the same as describe().
5 context('Login', () => {
6
7 // it() - A test case.
8 it('error - incorrect email', () => {
9
10 // get() - Querying behavior.
11 // type() - Action
12 // should() - Create an assertion
13 cy.get('input[type=email]').type('rooot@moxa.com');
14 cy.get('input[type=password]').type('root1234');
15 cy.get('button')
16 .contains('Sign in')
17 .click();
18 cy.get('.toast').should('contain',
19 'Please check your email and password');
20
21 });
22 });
23});
Common Querying Methods
Use jQuery-style selectors.
-
get(selector, options)
Yield: DOM elements. -
find(selector, options)
Get the descendent DOM elements of a specific selector.
Yield: DOM elements. -
contains(content, options)
Get the DOM element containing the text. Yield: DOM elements.
Example
HTML file
1<header><p class="subtitle">This is a website</p></header>
test case
1cy.get('header')
2 .find('.subtitle')
3 .contains('This is a website');
Common Action Methods
-
click(position, options)
-
submit(options)
-
select(value, options)
All Yield current DOM elements.
Example
1cy.get('select')
2 .select('apples')
3 .select('orange');
Assertion Methods
should(chainers, method, value)
Notice: Any valid chainer that comes fromChai
orChai-jQuery
orSinon-Chai
.
Example
1cy.get('a').should('have.attr', 'href', '/login')
Cypress Commands Are Asynchronous
Reference: Commands Are Asynchronous
Use a chain of promises
結合 Promise, Retry 和 timeout 來實作 Chainer object 實現非同步測試。
![Screen Shot 2018-01-28 at 11.12.09.png]({{ site.url }}/assets/images/Cypress-usage-chainer.png)
Example
How to set up timeout object.
1// How to add timeout to cy command.
2// For instance: get(selector, options);
3// you can use timeout object to *options* params.
4cy.get('.subtitle', {timeout: 5000});
Run tests serially
將 command 加到特定佇列之中,並在最後才根據佇列順序來執行測試流程。
1it('error - incorrect email', () => {
2
3 // Add commands to a queue.
4 cy.get('input[type=email]').type('rooot@moxa.com');
5 cy.get('input[type=password]').type('root1234');
6 cy.get('button')
7 .contains('Sign in')
8 .click();
9 cy.get('.toast').should('contain',
10 'Please check your email and password');
11
12});
13 // Run tests in order.
Somethings you MUST need to know
1. Cypress is the top of Mocha testing framework
Reference: Mocha is a feature-rich JavaScript test framework
- Could use Mocha related reporters(we use
mochawesome
). - Cannot change to your preferred frameworks.
2. Cypress is an E2E testing framework
- It is very hard to measure code coverage. Issue: Code Coverage #346
- 如果需要跑 Code Coverage,請額外使用其他 testing library (Mocha)來執行 Unit test.
3. Supported browser Canary/Chrome/Chromium/Electron
- 目前沒有支援 Chrome headless, 因為 Chrome extension 不支援。不過目前已有解法,還在開發中。
- Default use
headless electron
. Will supportChrome headless
in coming days. Issue#832: Support chrome headless and change defaults for cypress run - If wanna run CI with Chrome, you can use command
cypress run --browser chrome
. (Notice: This is in head mode not headless.) - Will support
Firefox
in the future.
Run Cypress with Cucumber
Cucumber
- A tool that supports Behaviour-Driven Development (BDD)
- Cucumber executes executable specifications written in plain language.
Feature file & Step js file
- Feature file
.feature
- 可由PM或其他非工程師的人撰寫。 Step.js
- 由工程師搭配 feature file 的內容來實作測試流程。
Write a Feature file
.feature
, 每個 feature file 為一個功能。Feature file 使用可以閱讀的文字敘述並搭配幾個指定單字:Given(前提假設)
, When(當什麼改變)
, Then(結果)
, And
,or But
. 一個 Feature files 通常包含一系列相關的 scenarios。
Example:
Feature: Slider Bar
Scenario: Enable a Slider Bar
Given 這是一個 "disabled" 的 Slider Bar
When 我指定一個檔案存放位置
Then Slider Bar 的狀態會變成 "enable"
Scenario: 拉動 Slider Bar 的位置,會顯示正確的值
When 使用者將 Slider Bar 拉至中間位置
Then Slider Bar 的值會變成檔案存放量最大值的一半
Scenario: 當使用者選擇的數值低於建議數值時,則顯示警告訊息
When Slider Bar 拉到低於建議數值
Then 會出現建議數值的警告訊息
" " - 標示此詞為 Variable
Scenario: 輸入錯誤的 End IP 格式,則更新失敗
Given 進入 DHCP server "Settings" 頁面
When "End IP" 設定為 "192.0.0.0.0"
When 點選 SAVE 儲存設定
Then 顯示 "error" 資訊
Scenario: 輸入錯誤的 Netmask 格式,則更新失敗
Given 進入 DHCP server "Settings" 頁面
When "Netmask" 設定為 "192.192.192.192.192"
When 點選 SAVE 儲存設定
Then 顯示 "error" 資訊
Scenario: 輸入錯誤的 Primary DNS 格式,則更新失敗
Given 進入 DHCP server "Settings" 頁面
When "Primary DNS" 設定為 "192"
When 點選 SAVE 儲存設定
Then 顯示 "error" 資訊
實作 Step.js file
- 如果 .feature 中的步驟沒有被實作在 step file 中,就會報錯。
Example
Feature
Scenario: 輸入錯誤的 Netmask 格式,則更新失敗
Given 進入 DHCP server "Settings" 頁面
When "Netmask" 設定為 "192.192.192.192.192"
When 點選 SAVE 儲存設定
Then 顯示 "error" 資訊
Scenario: 輸入錯誤的 Primary DNS 格式,則更新失敗
Given 進入 DHCP server "Settings" 頁面
When "Primary DNS" 設定為 "192"
When 點選 SAVE 儲存設定
Then 顯示 "error" 資訊
Step.js file
1when(`{string} 設定為 {string}`, (item, value) => {
2 cy
3 .get('label')
4 .contains(`${item}`)
5 .siblings('input')
6 .type(value);
7});
8
9then(`顯示 {string} 資訊`, status => {
10 cy.get(`.toast-${status}`);
11});
Connect Cucumber to Cypress
Use cucumber preprocessor plugin
- Know more about Cypress plugins Cypress plugin Document
- The current plugin we use is cypress-cucumber-preprocessor
![Screen Shot 2018-01-28 at 13.22.51.png]({{ site.url }}/assets/images/Cypress-usage-cucumber.png)
Add your plugins to plugins/index.js
1const cucumber = require('cypress-cucumber-preprocessor').default;
2module.exports = (on, config) => {
3 on('file:preprocessor', cucumber());
4};