|
|
@@ -1,4 +1,25 @@
|
|
|
-import { Page, Locator } from '@playwright/test';
|
|
|
+import { Page, Locator, Response } from '@playwright/test';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 平台状态常量
|
|
|
+ */
|
|
|
+export const PLATFORM_STATUS = {
|
|
|
+ ENABLED: 0,
|
|
|
+ DISABLED: 1,
|
|
|
+} as const;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 平台状态类型
|
|
|
+ */
|
|
|
+export type PlatformStatus = typeof PLATFORM_STATUS[keyof typeof PLATFORM_STATUS];
|
|
|
+
|
|
|
+/**
|
|
|
+ * 平台状态显示名称映射
|
|
|
+ */
|
|
|
+export const PLATFORM_STATUS_LABELS: Record<PlatformStatus, string> = {
|
|
|
+ 0: '启用',
|
|
|
+ 1: '禁用',
|
|
|
+} as const;
|
|
|
|
|
|
/**
|
|
|
* 平台数据接口
|
|
|
@@ -180,8 +201,8 @@ export class PlatformManagementPage {
|
|
|
async openEditDialog(platformName: string): Promise<void> {
|
|
|
// 找到平台行并点击编辑按钮
|
|
|
const platformRow = this.platformTable.locator('tbody tr').filter({ hasText: platformName });
|
|
|
- // 使用 data-testid 定位编辑按钮
|
|
|
- const editButton = platformRow.getByTestId(/edit-button/);
|
|
|
+ // 使用 role + name 组合定位编辑按钮,更健壮
|
|
|
+ const editButton = platformRow.getByRole('button', { name: '编辑' });
|
|
|
await editButton.click();
|
|
|
|
|
|
// 等待编辑对话框出现
|
|
|
@@ -195,8 +216,8 @@ export class PlatformManagementPage {
|
|
|
async openDeleteDialog(platformName: string): Promise<void> {
|
|
|
// 找到平台行并点击删除按钮
|
|
|
const platformRow = this.platformTable.locator('tbody tr').filter({ hasText: platformName });
|
|
|
- // 使用 data-testid 定位删除按钮
|
|
|
- const deleteButton = platformRow.getByTestId(/delete-button/);
|
|
|
+ // 使用 role + name 组合定位删除按钮,更健壮
|
|
|
+ const deleteButton = platformRow.getByRole('button', { name: '删除' });
|
|
|
await deleteButton.click();
|
|
|
|
|
|
// 等待删除确认对话框出现
|
|
|
@@ -241,13 +262,12 @@ export class PlatformManagementPage {
|
|
|
const responses: NetworkResponse[] = [];
|
|
|
|
|
|
// 监听所有网络请求
|
|
|
- const responseHandler = async (response: unknown) => {
|
|
|
- const res = response as { url(): string; request?: { method?: () => string }; status(): number; ok(): boolean; headers(): Promise<Record<string, string>>; text(): Promise<string> };
|
|
|
- const url = res.url();
|
|
|
+ const responseHandler = async (response: Response) => {
|
|
|
+ const url = response.url();
|
|
|
// 监听平台管理相关的 API 请求
|
|
|
if (url.includes('/platforms') || url.includes('platform')) {
|
|
|
- const _requestBody = res.request;
|
|
|
- const responseBody = await res.text().catch(() => '');
|
|
|
+ const requestBody = response.request()?.postData();
|
|
|
+ const responseBody = await response.text().catch(() => '');
|
|
|
let jsonBody = null;
|
|
|
try {
|
|
|
jsonBody = JSON.parse(responseBody);
|
|
|
@@ -257,10 +277,10 @@ export class PlatformManagementPage {
|
|
|
|
|
|
responses.push({
|
|
|
url,
|
|
|
- method: _requestBody?.method?.() ?? 'UNKNOWN',
|
|
|
- status: res.status(),
|
|
|
- ok: res.ok(),
|
|
|
- responseHeaders: await res.headers().catch(() => ({})),
|
|
|
+ method: response.request()?.method() ?? 'UNKNOWN',
|
|
|
+ status: response.status(),
|
|
|
+ ok: response.ok(),
|
|
|
+ responseHeaders: await response.allHeaders().catch(() => ({})),
|
|
|
responseBody: jsonBody || responseBody,
|
|
|
});
|
|
|
}
|
|
|
@@ -394,15 +414,20 @@ export class PlatformManagementPage {
|
|
|
* @returns 是否成功删除
|
|
|
*/
|
|
|
async deletePlatform(platformName: string): Promise<boolean> {
|
|
|
- await this.openDeleteDialog(platformName);
|
|
|
- await this.confirmDelete();
|
|
|
-
|
|
|
- // 等待并检查 Toast 消息
|
|
|
- await this.page.waitForTimeout(1000);
|
|
|
- const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
- const hasSuccess = await successToast.count() > 0;
|
|
|
-
|
|
|
- return hasSuccess;
|
|
|
+ try {
|
|
|
+ await this.openDeleteDialog(platformName);
|
|
|
+ await this.confirmDelete();
|
|
|
+
|
|
|
+ // 等待并检查 Toast 消息
|
|
|
+ await this.page.waitForTimeout(1000);
|
|
|
+ const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
+ const hasSuccess = await successToast.count() > 0;
|
|
|
+
|
|
|
+ return hasSuccess;
|
|
|
+ } catch (error) {
|
|
|
+ console.debug(`删除平台 "${platformName}" 失败:`, error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// ===== 搜索和验证方法 =====
|
|
|
@@ -410,21 +435,31 @@ export class PlatformManagementPage {
|
|
|
/**
|
|
|
* 按平台名称搜索
|
|
|
* @param name 平台名称
|
|
|
+ * @returns 搜索结果是否包含目标平台
|
|
|
*/
|
|
|
- async searchByName(name: string): Promise<void> {
|
|
|
+ async searchByName(name: string): Promise<boolean> {
|
|
|
await this.searchInput.fill(name);
|
|
|
await this.searchButton.click();
|
|
|
await this.page.waitForLoadState('domcontentloaded');
|
|
|
await this.page.waitForTimeout(1000);
|
|
|
+ // 验证搜索结果
|
|
|
+ return await this.platformExists(name);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 验证平台是否存在
|
|
|
+ * 验证平台是否存在(使用精确匹配)
|
|
|
* @param platformName 平台名称
|
|
|
* @returns 平台是否存在
|
|
|
*/
|
|
|
async platformExists(platformName: string): Promise<boolean> {
|
|
|
const platformRow = this.platformTable.locator('tbody tr').filter({ hasText: platformName });
|
|
|
- return (await platformRow.count()) > 0;
|
|
|
+ const count = await platformRow.count();
|
|
|
+ if (count === 0) return false;
|
|
|
+
|
|
|
+ // 进一步验证第一列的文本是否完全匹配平台名称
|
|
|
+ // 避免部分匹配导致的误判(如搜索"测试"匹配"测试平台A")
|
|
|
+ const firstCell = platformRow.locator('td').first();
|
|
|
+ const actualText = await firstCell.textContent();
|
|
|
+ return actualText?.trim() === platformName;
|
|
|
}
|
|
|
}
|