US-001: 用戶登入 - 手動測試指南
測試日期: ____________ 測試人員: ____________ 測試環境:
npm run dev(localhost:3000)
測試前準備
1. 啟動開發伺服器
npm run dev
2. 測試帳號
系統預設的測試帳號(參考 src/mocks/data/seeds.ts):
| 角色 | 用戶名 | 密碼 |
|---|---|---|
| 店主 | owner@florist.com | Password123! |
| 店員 | staff@florist.com | Password123! |
| 設計師 | designer@florist.com | Password123! |
| 送貨員 | delivery@florist.com | Password123! |
測試場景
✅ Scenario 1: 使用有效憑證登入成功(正常流程)
目標: 驗證完整的登入流程
操作步驟
-
訪問登入頁面
- 在瀏覽器訪問
http://localhost:3000/login - ✅ 驗證: 看到品牌識別區(Logo 圖示、「花店管理系統」標題)
- ✅ 驗證: 看到登入表單卡片(歡迎文字、用戶名、密碼、記住我、登入按鈕)
- ✅ 驗證: 開發環境下看到測試帳號提示(藍色 info 區塊)
- 在瀏覽器訪問
-
輸入有效憑證
- 用戶名:
staff@florist.com(或直接點擊測試帳號提示) - 密碼:
Password123! - 不勾選「記住我」
- 用戶名:
-
測試密碼顯示切換
- 點擊密碼欄位右側的眼睛圖示(👁)
- ✅ 驗證: 密碼從圓點顯示變為明文顯示
- ✅ 驗證: 圖示從 Eye 變為 EyeOff
- 再次點擊切換回密碼模式
-
提交登入
- 點擊「登入」按鈕
- ✅ 驗證: 按鈕顯示 spinner + 「登入中...」文字
- ✅ 驗證: 按鈕在載入期間為 disabled 狀態
-
驗證登入成功
- ✅ 驗證: 看到 Toast 通知「登入成功!」(綠色)
- ✅ 驗證: 約 500ms 後頁面重定向至首頁
/ - ✅ 驗證: Header 右上角顯示用戶資訊(頭像、姓名)
- ✅ 驗證: Application Launcher 可用(根據角色顯示對應 Applet)
- ✅ 驗證: URL 位於首頁(不在登入頁面)
-
檢查 Token 儲存
- 打開瀏覽器開發者工具 (F12) → Application/儲存空間
- ✅ 驗證: Redux DevTools 中可見
iam.me.authorization.access_token - ✅ 驗證: Console 沒有錯誤訊息
-
檢查審計日誌
- 打開 Console 頁籤
- ✅ 驗證: 看到類似以下日誌:
[AUDIT] Login successful: staff@florist.com (role: ROLE_SALES)
預期結果
- ✅ 登入成功
- ✅ Toast 通知顯示
- ✅ Token 正確儲存
- ✅ 頁面重定向
- ✅ 用戶資訊正確顯示
- ✅ 審計日誌記錄
✅ Scenario 2: 使用錯誤密碼登入失敗
目標: 驗證錯誤密碼的處理
操作步驟
- 訪問
http://localhost:3000/login - 輸入用戶名:
staff@florist.com - 輸入錯誤密碼:
WrongPassword123 - 點擊「登入」按鈕
- ✅ 驗證: 看到錯誤訊息「用戶名或密碼錯誤」
- ✅ 驗證: 用戶名欄位保留輸入值
- ✅ 驗證: 密碼欄位保留輸入值(方便用戶修改錯字)
- ✅ 驗證: 仍停留在登入頁面
- ✅ 驗證: 未儲存 access_token(檢查 localStorage)
預期結果
- ✅ 顯示錯誤訊息
- ✅ 表單狀態正確
- ✅ 未發放 Token
✅ Scenario 3: 使用不存在的用戶名登入失敗
目標: 驗證不存在的用戶處理(防止用戶枚舉攻擊)
操作步驟
- 訪問
http://localhost:3000/login - 輸入不存在的用戶名:
nonexistent@example.com - 輸入任意密碼:
Password123! - 點擊「登入」按鈕
- ✅ 驗證: 看到錯誤訊息「用戶名或密碼錯誤」(與 Scenario 2 相同)
- ✅ 驗證: 錯誤訊息不洩漏用戶是否存在
預期結果
- ✅ 錯誤訊息與錯誤密碼相同
- ✅ 不洩漏用戶存在資訊
✅ Scenario 4: 使用「記住我」功能登入
目標: 驗證「記住我」功能(Token 儲存位置與有效期)
安全設計說明:
- 勾選記住我 → Token 存
localStorage(關閉瀏覽器後保留,適合個人電腦) - 不勾選 → Token 存
sessionStorage(關閉瀏覽器即清除,適合公用電腦)
操作步驟
-
勾選「記住我」登入
- 訪問
http://localhost:3000/login - 輸入用戶名:
staff@florist.com - 輸入密碼:
Password123! - 勾選「記住我」
- 點擊「登入」按鈕
- ✅ 驗證: 登入成功
- 訪問
-
檢查 Token 儲存位置
- 打開 DevTools → Application → Storage
- ✅ 驗證:
localStorage中有access_token、refresh_token - ✅ 驗證:
localStorage中auth_storage_type=local - ✅ 驗證:
sessionStorage中沒有 token
-
關閉瀏覽器後重新開啟
- 完全關閉瀏覽器(非只關閉分頁)
- 重新開啟瀏覽器,訪問
http://localhost:3000 - ✅ 驗證: 仍保持登入狀態(不需重新登入)
-
登出後測試「不勾選記住我」
- 點擊右上角用戶選單 → 「登出」
- 重新登入,這次不勾選「記住我」
- ✅ 驗證:
sessionStorage中有access_token、refresh_token - ✅ 驗證:
localStorage中auth_storage_type=session - ✅ 驗證:
localStorage中沒有access_token
-
關閉瀏覽器後驗證自動登出
- 完全關閉瀏覽器
- 重新開啟瀏覽器,訪問
http://localhost:3000 - ✅ 驗證: 已自動登出,重定向至登入頁面
預期結果
- ✅ 勾選記住我 → Token 存 localStorage,關閉瀏覽器後保留
- ✅ 不勾選 → Token 存 sessionStorage,關閉瀏覽器自動登出
- ✅ Refresh Token 有效期:勾選 30 天 / 不勾選 7 天
✅ Scenario 5: 登入失敗 5 次後帳號鎖定
目標: 驗證 Rate Limiting 機制
操作步驟
-
連續輸入錯誤密碼 5 次
- 訪問
http://localhost:3000/login - 輸入用戶名:
staff@florist.com - 輸入錯誤密碼:
WrongPassword - 點擊「登入」(重複 5 次)
- 訪問
-
驗證帳號鎖定
- ✅ 驗證: 第 5 次失敗後,看到錯誤訊息「帳號已被鎖定,請 15 分鐘後再試」
- ✅ 驗證: 錯誤訊息顯示為紅色警告框
-
嘗試使用正確密碼登入
- 輸入用戶名:
staff@florist.com - 輸入正確密碼:
Password123! - 點擊「登入」
- ✅ 驗證: 仍然看到「帳號已被鎖定」錯誤訊息
- ✅ 驗證: 無法登入
- 輸入用戶名:
-
檢查審計日誌
- 打開 Console
- ✅ 驗證: 看到類似以下日誌:
[AUDIT] Account locked: staff@florist.com (5 failed attempts)
-
等待 15 分鐘後重試(可選)
- 等待 15 分鐘(或修改系統時間)
- 再次嘗試登入
- ✅ 驗證: 可以成功登入
預期結果
- ✅ 5 次失敗後帳號鎖定
- ✅ 鎖定期間無法登入
- ✅ 審計日誌記錄
- ✅ 15 分鐘後自動解鎖
✅ Scenario 6: 表單驗證 - 必填欄位為空
目標: 驗證前端表單驗證
操作步驟
- 訪問
http://localhost:3000/login - 不填寫任何欄位,直接點擊「登入」按鈕
- ✅ 驗證: 用戶名欄位顯示錯誤訊息「請輸入用戶名」
- ✅ 驗證: 密碼欄位顯示錯誤訊息「請輸入密碼」
- ✅ 驗證: 錯誤欄位顯示紅色邊框
- ✅ 驗證: 未發送 API 請求(檢查 Network 面板)
預期結果
- ✅ 前端驗證攔截空欄位
- ✅ 顯示清晰的錯誤訊息
- ✅ 未發送 API 請求
✅ Scenario 7: 鍵盤操作(無障礙性)
目標: 驗證鍵盤導航功能
操作步驟
-
訪問
http://localhost:3000/login -
使用 Tab 鍵導航
- 按 Tab → 焦點移至用戶名欄位
- ✅ 驗證: 用戶名欄位顯示焦點指示(藍色邊框)
- 按 Tab → 焦點移至密碼欄位
- ✅ 驗證: 密碼欄位顯示焦點指示
- 按 Tab → 焦點移至「記住我」勾選框
- 按 Tab → 焦點移至「登入」按鈕
-
使用 Enter 鍵提交
- 在用戶名欄位輸入
staff@florist.com - 按 Tab 移至密碼欄位
- 輸入密碼
Password123! - 按 Enter 鍵
- ✅ 驗證: 表單提交(與點擊按鈕效果相同)
- 在用戶名欄位輸入
預期結果
- ✅ Tab 鍵導航順序正確
- ✅ 焦點指示清晰
- ✅ Enter 鍵可提交表單
✅ Scenario 8: 響應式設計(手機版)
目標: 驗證手機版佈局
操作步驟
- 打開開發者工具 (F12)
- 切換至裝置模擬模式(Device Toolbar)
- 選擇「iPhone SE」或「iPhone 12 Pro」
- 訪問
http://localhost:3000/login - ✅ 驗證: 表單在手機螢幕正常顯示
- ✅ 驗證: 按鈕大小適合手指點擊(至少 44x44px)
- ✅ 驗證: 文字清晰可讀(字體不會太小)
- ✅ 驗證: 沒有橫向捲軸
預期結果
- ✅ 手機版佈局正確
- ✅ 可用性良好
✅ Scenario 9: 已登入用戶訪問登入頁面
目標: 驗證重定向邏輯
操作步驟
- 先完成登入(參考 Scenario 1)
- ✅ 驗證: 已在首頁
/ - 在瀏覽器網址列輸入
http://localhost:3000/login - ✅ 驗證: 自動重定向至首頁
/(不顯示登入表單)
預期結果
- ✅ 已登入用戶無法訪問登入頁面
- ✅ 自動重定向至首頁
✅ Scenario 10: 登出功能
目標: 驗證登出邏輯
操作步驟
- 先完成登入(參考 Scenario 1)
- 點擊右上角用戶選單
- ✅ 驗證: 看到下拉選單(個人設定、登出)
- 點擊「登出」
- ✅ 驗證: 重定向至登入頁面
/login - 打開開發者工具 → Application/儲存空間
- ✅ 驗證: localStorage 中的
access_token已清除 - 嘗試訪問受保護頁面(如
/orders) - ✅ 驗證: 自動重定向至登入頁面
預期結果
- ✅ 登出成功
- ✅ Token 已清除
- ✅ 無法訪問受保護頁面
測試檢查清單
完成所有測試場景後,請勾選以下項目:
基本功能
- Scenario 1: 有效憑證登入成功
- Scenario 2: 錯誤密碼登入失敗
- Scenario 3: 不存在的用戶名登入失敗
- Scenario 4: 記住我功能
- Scenario 5: 帳號鎖定機制
- Scenario 6: 表單驗證(空欄位)
- Scenario 7: 鍵盤操作
- Scenario 8: 響應式設計
- Scenario 9: 已登入用戶重定向
- Scenario 10: 登出功能
UI/UX
- 表單佈局清晰易懂
- 錯誤訊息顯示在正確位置
- 載入狀態顯示正確(按鈕顯示「登入中...」)
- 響應式設計(桌面、手機)
- DaisyUI 語義色彩正確應用
- 焦點指示清晰(Tab 導航)
安全性
- 密碼欄位不顯示明文
- 錯誤訊息不洩漏用戶存在資訊
- Rate Limiting 正常運作(5 次失敗鎖定)
- Token 儲存位置正確(localStorage)
- 審計日誌記錄正確
API
- POST /api/v1/auth/login 正常運作
- 錯誤響應格式正確
- Console 審計日誌記錄正確
已知問題
記錄測試過程中發現的問題:
測試結論
- 測試通過: ☐ 是 / ☐ 否
- 備註: ___________________________________________________________
- 測試人員簽名: ________________ 日期: ________________
最後更新: 2025-12-10