|
@@ -1,3 +1,4 @@
|
|
|
|
|
+import { TIMEOUTS } from '../../utils/timeouts';
|
|
|
import { Page, Locator } from '@playwright/test';
|
|
import { Page, Locator } from '@playwright/test';
|
|
|
import { selectRadixOption } from '@d8d/e2e-test-utils';
|
|
import { selectRadixOption } from '@d8d/e2e-test-utils';
|
|
|
|
|
|
|
@@ -185,9 +186,9 @@ export class OrderManagementPage {
|
|
|
await this.page.goto('/admin/orders');
|
|
await this.page.goto('/admin/orders');
|
|
|
await this.page.waitForLoadState('domcontentloaded');
|
|
await this.page.waitForLoadState('domcontentloaded');
|
|
|
// 等待页面标题出现
|
|
// 等待页面标题出现
|
|
|
- await this.pageTitle.waitFor({ state: 'visible', timeout: 15000 });
|
|
|
|
|
|
|
+ await this.pageTitle.waitFor({ state: 'visible', timeout: TIMEOUTS.PAGE_LOAD });
|
|
|
// 等待表格数据加载
|
|
// 等待表格数据加载
|
|
|
- await this.page.waitForSelector('table tbody tr', { state: 'visible', timeout: 20000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('table tbody tr', { state: 'visible', timeout: TIMEOUTS.PAGE_LOAD_LONG });
|
|
|
await this.expectToBeVisible();
|
|
await this.expectToBeVisible();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -195,8 +196,8 @@ export class OrderManagementPage {
|
|
|
* 验证页面关键元素可见
|
|
* 验证页面关键元素可见
|
|
|
*/
|
|
*/
|
|
|
async expectToBeVisible() {
|
|
async expectToBeVisible() {
|
|
|
- await this.pageTitle.waitFor({ state: 'visible', timeout: 15000 });
|
|
|
|
|
- await this.addOrderButton.waitFor({ state: 'visible', timeout: 10000 });
|
|
|
|
|
|
|
+ await this.pageTitle.waitFor({ state: 'visible', timeout: TIMEOUTS.PAGE_LOAD });
|
|
|
|
|
+ await this.addOrderButton.waitFor({ state: 'visible', timeout: TIMEOUTS.TABLE_LOAD });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 搜索和筛选功能 =====
|
|
// ===== 搜索和筛选功能 =====
|
|
@@ -209,7 +210,7 @@ export class OrderManagementPage {
|
|
|
await this.searchInput.fill(name);
|
|
await this.searchInput.fill(name);
|
|
|
await this.searchButton.click();
|
|
await this.searchButton.click();
|
|
|
await this.page.waitForLoadState('networkidle');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -218,7 +219,7 @@ export class OrderManagementPage {
|
|
|
async openFilterDialog() {
|
|
async openFilterDialog() {
|
|
|
const filterButton = this.page.getByRole('button', { name: /筛选|高级筛选/ });
|
|
const filterButton = this.page.getByRole('button', { name: /筛选|高级筛选/ });
|
|
|
await filterButton.click();
|
|
await filterButton.click();
|
|
|
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -287,7 +288,7 @@ export class OrderManagementPage {
|
|
|
const applyButton = this.page.getByRole('button', { name: /应用|确定|筛选/ });
|
|
const applyButton = this.page.getByRole('button', { name: /应用|确定|筛选/ });
|
|
|
await applyButton.click();
|
|
await applyButton.click();
|
|
|
await this.page.waitForLoadState('networkidle');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -296,7 +297,7 @@ export class OrderManagementPage {
|
|
|
async clearFilters() {
|
|
async clearFilters() {
|
|
|
const clearButton = this.page.getByRole('button', { name: /重置|清空/ });
|
|
const clearButton = this.page.getByRole('button', { name: /重置|清空/ });
|
|
|
await clearButton.click();
|
|
await clearButton.click();
|
|
|
- await this.page.waitForTimeout(500);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 订单 CRUD 操作 =====
|
|
// ===== 订单 CRUD 操作 =====
|
|
@@ -306,7 +307,7 @@ export class OrderManagementPage {
|
|
|
*/
|
|
*/
|
|
|
async openCreateDialog() {
|
|
async openCreateDialog() {
|
|
|
await this.addOrderButton.click();
|
|
await this.addOrderButton.click();
|
|
|
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -322,11 +323,11 @@ export class OrderManagementPage {
|
|
|
// 等待菜单出现并点击"编辑"选项
|
|
// 等待菜单出现并点击"编辑"选项
|
|
|
// 使用 data-testid 或 role 定位编辑选项
|
|
// 使用 data-testid 或 role 定位编辑选项
|
|
|
const editOption = this.page.getByRole('menuitem', { name: '编辑' });
|
|
const editOption = this.page.getByRole('menuitem', { name: '编辑' });
|
|
|
- await editOption.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
|
|
|
+ await editOption.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
await editOption.click();
|
|
await editOption.click();
|
|
|
|
|
|
|
|
// 等待编辑对话框出现
|
|
// 等待编辑对话框出现
|
|
|
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -341,11 +342,11 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 等待菜单出现并点击"删除"选项
|
|
// 等待菜单出现并点击"删除"选项
|
|
|
const deleteOption = this.page.getByRole('menuitem', { name: '删除' });
|
|
const deleteOption = this.page.getByRole('menuitem', { name: '删除' });
|
|
|
- await deleteOption.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
|
|
|
+ await deleteOption.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
await deleteOption.click();
|
|
await deleteOption.click();
|
|
|
|
|
|
|
|
// 等待删除确认对话框出现
|
|
// 等待删除确认对话框出现
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -354,7 +355,7 @@ export class OrderManagementPage {
|
|
|
*/
|
|
*/
|
|
|
async fillOrderForm(data: OrderData) {
|
|
async fillOrderForm(data: OrderData) {
|
|
|
// 等待表单出现
|
|
// 等待表单出现
|
|
|
- await this.page.waitForSelector('form', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('form', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
|
|
|
// 填写订单名称
|
|
// 填写订单名称
|
|
|
if (data.name) {
|
|
if (data.name) {
|
|
@@ -437,7 +438,7 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 等待网络请求完成(使用较宽松的超时,因为有些操作可能不触发网络请求)
|
|
// 等待网络请求完成(使用较宽松的超时,因为有些操作可能不触发网络请求)
|
|
|
try {
|
|
try {
|
|
|
- await this.page.waitForLoadState('domcontentloaded', { timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForLoadState('domcontentloaded', { timeout: TIMEOUTS.DIALOG });
|
|
|
} catch {
|
|
} catch {
|
|
|
// domcontentloaded 超时不是致命错误,继续检查 Toast 消息
|
|
// domcontentloaded 超时不是致命错误,继续检查 Toast 消息
|
|
|
console.debug('domcontentloaded 超时,继续检查 Toast 消息');
|
|
console.debug('domcontentloaded 超时,继续检查 Toast 消息');
|
|
@@ -448,7 +449,7 @@ export class OrderManagementPage {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 等待 Toast 消息显示
|
|
// 等待 Toast 消息显示
|
|
|
- await this.page.waitForTimeout(2000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.VERY_LONG);
|
|
|
|
|
|
|
|
// 检查 Toast 消息
|
|
// 检查 Toast 消息
|
|
|
const errorToast = this.page.locator('[data-sonner-toast][data-type="error"]');
|
|
const errorToast = this.page.locator('[data-sonner-toast][data-type="error"]');
|
|
@@ -491,7 +492,7 @@ export class OrderManagementPage {
|
|
|
*/
|
|
*/
|
|
|
async waitForDialogClosed() {
|
|
async waitForDialogClosed() {
|
|
|
// 先等待一段时间让对话框有机会关闭
|
|
// 先等待一段时间让对话框有机会关闭
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
|
|
|
|
|
// 检查是否还有对话框可见
|
|
// 检查是否还有对话框可见
|
|
|
const dialogs = this.page.locator('[role="dialog"]');
|
|
const dialogs = this.page.locator('[role="dialog"]');
|
|
@@ -505,14 +506,14 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 尝试等待对话框隐藏或从 DOM 中移除
|
|
// 尝试等待对话框隐藏或从 DOM 中移除
|
|
|
try {
|
|
try {
|
|
|
- await dialogs.first().waitFor({ state: 'hidden', timeout: 3000 });
|
|
|
|
|
|
|
+ await dialogs.first().waitFor({ state: 'hidden', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
console.debug('对话框已关闭');
|
|
console.debug('对话框已关闭');
|
|
|
} catch {
|
|
} catch {
|
|
|
// 超时不是致命错误,对话框可能已经以其他方式关闭
|
|
// 超时不是致命错误,对话框可能已经以其他方式关闭
|
|
|
console.debug('对话框关闭等待超时,继续执行');
|
|
console.debug('对话框关闭等待超时,继续执行');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await this.page.waitForTimeout(500);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -525,10 +526,10 @@ export class OrderManagementPage {
|
|
|
});
|
|
});
|
|
|
await confirmButton.click();
|
|
await confirmButton.click();
|
|
|
// 等待确认对话框关闭和网络请求完成
|
|
// 等待确认对话框关闭和网络请求完成
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: TIMEOUTS.DIALOG })
|
|
|
.catch(() => console.debug('删除确认对话框关闭超时'));
|
|
.catch(() => console.debug('删除确认对话框关闭超时'));
|
|
|
- await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD });
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -539,7 +540,7 @@ export class OrderManagementPage {
|
|
|
this.page.locator('[role="alertdialog"]')
|
|
this.page.locator('[role="alertdialog"]')
|
|
|
);
|
|
);
|
|
|
await cancelButton.click();
|
|
await cancelButton.click();
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: TIMEOUTS.DIALOG })
|
|
|
.catch(() => console.debug('删除确认对话框关闭超时(取消操作)'));
|
|
.catch(() => console.debug('删除确认对话框关闭超时(取消操作)'));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -568,17 +569,18 @@ export class OrderManagementPage {
|
|
|
await menuTrigger.click();
|
|
await menuTrigger.click();
|
|
|
|
|
|
|
|
// 等待菜单显示
|
|
// 等待菜单显示
|
|
|
- await this.page.waitForTimeout(200);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.VERY_SHORT);
|
|
|
|
|
|
|
|
// 点击"查看详情"菜单项
|
|
// 点击"查看详情"菜单项
|
|
|
const detailButton = this.page.getByRole('menuitem', { name: /查看详情/ });
|
|
const detailButton = this.page.getByRole('menuitem', { name: /查看详情/ });
|
|
|
await detailButton.click();
|
|
await detailButton.click();
|
|
|
|
|
|
|
|
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
- * 获取订单详情中的基本信息
|
|
|
|
|
|
|
+ * 获取订单详情对话框中的基本信息
|
|
|
* @returns 订单基本信息
|
|
* @returns 订单基本信息
|
|
|
*/
|
|
*/
|
|
|
async getOrderDetailInfo(): Promise<{
|
|
async getOrderDetailInfo(): Promise<{
|
|
@@ -593,41 +595,54 @@ export class OrderManagementPage {
|
|
|
const dialog = this.page.locator('[role="dialog"]');
|
|
const dialog = this.page.locator('[role="dialog"]');
|
|
|
const result: Record<string, string | undefined> = {};
|
|
const result: Record<string, string | undefined> = {};
|
|
|
|
|
|
|
|
- // 辅助函数:通过标签文本获取对应值
|
|
|
|
|
- // DOM 结构: generic (field row) > generic (label) + generic (value)
|
|
|
|
|
- const getValueByLabel = async (labelText: string | RegExp): Promise<string | undefined> => {
|
|
|
|
|
- const label = dialog.locator('generic').filter({ hasText: labelText }).first();
|
|
|
|
|
- if (await label.count() > 0) {
|
|
|
|
|
- // 使用 XPath 获取下一个兄弟 generic 元素(值元素)
|
|
|
|
|
- const value = label.locator('xpath=following-sibling::generic');
|
|
|
|
|
- if (await value.count() > 0) {
|
|
|
|
|
- const text = await value.textContent();
|
|
|
|
|
- return text?.trim() || undefined;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return undefined;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 订单名称 - 查找"订单名称:"标签后的值
|
|
|
|
|
- result.name = await getValueByLabel('订单名称:');
|
|
|
|
|
|
|
+ // 使用 data-testid 直接定位元素(更可靠)
|
|
|
|
|
+ // DOM 结构: <div className="flex items-center justify-between">
|
|
|
|
|
+ // <span className="text-sm font-medium">标签:</span>
|
|
|
|
|
+ // <span data-testid="order-detail-xxx">值</span>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+
|
|
|
|
|
+ // 订单名称 - 使用 data-testid
|
|
|
|
|
+ const nameElement = dialog.locator('[data-testid="order-detail-name"]');
|
|
|
|
|
+ if (await nameElement.count() > 0) {
|
|
|
|
|
+ result.name = (await nameElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 订单状态
|
|
// 订单状态
|
|
|
- result.status = await getValueByLabel('订单状态:');
|
|
|
|
|
|
|
+ const statusElement = dialog.locator('[data-testid="order-detail-status"]');
|
|
|
|
|
+ if (await statusElement.count() > 0) {
|
|
|
|
|
+ result.status = (await statusElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 工作状态
|
|
|
|
|
- result.workStatus = await getValueByLabel('工作状态:');
|
|
|
|
|
|
|
+ // 工作状态 - 查找包含"工作状态"标签的行
|
|
|
|
|
+ const workStatusRow = dialog.locator('div').filter({ hasText: /工作状态:/ }).first();
|
|
|
|
|
+ if (await workStatusRow.count() > 0) {
|
|
|
|
|
+ const workStatusElement = workStatusRow.locator('span').nth(1);
|
|
|
|
|
+ result.workStatus = (await workStatusElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 预计开始日期
|
|
|
|
|
- result.expectedStartDate = await getValueByLabel(/预计开始日期:|开始日期:/);
|
|
|
|
|
|
|
+ // 预计开始日期 - 使用 data-testid
|
|
|
|
|
+ const expectedStartDateElement = dialog.locator('[data-testid="order-detail-expected-start"]');
|
|
|
|
|
+ if (await expectedStartDateElement.count() > 0) {
|
|
|
|
|
+ result.expectedStartDate = (await expectedStartDateElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 平台
|
|
|
|
|
- result.platform = await getValueByLabel('平台:');
|
|
|
|
|
|
|
+ // 平台 - 使用 data-testid
|
|
|
|
|
+ const platformElement = dialog.locator('[data-testid="order-detail-platform"]');
|
|
|
|
|
+ if (await platformElement.count() > 0) {
|
|
|
|
|
+ result.platform = (await platformElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 公司
|
|
|
|
|
- result.company = await getValueByLabel('公司:');
|
|
|
|
|
|
|
+ // 公司 - 使用 data-testid
|
|
|
|
|
+ const companyElement = dialog.locator('[data-testid="order-detail-company"]');
|
|
|
|
|
+ if (await companyElement.count() > 0) {
|
|
|
|
|
+ result.company = (await companyElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 渠道
|
|
|
|
|
- result.channel = await getValueByLabel('渠道:');
|
|
|
|
|
|
|
+ // 渠道 - 使用 data-testid
|
|
|
|
|
+ const channelElement = dialog.locator('[data-testid="order-detail-channel"]');
|
|
|
|
|
+ if (await channelElement.count() > 0) {
|
|
|
|
|
+ result.channel = (await channelElement.textContent())?.trim();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
@@ -868,7 +883,7 @@ export class OrderManagementPage {
|
|
|
// 点击添加人员按钮
|
|
// 点击添加人员按钮
|
|
|
const addButton = this.page.getByRole('button', { name: /添加人员|新增人员/ });
|
|
const addButton = this.page.getByRole('button', { name: /添加人员|新增人员/ });
|
|
|
await addButton.click();
|
|
await addButton.click();
|
|
|
- await this.page.waitForTimeout(300);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
|
|
|
|
|
// 选择残疾人(支持通过名称选择)
|
|
// 选择残疾人(支持通过名称选择)
|
|
|
if (personData.disabledPersonName) {
|
|
if (personData.disabledPersonName) {
|
|
@@ -877,7 +892,7 @@ export class OrderManagementPage {
|
|
|
// 如果只提供了 ID,尝试在对话框中选择第一个残疾人
|
|
// 如果只提供了 ID,尝试在对话框中选择第一个残疾人
|
|
|
const firstCheckbox = this.page.locator('[role="dialog"]').locator('table tbody tr').first().locator('input[type="checkbox"]').first();
|
|
const firstCheckbox = this.page.locator('[role="dialog"]').locator('table tbody tr').first().locator('input[type="checkbox"]').first();
|
|
|
try {
|
|
try {
|
|
|
- await firstCheckbox.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
|
|
|
+ await firstCheckbox.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
await firstCheckbox.check();
|
|
await firstCheckbox.check();
|
|
|
} catch {
|
|
} catch {
|
|
|
console.debug('没有可用的残疾人数据');
|
|
console.debug('没有可用的残疾人数据');
|
|
@@ -907,7 +922,7 @@ export class OrderManagementPage {
|
|
|
await submitButton.click();
|
|
await submitButton.click();
|
|
|
|
|
|
|
|
await this.page.waitForLoadState('networkidle');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -919,7 +934,7 @@ export class OrderManagementPage {
|
|
|
const dialog = this.page.locator('[role="dialog"]');
|
|
const dialog = this.page.locator('[role="dialog"]');
|
|
|
|
|
|
|
|
// 等待对话框完全加载
|
|
// 等待对话框完全加载
|
|
|
- await dialog.waitFor({ state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await dialog.waitFor({ state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
|
|
|
// 从 error-context.md 可知:
|
|
// 从 error-context.md 可知:
|
|
|
// 1. 对话框中有"绑定人员列表"表格
|
|
// 1. 对话框中有"绑定人员列表"表格
|
|
@@ -953,7 +968,7 @@ export class OrderManagementPage {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 等待行可见
|
|
// 等待行可见
|
|
|
- await targetRow.waitFor({ state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await targetRow.waitFor({ state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
|
|
|
// 从 error-context.md 可知,工作状态在单元格中是一个 combobox
|
|
// 从 error-context.md 可知,工作状态在单元格中是一个 combobox
|
|
|
// 表格列:ID 姓名 性别 残疾类型 联系电话 入职日期 离职日期 工作状态 薪资
|
|
// 表格列:ID 姓名 性别 残疾类型 联系电话 入职日期 离职日期 工作状态 薪资
|
|
@@ -973,11 +988,11 @@ export class OrderManagementPage {
|
|
|
throw new Error(`未找到人员 ${personName} 的工作状态选择器`);
|
|
throw new Error(`未找到人员 ${personName} 的工作状态选择器`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await workStatusCombobox.click({ timeout: 5000 });
|
|
|
|
|
|
|
+ await workStatusCombobox.click({ timeout: TIMEOUTS.DIALOG });
|
|
|
console.debug('工作状态 combobox 已点击');
|
|
console.debug('工作状态 combobox 已点击');
|
|
|
|
|
|
|
|
// 等待下拉选项显示
|
|
// 等待下拉选项显示
|
|
|
- await this.page.waitForTimeout(500);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
|
|
// 使用中文标签选择选项
|
|
// 使用中文标签选择选项
|
|
|
// 注意:UI 中的工作状态选项与 WORK_STATUS_LABELS 不同
|
|
// 注意:UI 中的工作状态选项与 WORK_STATUS_LABELS 不同
|
|
@@ -1000,13 +1015,13 @@ export class OrderManagementPage {
|
|
|
throw new Error(`未找到工作状态选项: ${newWorkStatusLabel}`);
|
|
throw new Error(`未找到工作状态选项: ${newWorkStatusLabel}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await optionLocator.first().click({ timeout: 5000 });
|
|
|
|
|
|
|
+ await optionLocator.first().click({ timeout: TIMEOUTS.DIALOG });
|
|
|
console.debug(`工作状态已更新为: ${newWorkStatusLabel}`);
|
|
console.debug(`工作状态已更新为: ${newWorkStatusLabel}`);
|
|
|
|
|
|
|
|
// 使用较短的超时时间等待网络空闲
|
|
// 使用较短的超时时间等待网络空闲
|
|
|
- await this.page.waitForLoadState('domcontentloaded', { timeout: 5000 })
|
|
|
|
|
|
|
+ await this.page.waitForLoadState('domcontentloaded', { timeout: TIMEOUTS.DIALOG })
|
|
|
.catch(() => console.debug('domcontentloaded 等待超时,继续'));
|
|
.catch(() => console.debug('domcontentloaded 等待超时,继续'));
|
|
|
- await this.page.waitForTimeout(500);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 附件管理 =====
|
|
// ===== 附件管理 =====
|
|
@@ -1017,7 +1032,7 @@ export class OrderManagementPage {
|
|
|
async openAddAttachmentDialog() {
|
|
async openAddAttachmentDialog() {
|
|
|
const attachmentButton = this.page.getByRole('button', { name: /添加附件|上传附件/ });
|
|
const attachmentButton = this.page.getByRole('button', { name: /添加附件|上传附件/ });
|
|
|
await attachmentButton.click();
|
|
await attachmentButton.click();
|
|
|
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1041,14 +1056,14 @@ export class OrderManagementPage {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// 等待上传处理
|
|
// 等待上传处理
|
|
|
- await this.page.waitForTimeout(500);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
|
|
// 提交
|
|
// 提交
|
|
|
const submitButton = this.page.getByRole('button', { name: /^(上传|确定|保存)$/ });
|
|
const submitButton = this.page.getByRole('button', { name: /^(上传|确定|保存)$/ });
|
|
|
await submitButton.click();
|
|
await submitButton.click();
|
|
|
|
|
|
|
|
await this.page.waitForLoadState('networkidle');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 高级操作 =====
|
|
// ===== 高级操作 =====
|
|
@@ -1090,7 +1105,7 @@ export class OrderManagementPage {
|
|
|
await this.confirmDelete();
|
|
await this.confirmDelete();
|
|
|
|
|
|
|
|
// 等待并检查 Toast 消息
|
|
// 等待并检查 Toast 消息
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
const hasSuccess = await successToast.count() > 0;
|
|
const hasSuccess = await successToast.count() > 0;
|
|
|
|
|
|
|
@@ -1111,11 +1126,11 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 等待菜单出现并点击"激活"选项
|
|
// 等待菜单出现并点击"激活"选项
|
|
|
const activateOption = this.page.getByRole('menuitem', { name: /激活|激活订单/ });
|
|
const activateOption = this.page.getByRole('menuitem', { name: /激活|激活订单/ });
|
|
|
- await activateOption.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
|
|
|
+ await activateOption.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
await activateOption.click();
|
|
await activateOption.click();
|
|
|
|
|
|
|
|
// 等待确认对话框出现
|
|
// 等待确认对话框出现
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1128,10 +1143,10 @@ export class OrderManagementPage {
|
|
|
});
|
|
});
|
|
|
await confirmButton.click();
|
|
await confirmButton.click();
|
|
|
// 等待确认对话框关闭和网络请求完成
|
|
// 等待确认对话框关闭和网络请求完成
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: TIMEOUTS.DIALOG })
|
|
|
.catch(() => console.debug('激活确认对话框关闭超时'));
|
|
.catch(() => console.debug('激活确认对话框关闭超时'));
|
|
|
- await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD });
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1144,7 +1159,7 @@ export class OrderManagementPage {
|
|
|
await this.confirmActivate();
|
|
await this.confirmActivate();
|
|
|
|
|
|
|
|
// 等待并检查 Toast 消息
|
|
// 等待并检查 Toast 消息
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
const hasSuccess = await successToast.count() > 0;
|
|
const hasSuccess = await successToast.count() > 0;
|
|
|
|
|
|
|
@@ -1163,11 +1178,11 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 等待菜单出现并点击"关闭"选项
|
|
// 等待菜单出现并点击"关闭"选项
|
|
|
const closeOption = this.page.getByRole('menuitem', { name: /关闭|关闭订单|完成/ });
|
|
const closeOption = this.page.getByRole('menuitem', { name: /关闭|关闭订单|完成/ });
|
|
|
- await closeOption.waitFor({ state: 'visible', timeout: 3000 });
|
|
|
|
|
|
|
+ await closeOption.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT });
|
|
|
await closeOption.click();
|
|
await closeOption.click();
|
|
|
|
|
|
|
|
// 等待确认对话框出现
|
|
// 等待确认对话框出现
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1180,10 +1195,10 @@ export class OrderManagementPage {
|
|
|
});
|
|
});
|
|
|
await confirmButton.click();
|
|
await confirmButton.click();
|
|
|
// 等待确认对话框关闭和网络请求完成
|
|
// 等待确认对话框关闭和网络请求完成
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
|
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: TIMEOUTS.DIALOG })
|
|
|
.catch(() => console.debug('关闭确认对话框关闭超时'));
|
|
.catch(() => console.debug('关闭确认对话框关闭超时'));
|
|
|
- await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD });
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1196,7 +1211,7 @@ export class OrderManagementPage {
|
|
|
await this.confirmClose();
|
|
await this.confirmClose();
|
|
|
|
|
|
|
|
// 等待并检查 Toast 消息
|
|
// 等待并检查 Toast 消息
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
const hasSuccess = await successToast.count() > 0;
|
|
const hasSuccess = await successToast.count() > 0;
|
|
|
|
|
|
|
@@ -1212,7 +1227,7 @@ export class OrderManagementPage {
|
|
|
const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
|
|
const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
|
|
|
|
|
|
|
|
// 等待行可见
|
|
// 等待行可见
|
|
|
- await orderRow.waitFor({ state: 'visible', timeout: 3000 }).catch(() => {
|
|
|
|
|
|
|
+ await orderRow.waitFor({ state: 'visible', timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT }).catch(() => {
|
|
|
console.debug(`订单 "${orderName}" 行不可见`);
|
|
console.debug(`订单 "${orderName}" 行不可见`);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -1329,7 +1344,7 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 关闭菜单以便后续操作
|
|
// 关闭菜单以便后续操作
|
|
|
await this.page.keyboard.press('Escape');
|
|
await this.page.keyboard.press('Escape');
|
|
|
- await this.page.waitForTimeout(300);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
|
|
|
|
|
return isEnabled;
|
|
return isEnabled;
|
|
|
}
|
|
}
|
|
@@ -1375,7 +1390,7 @@ export class OrderManagementPage {
|
|
|
|
|
|
|
|
// 关闭菜单以便后续操作
|
|
// 关闭菜单以便后续操作
|
|
|
await this.page.keyboard.press('Escape');
|
|
await this.page.keyboard.press('Escape');
|
|
|
- await this.page.waitForTimeout(300);
|
|
|
|
|
|
|
+ await this.page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
|
|
|
|
|
return isEnabled;
|
|
return isEnabled;
|
|
|
}
|
|
}
|