因為 Cucumber 是能夠跨越不同開發環境使用的,因此這次我們會以前端與後端互相搭配的方式進行,在前端的部分採用 Vite 和 Playwright 來進行測試。
Vite 安裝
Vite 是非常輕量的工具,也有 Vite Ruby 可以跟 Ruby 的專案一起使用,這一次我們會使用 Vue 與 TypeScript 和 Cucumber 搭配開發,因此我們需要先建立一個前端的專案供我們使用。
1yarn create frontend --template vue-ts
如果習慣使用 npm
或者 pnpm
等工具,也可以依照官方文件的指示選擇使用自己習慣的套件管理工具。
Cucumber 安裝
要安裝 Cucumber 只需要透過套件管理工具加入到 package.json
即可,除了 Cucumber 之外,我們還希望有 Playwright 來模擬使用真實瀏覽器操作的狀況,因此一起將兩個套件加入。
1yarn add --dev @cucumber/cucumber playwright @playwright/test
Playwright 本身就有運行測試的功能,因為我們希望讓 Cucumber 來扮演這個角色,因此需要另外加入 @playwright/test
這個套件,用來實現斷言相關的機制。
完成之後我們可以簡單用 yarn run
命令驗證 Cucumber 正常運作。
1yarn run cucumber-js
接下來我們要將 Cucumber 設定為會使用 Playwright 開啟瀏覽器以及 Vite 預覽伺服器的模式,來讓我們可以測試到真實的 Vite 專案。
環境設定
Cucumber 針對前端的測試基本上有幾種方式,比較直覺的做法是先進行 yarn build
(建置)之後直接使用靜態的檔案處理,另外一個就是我們直接利用 Vite 的 createServer
API 啟動一個測試用的環境來運行。
首先,我們先在專案目錄下加入 cucumber.js
來設定我們的測試環境。
1export default {
2 publishQuiet: true,
3 requireModule: ['tsm'],
4 require: [
5 'features/**/*.ts'
6 ],
7 strict: true,
8 tags: 'not @wip',
9}
為了讓 TypeScript 可以被 Cucumber 辨識到,我們可以使用 requireModule
的選項載入對應的模組,像是 tsm
或者 ts-node
等等,可以依照自己的偏好選擇。
接下來要讓 Playwright 在測試開始時啟動瀏覽器,以及使用 Vite 的 API 來運行一個測試用的環境,我們加入 features/support/world.ts
這個檔案來進行定義。
因為用
features/**/*.ts
定義了要自動載入的路徑,我們這邊使用大多數 Cucumber 的慣例將環境設定相關的檔案放到features/support
目錄下
1import { Before, After, AfterAll, setWorldConstructor } from "@cucumber/cucumber"
2import { createServer, ViteDevServer } from "vite"
3import * as playwright from 'playwright'
4
5// 啟動瀏覽器與建立伺服器
6const browser = playwright.chromium.launch()
7const server = createServer({ mode: "test" })
8
9export default class World {
10 // 紀錄目前測試的狀態
11 context: playwright.BrowserContext
12 page: playwright.Page
13 server: ViteDevServer
14
15 async init() {
16 // 啟動 Vite 伺服器
17 this.server = await (await server).listen()
18 // 建立新的瀏覽器設定檔,並且設定網址基準為 Vite 伺服器位置
19 this.context = await (await browser).newContext({
20 baseURL: this.server.resolvedUrls?.local[0],
21 });
22 // 開啟一個新的分頁
23 this.page = await this.context.newPage()
24 }
25
26 // 開啟特定路徑
27 async visit(path: string) {
28 await this.page.goto(path)
29 }
30}
31
32// 設定 Cucumber 使用 World 這個類別運行測試
33setWorldConstructor(World);
34
35// 在測試開始前進行初始化
36Before(async function() {
37 await this.init()
38})
39
40// 結束後關閉分頁與測試伺服器
41After(async function() {
42 await this.context.close()
43 await this.server.close()
44})
45
46// 所有測試結束後關閉瀏覽器
47AfterAll(async function() {
48 await (await browser).close()
49})
上面這段程式碼有點複雜,我們需要自己管理 Playwright 開啟的瀏覽器以及 Vite 的測試環境,同時每個測試都開啟新的瀏覽器也不太現實,因此會統一開啟一個瀏覽器直到所有測試都結束為止。
在 Playwright 的概念中,瀏覽器本身還有設定檔(
BrowserContext
)的功能,用 Chrome 舉例就是「個人資料」的機制,每個測試都開啟獨立的BrowserContext
可以確保不被 Cookie 等紀錄影響。
設定完畢後,我們就可以著手於撰寫 features/hello.feature
和 features/step_definitions/common.ts
這兩個檔案,來驗證我們的測試可以順利運行。
1Feature: Hello World
2 Scenario: I can test with Playwright
3 Then I can see "Vite"
1import { Then } from "@cucumber/cucumber"
2import { expect } from "@playwright/test"
3
4Then('I can see {string}', async function (string) {
5 await this.visit('/')
6 await expect(this.page).toHaveTitle(new RegExp(string))
7});
為了讓測試簡單被理解,我們可以做一個對網頁標題的檢查,這裡就可以直接引用 Playwright 的 expect
方法來進行斷言,這個好處是我們能直接使用到所有 Playwright 的測試 API,就不需要自己再額外的實作各種尋找 HTML 元素的行為。
現在運行 yarn run cucumber-js
就可以看到測試成功的結果。
1yarn run v1.22.19
2$ /Users/elct9620/Workspace/StarPortal/Cucumber2024/frontend/node_modules/.bin/cucumber-js
3...
4
51 scenario (1 passed)
61 step (1 passed)
70m01.678s (executing steps: 0m01.632s)
8✨ Done in 3.13s.
在 JavaScript 的生態系中測試框架的斷言有時候是能夠混用的,以 Vite 經常搭配使用的 Vitest 為例子,我們也可以用
@playwright/test
套件來取代原本的斷言功能,這樣就可以很輕鬆的用 Playwright 來實現 E2E Testing 而不需要使用多款工具搭配使用。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 同時完成測試與文件 - Cucumber 的文件測試法
- 基本語法:功能描述 - Cucumber 的文件測試法
- 基本語法:驗證行為 - Cucumber 的文件測試法
- 基本語法:步驟定義 - Cucumber 的文件測試法
- 基本語法:輔助設定 - Cucumber 的文件測試法
- 前端環境:Vite 與 Cucumber - Cucumber 的文件測試法
- 商品列表與加入購物車 - Cucumber 的文件測試法
- 重構與移出購物車 - Cucumber 的文件測試法
- 商品資料與總價 - Cucumber 的文件測試法
- 結帳與結果 - Cucumber 的文件測試法
- 整理前端實作 - Cucumber 的文件測試法
- 初始化後端專案 - Cucumber 的文件測試法
- 商品資料 API - Cucumber 的文件測試法
- 更新購物車 API - Cucumber 的文件測試法
- 加入資料模型 - Cucumber 的文件測試法
- 持久化保存 - Cucumber 的文件測試法
- 結帳處理 - Cucumber 的文件測試法
- 在 Rails 的前後端分離 - Cucumber 的文件測試法
- 匯入前端實作 - Cucumber 的文件測試法
- 重現後端實作 - Cucumber 的文件測試法
- 累積價值 - Cucumber 的文件測試法