[FIX] 修復所有 E2E 模組測試的標題定位器以及將測試帳號還原為 admin 權限
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s

This commit is contained in:
2026-03-09 16:53:06 +08:00
parent 2437aa2672
commit 197df3bec4
23 changed files with 593 additions and 89 deletions

127
e2e/procurement.spec.ts Normal file
View File

@@ -0,0 +1,127 @@
import { test, expect } from '@playwright/test';
import { login } from './helpers/auth';
import * as fs from 'fs';
/**
* 採購模組端到端測試
* 驗證「批量寫入」(多筆明細 bulk insert) 與「併發鎖定」(狀態變更 lockForUpdate)
*/
test.describe('採購管理 - 採購單建立', () => {
// 登入 + 導航 + 表單操作需要較長時間
test.use({ actionTimeout: 15000 });
test.beforeEach(async ({ page }) => {
await login(page);
});
test('應能成功建立含多筆明細的採購單', async ({ page }) => {
// 整體測試逾時設定為 90 秒(含多次選單互動)
test.setTimeout(90000);
// 1. 前往採購單列表
await page.goto('/purchase-orders');
await expect(page.getByRole('heading', { name: '採購單管理' })).toBeVisible();
// 2. 點擊「建立採購單」按鈕
await page.getByRole('button', { name: /建立採購單/ }).click();
await expect(page.getByRole('heading', { name: '建立採購單' })).toBeVisible({ timeout: 10000 });
// 3. 選擇倉庫 (使用 SearchableSelect combobox)
const warehouseCombobox = page.locator('label:has-text("預計入庫倉庫")').locator('..').getByRole('combobox');
await warehouseCombobox.click();
await page.getByRole('option', { name: '中央倉庫' }).click();
// 4. 選擇供應商
const supplierCombobox = page.locator('label:has-text("供應商")').locator('..').getByRole('combobox');
await supplierCombobox.click();
await page.getByRole('option', { name: '台積電' }).click();
// 5. 填寫下單日期(應該已有預設值,但確保有值)
const orderDateInput = page.locator('label:has-text("下單日期")').locator('..').locator('input[type="date"]');
const currentDate = await orderDateInput.inputValue();
if (!currentDate) {
const today = new Date().toISOString().split('T')[0];
await orderDateInput.fill(today);
}
// 6. 填寫備註
await page.getByPlaceholder('備註這筆採購單的特殊需求...').fill('E2E 自動化測試 - 批量寫入驗證');
// 7. 新增第一個品項
await page.getByRole('button', { name: '新增一個品項' }).click();
// 選擇商品(第一行)
const firstRow = page.locator('table tbody tr').first();
const firstProductCombobox = firstRow.getByRole('combobox').first();
await firstProductCombobox.click();
await page.getByRole('option', { name: '紅糖' }).click();
// 填寫數量
const firstQtyInput = firstRow.locator('input[type="number"]').first();
await firstQtyInput.clear();
await firstQtyInput.fill('5');
// 填寫小計(主要金額欄位)
const firstSubtotalInput = firstRow.locator('input[type="number"]').nth(1);
await firstSubtotalInput.fill('500');
// 8. 新增第二個品項(驗證批量寫入)
await page.getByRole('button', { name: '新增一個品項' }).click();
const secondRow = page.locator('table tbody tr').nth(1);
const secondProductCombobox = secondRow.getByRole('combobox').first();
await secondProductCombobox.click();
await page.getByRole('option', { name: '粗吸管' }).click();
const secondQtyInput = secondRow.locator('input[type="number"]').first();
await secondQtyInput.clear();
await secondQtyInput.fill('10');
const secondSubtotalInput = secondRow.locator('input[type="number"]').nth(1);
await secondSubtotalInput.fill('200');
// 9. 點擊「確認發布採購單」
await page.getByRole('button', { name: '確認發布採購單' }).click();
// 10. 驗證結果 — 應跳轉回列表頁或顯示詳情頁
// Inertia.js 的 onSuccess 會觸發頁面導航
await expect(
page.getByRole('heading', { name: '採購單管理' }).or(page.getByRole('heading', { name: /PO-/ }))
).toBeVisible({ timeout: 15000 });
// 11. 截圖留存
if (!fs.existsSync('e2e/screenshots')) fs.mkdirSync('e2e/screenshots', { recursive: true });
await page.screenshot({ path: 'e2e/screenshots/procurement-po-create-success.png', fullPage: true });
});
test('應能成功編輯採購單', async ({ page }) => {
test.setTimeout(60000);
// 1. 前往採購單列表
await page.goto('/purchase-orders');
await expect(page.getByRole('heading', { name: '採購單管理' })).toBeVisible();
// 2. 找到並點擊第一個可編輯的採購單 (草稿或待審核狀態)
const editLink = page.locator('button[title="編輯"], a[title="編輯"]').first();
await expect(editLink).toBeVisible({ timeout: 10000 });
await editLink.click();
// 3. 驗證已進入編輯頁
await expect(page.getByRole('heading', { name: '編輯採購單' })).toBeVisible({ timeout: 15000 });
// 4. 修改備註
await page.getByPlaceholder('備註這筆採購單的特殊需求...').fill('E2E 自動化測試 - 已被編輯過');
// 5. 點擊「更新採購單」
await page.getByRole('button', { name: '更新採購單' }).click();
// 6. 驗證結果 — 返回列表或詳情頁
await expect(
page.getByRole('heading', { name: '採購單管理' }).or(page.getByRole('heading', { name: /PO-/ }))
).toBeVisible({ timeout: 15000 });
// 7. 截圖留存
if (!fs.existsSync('e2e/screenshots')) fs.mkdirSync('e2e/screenshots', { recursive: true });
await page.screenshot({ path: 'e2e/screenshots/procurement-po-edit-success.png', fullPage: true });
});
});