|
@@ -1,4 +1,10 @@
|
|
|
import { Page, Locator } from '@playwright/test';
|
|
import { Page, Locator } from '@playwright/test';
|
|
|
|
|
+import { selectRadixOptionAsync } from '@d8d/e2e-test-utils';
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * API 基础 URL
|
|
|
|
|
+ */
|
|
|
|
|
+const API_BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:8080';
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 公司状态常量
|
|
* 公司状态常量
|
|
@@ -91,6 +97,12 @@ export interface FormSubmitResult {
|
|
|
export class CompanyManagementPage {
|
|
export class CompanyManagementPage {
|
|
|
readonly page: Page;
|
|
readonly page: Page;
|
|
|
|
|
|
|
|
|
|
+ // ===== API 端点常量 =====
|
|
|
|
|
+ /** 获取所有公司列表 API */
|
|
|
|
|
+ private static readonly API_GET_ALL_COMPANIES = `${API_BASE_URL}/api/v1/company/getAllCompanies`;
|
|
|
|
|
+ /** 删除公司 API */
|
|
|
|
|
+ private static readonly API_DELETE_COMPANY = `${API_BASE_URL}/api/v1/company/deleteCompany`;
|
|
|
|
|
+
|
|
|
// ===== 页面级选择器 =====
|
|
// ===== 页面级选择器 =====
|
|
|
/** 页面标题 */
|
|
/** 页面标题 */
|
|
|
readonly pageTitle: Locator;
|
|
readonly pageTitle: Locator;
|
|
@@ -237,18 +249,16 @@ export class CompanyManagementPage {
|
|
|
/**
|
|
/**
|
|
|
* 填写公司表单
|
|
* 填写公司表单
|
|
|
* @param data 公司数据
|
|
* @param data 公司数据
|
|
|
|
|
+ * @param platformName 平台名称(当需要选择平台时必须提供)
|
|
|
*/
|
|
*/
|
|
|
- async fillCompanyForm(data: CompanyData): Promise<void> {
|
|
|
|
|
|
|
+ async fillCompanyForm(data: CompanyData, platformName?: string): Promise<void> {
|
|
|
// 等待表单出现
|
|
// 等待表单出现
|
|
|
await this.page.waitForSelector('form', { state: 'visible', timeout: 5000 });
|
|
await this.page.waitForSelector('form', { state: 'visible', timeout: 5000 });
|
|
|
|
|
|
|
|
// 填写平台选择器(可选字段)
|
|
// 填写平台选择器(可选字段)
|
|
|
- if (data.platformId !== undefined) {
|
|
|
|
|
- // 注意:PlatformSelector 使用 Radix UI Select
|
|
|
|
|
- // 需要使用 @d8d/e2e-test-utils 的 selectRadixOption 工具
|
|
|
|
|
- // 这里假设测试代码中会传入平台名称进行选择
|
|
|
|
|
- // 实际的选择逻辑应在测试代码中处理
|
|
|
|
|
- console.debug('需要选择平台,platformId:', data.platformId);
|
|
|
|
|
|
|
+ if (data.platformId !== undefined && platformName) {
|
|
|
|
|
+ // 使用 @d8d/e2e-test-utils 的 selectRadixOptionAsync 选择平台
|
|
|
|
|
+ await selectRadixOptionAsync(this.page, '平台', platformName);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 填写公司名称(必填字段)
|
|
// 填写公司名称(必填字段)
|
|
@@ -314,7 +324,6 @@ export class CompanyManagementPage {
|
|
|
submitButton = this.page.getByRole('button', { name: /^(创建|更新|保存)$/ });
|
|
submitButton = this.page.getByRole('button', { name: /^(创建|更新|保存)$/ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- console.debug('点击提交按钮,按钮数量:', await submitButton.count());
|
|
|
|
|
await submitButton.click();
|
|
await submitButton.click();
|
|
|
|
|
|
|
|
// 等待 API 响应并收集
|
|
// 等待 API 响应并收集
|
|
@@ -340,11 +349,6 @@ export class CompanyManagementPage {
|
|
|
responseHeaders: await mainResponse.allHeaders().catch(() => ({})),
|
|
responseHeaders: await mainResponse.allHeaders().catch(() => ({})),
|
|
|
responseBody: jsonBody || responseBody,
|
|
responseBody: jsonBody || responseBody,
|
|
|
});
|
|
});
|
|
|
- console.debug('公司 API 响应:', {
|
|
|
|
|
- url: mainResponse.url(),
|
|
|
|
|
- status: mainResponse.status(),
|
|
|
|
|
- ok: mainResponse.ok()
|
|
|
|
|
- });
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (getAllResponse) {
|
|
if (getAllResponse) {
|
|
@@ -361,18 +365,13 @@ export class CompanyManagementPage {
|
|
|
responseHeaders: await getAllResponse.allHeaders().catch(() => ({})),
|
|
responseHeaders: await getAllResponse.allHeaders().catch(() => ({})),
|
|
|
responseBody: jsonBody || responseBody,
|
|
responseBody: jsonBody || responseBody,
|
|
|
});
|
|
});
|
|
|
- console.debug('getAllCompanies API 响应:', {
|
|
|
|
|
- url: getAllResponse.url(),
|
|
|
|
|
- status: getAllResponse.status(),
|
|
|
|
|
- ok: getAllResponse.ok()
|
|
|
|
|
- });
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 等待网络请求完成
|
|
// 等待网络请求完成
|
|
|
try {
|
|
try {
|
|
|
await this.page.waitForLoadState('networkidle', { timeout: 5000 });
|
|
await this.page.waitForLoadState('networkidle', { timeout: 5000 });
|
|
|
} catch {
|
|
} catch {
|
|
|
- console.debug('networkidle 超时,继续检查 Toast 消息');
|
|
|
|
|
|
|
+ // 继续检查 Toast 消息
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.debug('submitForm 异常:', error);
|
|
console.debug('submitForm 异常:', error);
|
|
@@ -425,15 +424,6 @@ export class CompanyManagementPage {
|
|
|
successMessage = await ((await successToast.count()) > 0 ? successToast.first() : fallbackSuccessToast).textContent();
|
|
successMessage = await ((await successToast.count()) > 0 ? successToast.first() : fallbackSuccessToast).textContent();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 调试输出
|
|
|
|
|
- console.debug('submitForm 结果:', {
|
|
|
|
|
- hasError,
|
|
|
|
|
- hasSuccess,
|
|
|
|
|
- errorMessage,
|
|
|
|
|
- successMessage,
|
|
|
|
|
- responsesCount: responses.length
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
return {
|
|
return {
|
|
|
success: hasSuccess || (!hasError && !hasSuccess && responses.some(r => r.ok)),
|
|
success: hasSuccess || (!hasError && !hasSuccess && responses.some(r => r.ok)),
|
|
|
hasError,
|
|
hasError,
|
|
@@ -461,13 +451,14 @@ export class CompanyManagementPage {
|
|
|
const count = await dialog.count();
|
|
const count = await dialog.count();
|
|
|
|
|
|
|
|
if (count === 0) {
|
|
if (count === 0) {
|
|
|
- console.debug('对话框已经不存在,跳过等待');
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 等待对话框隐藏
|
|
// 等待对话框隐藏
|
|
|
await dialog.waitFor({ state: 'hidden', timeout: 5000 })
|
|
await dialog.waitFor({ state: 'hidden', timeout: 5000 })
|
|
|
- .catch(() => console.debug('对话框关闭超时,可能已经关闭'));
|
|
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ // 对话框可能已经关闭
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
// 额外等待以确保 DOM 更新完成
|
|
// 额外等待以确保 DOM 更新完成
|
|
|
await this.page.waitForTimeout(500);
|
|
await this.page.waitForTimeout(500);
|
|
@@ -480,7 +471,9 @@ export class CompanyManagementPage {
|
|
|
await this.confirmDeleteButton.click();
|
|
await this.confirmDeleteButton.click();
|
|
|
// 等待确认对话框关闭和网络请求完成
|
|
// 等待确认对话框关闭和网络请求完成
|
|
|
await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
- .catch(() => console.debug('删除确认对话框关闭超时'));
|
|
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ // 继续执行
|
|
|
|
|
+ });
|
|
|
try {
|
|
try {
|
|
|
await this.page.waitForLoadState('domcontentloaded', { timeout: 5000 });
|
|
await this.page.waitForLoadState('domcontentloaded', { timeout: 5000 });
|
|
|
} catch {
|
|
} catch {
|
|
@@ -496,7 +489,9 @@ export class CompanyManagementPage {
|
|
|
const cancelButton = this.page.locator('[role="alertdialog"]').getByRole('button', { name: '取消' });
|
|
const cancelButton = this.page.locator('[role="alertdialog"]').getByRole('button', { name: '取消' });
|
|
|
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: 5000 })
|
|
|
- .catch(() => console.debug('删除确认对话框关闭超时(取消操作)'));
|
|
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ // 继续执行
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== CRUD 操作方法 =====
|
|
// ===== CRUD 操作方法 =====
|
|
@@ -504,11 +499,12 @@ export class CompanyManagementPage {
|
|
|
/**
|
|
/**
|
|
|
* 创建公司(完整流程)
|
|
* 创建公司(完整流程)
|
|
|
* @param data 公司数据
|
|
* @param data 公司数据
|
|
|
|
|
+ * @param platformName 平台名称(当需要选择平台时必须提供)
|
|
|
* @returns 表单提交结果
|
|
* @returns 表单提交结果
|
|
|
*/
|
|
*/
|
|
|
- async createCompany(data: CompanyData): Promise<FormSubmitResult> {
|
|
|
|
|
|
|
+ async createCompany(data: CompanyData, platformName?: string): Promise<FormSubmitResult> {
|
|
|
await this.openCreateDialog();
|
|
await this.openCreateDialog();
|
|
|
- await this.fillCompanyForm(data);
|
|
|
|
|
|
|
+ await this.fillCompanyForm(data, platformName);
|
|
|
const result = await this.submitForm();
|
|
const result = await this.submitForm();
|
|
|
await this.waitForDialogClosed();
|
|
await this.waitForDialogClosed();
|
|
|
return result;
|
|
return result;
|
|
@@ -518,11 +514,12 @@ export class CompanyManagementPage {
|
|
|
* 编辑公司(完整流程)
|
|
* 编辑公司(完整流程)
|
|
|
* @param companyName 公司名称
|
|
* @param companyName 公司名称
|
|
|
* @param data 更新的公司数据
|
|
* @param data 更新的公司数据
|
|
|
|
|
+ * @param platformName 平台名称(当需要选择平台时必须提供)
|
|
|
* @returns 表单提交结果
|
|
* @returns 表单提交结果
|
|
|
*/
|
|
*/
|
|
|
- async editCompany(companyName: string, data: CompanyData): Promise<FormSubmitResult> {
|
|
|
|
|
|
|
+ async editCompany(companyName: string, data: CompanyData, platformName?: string): Promise<FormSubmitResult> {
|
|
|
await this.openEditDialog(companyName);
|
|
await this.openEditDialog(companyName);
|
|
|
- await this.fillCompanyForm(data);
|
|
|
|
|
|
|
+ await this.fillCompanyForm(data, platformName);
|
|
|
const result = await this.submitForm();
|
|
const result = await this.submitForm();
|
|
|
await this.waitForDialogClosed();
|
|
await this.waitForDialogClosed();
|
|
|
return result;
|
|
return result;
|
|
@@ -537,32 +534,19 @@ export class CompanyManagementPage {
|
|
|
try {
|
|
try {
|
|
|
// 使用 API 直接删除,添加超时保护
|
|
// 使用 API 直接删除,添加超时保护
|
|
|
const result = await Promise.race([
|
|
const result = await Promise.race([
|
|
|
- this.page.evaluate(async ({ companyName }) => {
|
|
|
|
|
- // 尝试多种可能的 token 键名
|
|
|
|
|
- let token = localStorage.getItem('token');
|
|
|
|
|
- if (!token) {
|
|
|
|
|
- token = localStorage.getItem('auth_token');
|
|
|
|
|
- }
|
|
|
|
|
- if (!token) {
|
|
|
|
|
- token = localStorage.getItem('accessToken');
|
|
|
|
|
- }
|
|
|
|
|
- if (!token) {
|
|
|
|
|
- const localStorageKeys = Object.keys(localStorage);
|
|
|
|
|
- for (const key of localStorageKeys) {
|
|
|
|
|
- if (key.toLowerCase().includes('token')) {
|
|
|
|
|
- token = localStorage.getItem(key);
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ this.page.evaluate(async ({ companyName, apiGetAll, apiDelete }) => {
|
|
|
|
|
+ // 尝试获取 token(使用标准键名)
|
|
|
|
|
+ let token = localStorage.getItem('token') ||
|
|
|
|
|
+ localStorage.getItem('auth_token') ||
|
|
|
|
|
+ localStorage.getItem('accessToken');
|
|
|
|
|
|
|
|
if (!token) {
|
|
if (!token) {
|
|
|
- return { success: false, notFound: true };
|
|
|
|
|
|
|
+ return { success: false, noToken: true };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
// 先获取公司列表,找到公司的 ID(限制 100 条)
|
|
// 先获取公司列表,找到公司的 ID(限制 100 条)
|
|
|
- const listResponse = await fetch('http://localhost:8080/api/v1/company/getAllCompanies?skip=0&take=100', {
|
|
|
|
|
|
|
+ const listResponse = await fetch(`${apiGetAll}?skip=0&take=100`, {
|
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -583,7 +567,7 @@ export class CompanyManagementPage {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 使用公司 ID 删除 - POST 方法
|
|
// 使用公司 ID 删除 - POST 方法
|
|
|
- const deleteResponse = await fetch('http://localhost:8080/api/v1/company/deleteCompany', {
|
|
|
|
|
|
|
+ const deleteResponse = await fetch(apiDelete, {
|
|
|
method: 'POST',
|
|
method: 'POST',
|
|
|
headers: {
|
|
headers: {
|
|
|
'Authorization': `Bearer ${token}`,
|
|
'Authorization': `Bearer ${token}`,
|
|
@@ -600,19 +584,26 @@ export class CompanyManagementPage {
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
return { success: false, notFound: false };
|
|
return { success: false, notFound: false };
|
|
|
}
|
|
}
|
|
|
- }, { companyName }),
|
|
|
|
|
|
|
+ }, {
|
|
|
|
|
+ companyName,
|
|
|
|
|
+ apiGetAll: CompanyManagementPage.API_GET_ALL_COMPANIES,
|
|
|
|
|
+ apiDelete: CompanyManagementPage.API_DELETE_COMPANY
|
|
|
|
|
+ }),
|
|
|
// 10 秒超时
|
|
// 10 秒超时
|
|
|
new Promise((resolve) => setTimeout(() => resolve({ success: false, timeout: true }), 10000))
|
|
new Promise((resolve) => setTimeout(() => resolve({ success: false, timeout: true }), 10000))
|
|
|
]) as any;
|
|
]) as any;
|
|
|
|
|
|
|
|
// 如果超时或公司找不到,返回 true(允许测试继续)
|
|
// 如果超时或公司找不到,返回 true(允许测试继续)
|
|
|
if (result.timeout || result.notFound) {
|
|
if (result.timeout || result.notFound) {
|
|
|
- console.debug(`删除公司 "${companyName}" 超时或未找到,跳过`);
|
|
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (result.noToken) {
|
|
|
|
|
+ console.debug('删除公司失败: 未找到认证 token');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (!result.success) {
|
|
if (!result.success) {
|
|
|
- console.debug(`删除公司 "${companyName}" 失败:`, result.error);
|
|
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|