e2e測試(End-to-End testing)是模擬使用者的行為,實際打開瀏覽器操作頁面的測試方式,因此不限於vue, react的專案,e2e的測試可以反映出頁面在不同瀏覽器的執行情形。
Cypress便是其中一個常見工具,Cypress在安裝上簡單,語法採用 mocha 的句法、chai 的斷詞(expect, should, assert),撰寫的方式跟 unit test 相似。
安裝
進到想要測試的專案目錄內,使用 npm 安裝。(官網說明)
npm install cypress --save-dev
接著在目錄裡,建立先建立一個 cypress.json,內容放一個空物件,此時你可以直接執行下面的命令(官網說明):
npx cypress open
會發現多了一個 cypress/ 的資料夾,裡面有四個目錄:
- integration: 主要的測試檔案
- fixtures: 固定的資料
- plugins: 主要有 on 定義全局的不同時間點的執行工作,以及 config 提供全局使用的參數,如常用的 env
- support: 可提供自定義的指令、或引入擴充的指令,供撰寫測試檔案使用
Cypress.json 與環境變數(.env)
使用 cypress 都必須在專案的根目錄裡新增 cypress.json,如果直接放 {} 空物件,代表直接使用預設值。
下面是我的設定,從字面上不難理解設定的內容,第一個testFiles是測試的檔案名稱,接著各個目錄的路徑,video是 Boolean 決定是否錄製測試過程的影片,screenshotOnRunFailure也是 Boolean 是否在執行失敗時擷取畫面。
{
"testFiles": "**/*.spec.js",
"integrationFolder": "resources/cypress/integration",
"componentFolder": "resources/cypress/components",
"fixturesFolder": "resources/cypress/fixtures",
"pluginsFile": "resources/cypress/plugins",
"supportFile": "resources/cypress/support",
"video": false,
"screenshotOnRunFailure": false
}
除了cypress基本的設定,常常也需要讀取環境設定檔(.env),假設內容如下(官方說明):
APP_URL=https://chenuin.github.io/
USER_NAME=chenuin
在plugins/index.js可以設定:
// plugins/index.js
require('dotenv').config();
module.exports = (on, config) => {
config.baseUrl = process.env.APP_URL;
config.env.USER_NAME = process.env.USER_NAME;
return config;
}
測試檔案需要使用時,可以直接呼叫:
Cypress.config('baseUrl')
Cypress.env('USER_NAME')
打開GUI,點選上方的 Settings 可以看到設定的結果,上面的顏色可以區分目前的設定是讀取哪裡,像是 baseUrl 是紫色的 plugin,
因此,可以知道下面兩種寫法都可以達到相同的效果:
// plugins/index.js
config.baseUrl = process.env.APP_URL;
// cypress.json
{
"baseUrl": "https://chenuin.github.io/"
}
執行
提供 GUI 介面操作
npx cypress open
無GUI,在 Terminal 上執行
npx cypress run
訪問頁面 visit
測試的第一步常常是先進入某一個頁面,通常專案內都在相同的Domain下,如果有設定 baseUrl,Cypress會直接將設定作為前綴,導到相應的頁面,在寫法上簡潔許多。
// https://chenuin.github.io/webpack/2021/08/08/webpack5-getting-started.html
cy.visit('/webpack/2021/08/08/webpack5-getting-started.html')
若未設定,需要傳入完整的路徑,或者cypress會嘗試在你的web server上找到對應位置的頁面。(官方說明)
intercept與fixtures的使用
使用 intercept 來監聽由頁面上請求(request)及回應(response),下面三者是相同的意思:
cy.intercept('/users/**')
cy.intercept('GET', '/users/**')
cy.intercept({
method: 'GET',
url: '/users/**',
})
你也可以為這個路由(route)新增別名(alias),除了方便辨識外,如果需要在request後執行的工作,可以使用下面的寫法:
cy.intercept('POST', '/users').as('createUser');
// once a request to create user responds, 'cy.wait' will resolve
cy.wait('@createUser')
GUI上可以看到這個 route 表格
執行此請求時會留下Log記錄,所有被監聽的路由會列在route表格,表格上可以看到所有route被呼叫的次數(表格最右側的數字),對應的別名(alias)是什麼。
上面 Stubbed 是代表回應(response)是否被取代了,這個是很好用的功能,例如:當我們將 users 這個請求的回應,取代為一個列表:
// requests to '/users' will be fulfilled
// with a body of list: ['John', 'Ben', 'Mary]
cy.intercept(
'/users',
['John', 'Ben', 'Mary],
)
或者可以使用 fixture ,後面填寫 fixture/ 目錄裡的檔案名稱。
// requests to '/users' will be fulfilled
// with the contents of the "users.json" fixture
cy.intercept(
'/users',
{ fixture: 'users.json' },
)
(
官方說明)
ESLint設定
請在 .eslintrc.js 加上設定,不需要安裝任何套件:
module.exports = {
extends: [
'plugin:cypress/recommended',
],
};