iT邦幫忙

2025 iThome 鐵人賽

DAY 24
0
Vue.js

Vue 全攻略:30 天技能樹養成系列 第 24

【Day 24】換上使用者的眼鏡:用 Testing Library 玩「大家來找碴」

  • 分享至 

  • xImage
  •  

聯繫我

如果有任何問題或建議,歡迎隨時聯繫我:

前言

嘿,各位 Vue 的品質鑑定師!昨天我們扮演了一位「精密儀器技師」,拿著 @vue/test-utils 這個高科技放大鏡,仔細檢查元件的內部構造。

  • 「報告!這個元件的 class 清單裡,確實有 is-disabled!」
  • 「報告!使用者點擊後,click 事件確實有發射成功!」

這些測試非常精準,就像一份詳細的「零件出廠品管報告」。它證明了我們做的每個零件都符合規格。但...它能保證組裝起來的「成品」好用嗎?

試想一下:

一個拿到新手機的使用者,他才不管螢幕底下那顆按鈕的 class 叫什麼,他只在乎:「為什麼這個灰色的按鈕我按不下去?

一個想登入網站的使用者,他根本不知道什麼是 emit,他只關心:「我點了登入,然後呢?怎麼沒反應?

看到了嗎?「零件合格」跟「使用者覺得好用」之間,還有一段距離。

今天,我們要進行一個角色大轉變!我們要從「技師」變身為「真正的使用者」,甚至是一位挑剔的「秘密客」。我們要介紹的這位新夥伴——Testing Library,就是為此而生的。

它的核心精神,就像一句廣告詞:

「我們不只關心產品怎麼做出來的,我們更關心你用起來爽不爽!」

如果說昨天的測試是在「實驗室」裡做檢測,那今天的測試,就是把產品直接丟到「真實市場」去,讓使用者來一場貨真價實的「大家來找碴」!

1. Testing Library 的「換位思考」哲學

Testing Library 最酷的地方,就是它會故意「蒙上你的雙眼」,讓你沒辦法輕易看到元件的內部零件(像是 datapropsclass 名稱)。它強迫你戴上「使用者的眼鏡」,從他的視角來跟你的應用程式互動。

它鼓勵你這麼做:

  1. 像使用者一樣「找東西」:你不是用 idclass 這種開發者才知道的暗號去找按鈕。你得像個真人一樣,用眼睛去找「畫面上寫著『提交』的按鈕」、找「標籤是『使用者名稱』的輸入框」。

  2. 像使用者一樣「動手玩」:你不是冷冰冰地 trigger 一個點擊事件。你要模擬一個完整的人類行為,像是用滑鼠「點擊」那個按鈕,或是在輸入框裡「打字」。

  3. 像使用者一樣「看結果」:你不斷言某個變數變成 true。你斷言的是:「我點了登入後,畫面上是不是出現了『歡迎回來!』這句話?

這種轉變,就像是從「檢查食譜的每個步驟是否正確」變成「親口嚐嚐這道菜好不好吃」。

這樣寫出來的測試,會變得超級健壯!就算你今天心血來潮,把廚房(元件內部)整個大改造,換了鍋子、改了爐子,只要最後端出來的「宮保雞丁」味道還是對的,那「美食家」(測試)就會給你一個讚,測試照樣通過!這才是我們追求的終極目標:確保軟體真的能用!

2. 招募新夥伴:環境設定

要開始我們的「秘密客任務」,需要先招募幾位新夥伴:

  • @testing-library/vue: 我們的核心工具,Vue 專屬的「使用者眼鏡」。
  • @testing-library/user-event: 一位超強的「行為模仿大師」,能更逼真地模擬使用者點擊、打字等動作。
  • @testing-library/jest-dom: 一本「斷言字典」,提供更多符合直覺的判斷詞,例如 在不在畫面上()

用下面這行咒語把他們召喚過來:

npm install -D @testing-library/vue @testing-library/user-event @testing-library/jest-dom

為了讓我們的測試環境 Vitest 看得懂這本新字典,我們需要做個小小的設定。

建立 vitest.setup.js 於專案根目錄(如果還沒有的話):

// vitest.setup.js
// 告訴 Vitest:「嘿,記得帶上這本新字典喔!」
import { expect } from 'vitest';
import '@testing-library/jest-dom/vitest';

修改 vite.config.js,讓 Vitest 知道要去哪裡找這個設定檔:

// vite.config.js
/// <reference types="vitest" />
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  test: {
    globals: true,
    environment: 'jsdom',
    // 在這裡告訴 Vitest 我們的設定檔在哪
    setupFiles: ['./vitest.setup.js'],
  },
});

3. Testing Library 實戰演練

光說不練假把戲!讓我們用 Testing Library 來測試一個簡單的計數器元件。

我們的元件 (Counter.vue)

// src/components/Counter.vue
<template>
  <div>
    <p>當前計數:{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => count.value++;
</script>

我們的「使用者視角」測試 (Counter.spec.js)

import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import Counter from './Counter.vue';

describe('Counter.vue', () => {
  it('should display initial count and increment when button is clicked', async () => {
    // 1. 準備:把元件渲染到畫面上
    render(Counter);

    // 2. 找碴:像使用者一樣,用「看到的文字」去找元素
    // 找看看畫面上是不是有「當前計數:0」
    expect(screen.getByText('當前計數:0')).toBeInTheDocument();

    // 接著,找看看有沒有一個叫「增加」的按鈕
    const incrementButton = screen.getByRole('button', { name: '增加' });

    // 3. 互動:像使用者一樣,用滑鼠去「點」那個按鈕
    await userEvent.click(incrementButton);

    // 4. 驗收:看看結果是不是如預期
    // 畫面上的計數,是不是變成「當前計數:1」了?
    expect(screen.getByText('當前計數:1')).toBeInTheDocument();
    // 舊的計數是不是不見了?
    expect(screen.queryByText('當前計數:0')).not.toBeInTheDocument();
  });
});

看到了嗎?整個測試流程沒有一個 wrapper.find,沒有一個 .trigger,更沒有檢查 classid。整個過程就像在描述一位使用者如何與你的網頁互動,非常直觀!

本篇自我挑戰

  1. 建立一個簡單的 LoginForm.vue 元件:包含 email、password 兩個輸入框和一個「登入」按鈕。
  2. 撰寫測試:使用 @testing-library/vueuser-event
  3. 模擬使用者操作:在輸入框中打字,然後點擊按鈕。
  4. 斷言結果:(暫時) 你可以先讓按鈕點擊後顯示一段成功訊息,例如「登入成功!」,然後斷言這段訊息是否出現在畫面上。

總結

今天我們進行了一次重要的「思維轉換」。我們從關心「元件內部實現」的技師,轉變為關心「使用者真實體驗」的秘密客。

  • 我們理解了 Testing Library 的核心哲學:測試那些使用者關心的事,而不是你的實作細節。
  • 我們學會了如何使用 screen.getByRolescreen.getByText 等查詢方式,像真人一樣在畫面上找東西。
  • 我們掌握了用 userEvent 來模擬真實的使用者互動,例如點擊和打字。
  • 我們體會到這樣寫的測試,即使未來元件內部大重構,只要外在行為不變,測試就依然能通過,這大大降低了測試的維護成本。

掌握了 Testing Library,你就掌握了撰寫高價值、高穩定性前端測試的關鍵。你的測試不再是易碎的玻璃,而是堅固的護城河。

明天,我們將探討一個在真實世界中不可避免的議題:如何測試那些需要呼叫 API 的非同步元件。

本日關鍵字回顧

  • Testing Library
  • 使用者中心測試 (User-centric Testing)
  • getByRole, getByText
  • user-event
  • 行為測試 (Behavioral Testing)
  • 實作細節 (Implementation Details)
  • 健壯性 (Resilience)

上一篇
【Day 23】元件的X光片:深入測試 Props、事件與 Slot
下一篇
【Day 25】給測試一個乾淨的世界:Mocking API 請求
系列文
Vue 全攻略:30 天技能樹養成26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言