---
title: "前端環境：Vite 與 Cucumber - Cucumber 的文件測試法"
date: 2024-02-09T00:00:00+08:00
publishDate: 2024-02-09T00:00:00+08:00
lastmod: 2023-12-06T15:50:15+08:00
tags: ["Cucumber","教學","測試","前端","Vite","Vue","Playwright"]
series: "test-with-cucumber"
toc: true
permalink: "https://blog.aotoki.me/posts/2024/02/09/test-with-cucumber-use-with-vite/"
language: "zh-tw"
---


因為 Cucumber 是能夠跨越不同開發環境使用的，因此這次我們會以前端與後端互相搭配的方式進行，在前端的部分採用 Vite 和 Playwright 來進行測試。

<!--more-->

## Vite 安裝{#setup-vite}

Vite 是非常輕量的工具，也有 [Vite Ruby](https://vite-ruby.netlify.app/) 可以跟 Ruby 的專案一起使用，這一次我們會使用 Vue 與 TypeScript 和 Cucumber 搭配開發，因此我們需要先建立一個前端的專案供我們使用。

```bash
yarn create frontend --template vue-ts
```

如果習慣使用 `npm` 或者 `pnpm` 等工具，也可以依照[官方文件](https://vitejs.dev/guide/)的指示選擇使用自己習慣的套件管理工具。

## Cucumber 安裝{#setup-cucumber}

要安裝 Cucumber 只需要透過套件管理工具加入到 `package.json` 即可，除了 Cucumber 之外，我們還希望有 [Playwright](https://playwright.dev/) 來模擬使用真實瀏覽器操作的狀況，因此一起將兩個套件加入。

```bash
yarn add --dev @cucumber/cucumber playwright @playwright/test
```

Playwright 本身就有運行測試的功能，因為我們希望讓 Cucumber 來扮演這個角色，因此需要另外加入 `@playwright/test` 這個套件，用來實現斷言相關的機制。

完成之後我們可以簡單用 `yarn run` 命令驗證 Cucumber 正常運作。

```bash
yarn run cucumber-js
```

接下來我們要將 Cucumber 設定為會使用 Playwright 開啟瀏覽器以及 Vite 預覽伺服器的模式，來讓我們可以測試到真實的 Vite 專案。

## 環境設定{#setup-environment}

Cucumber 針對前端的測試基本上有幾種方式，比較直覺的做法是先進行 `yarn build`（建置）之後直接使用靜態的檔案處理，另外一個就是我們直接利用 Vite 的 `createServer` API 啟動一個測試用的環境來運行。

首先，我們先在專案目錄下加入 `cucumber.js` 來設定我們的測試環境。

```js
export default {
  publishQuiet: true,
  requireModule: ['tsm'],
  require: [
    'features/**/*.ts'
  ],
  strict: true,
  tags: 'not @wip',
}
```

為了讓 TypeScript 可以被 Cucumber 辨識到，我們可以使用 `requireModule` 的選項載入對應的模組，像是 `tsm` 或者 `ts-node` 等等，可以依照自己的偏好選擇。

接下來要讓 Playwright 在測試開始時啟動瀏覽器，以及使用 Vite 的 API 來運行一個測試用的環境，我們加入 `features/support/world.ts` 這個檔案來進行定義。

> 因為用 `features/**/*.ts` 定義了要自動載入的路徑，我們這邊使用大多數 Cucumber 的慣例將環境設定相關的檔案放到 `features/support` 目錄下

```ts
import { Before, After, AfterAll, setWorldConstructor } from "@cucumber/cucumber"
import { createServer, ViteDevServer } from "vite"
import * as playwright from 'playwright'

// 啟動瀏覽器與建立伺服器
const browser = playwright.chromium.launch()
const server = createServer({ mode: "test" })

export default class World {
  // 紀錄目前測試的狀態
  context: playwright.BrowserContext
  page: playwright.Page
  server: ViteDevServer

  async init() {
    // 啟動 Vite 伺服器
    this.server = await (await server).listen()
    // 建立新的瀏覽器設定檔，並且設定網址基準為 Vite 伺服器位置
    this.context = await (await browser).newContext({
      baseURL: this.server.resolvedUrls?.local[0],
    });
    // 開啟一個新的分頁
    this.page = await this.context.newPage()
  }

  // 開啟特定路徑
  async visit(path: string) {
    await this.page.goto(path)
  }
}

// 設定 Cucumber 使用 World 這個類別運行測試
setWorldConstructor(World);

// 在測試開始前進行初始化
Before(async function() {
  await this.init()
})

// 結束後關閉分頁與測試伺服器
After(async function() {
  await this.context.close()
  await this.server.close()
})

// 所有測試結束後關閉瀏覽器
AfterAll(async function() {
  await (await browser).close()
})
```

上面這段程式碼有點複雜，我們需要自己管理 Playwright 開啟的瀏覽器以及 Vite 的測試環境，同時每個測試都開啟新的瀏覽器也不太現實，因此會統一開啟一個瀏覽器直到所有測試都結束為止。

> 在 Playwright 的概念中，瀏覽器本身還有設定檔（`BrowserContext`）的功能，用 Chrome 舉例就是「個人資料」的機制，每個測試都開啟獨立的 `BrowserContext` 可以確保不被 Cookie 等紀錄影響。

設定完畢後，我們就可以著手於撰寫 `features/hello.feature` 和 `features/step_definitions/common.ts` 這兩個檔案，來驗證我們的測試可以順利運行。

```gherkin
Feature: Hello World
  Scenario: I can test with Playwright
    Then I can see "Vite"
```

```ts
import { Then } from "@cucumber/cucumber"
import { expect } from "@playwright/test"

Then('I can see {string}', async function (string) {
  await this.visit('/')
  await expect(this.page).toHaveTitle(new RegExp(string))
});
```

為了讓測試簡單被理解，我們可以做一個對網頁標題的檢查，這裡就可以直接引用 Playwright 的 `expect` 方法來進行斷言，這個好處是我們能直接使用到所有 Playwright 的測試 API，就不需要自己再額外的實作各種尋找 HTML 元素的行為。

現在運行 `yarn run cucumber-js` 就可以看到測試成功的結果。

```bash
yarn run v1.22.19
$ /Users/elct9620/Workspace/StarPortal/Cucumber2024/frontend/node_modules/.bin/cucumber-js
...

1 scenario (1 passed)
1 step (1 passed)
0m01.678s (executing steps: 0m01.632s)
✨  Done in 3.13s.
```

> 在 JavaScript 的生態系中測試框架的斷言有時候是能夠混用的，以 Vite 經常搭配使用的 Vitest 為例子，我們也可以用 `@playwright/test` 套件來取代原本的斷言功能，這樣就可以很輕鬆的用 Playwright 來實現 E2E Testing 而不需要使用多款工具搭配使用。

