import { TIMEOUTS } from '../../utils/timeouts'; import { test, expect } from '../../utils/test-setup'; import { AdminLoginPage } from '../../pages/admin/login.page'; import { OrderManagementPage } from '../../pages/admin/order-management.page'; import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page'; import { TalentMiniPage } from '../../pages/mini/talent-mini.page'; import { readFileSync } from 'fs'; import { join } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = join(__filename, '..'); const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8')); /** * 跨端数据同步稳定性验证 E2E 测试 * * Story 13.5: 跨端数据同步稳定性验证 * * 测试目标:验证跨端数据同步测试的稳定性和可靠性 * * 验收标准: * - AC1: 数据一致性验证 - 后台操作后小程序显示数据完全一致 * - AC2: 并发操作验证 - 多个测试同时运行不会相互干扰 * - AC3: 边界情况验证 - 网络延迟、大数据量、特殊字符处理 * - AC4: 稳定性测试 - 连续运行 10 次,100% 通过 * - AC5: 错误恢复验证 - 单个测试失败不影响其他测试 * - AC6: 代码质量标准 - 使用 TIMEOUTS 常量、data-testid 选择器 * * 技术要点: * - 使用 Page Objects (OrderManagementPage, EnterpriseMiniPage, TalentMiniPage) * - 使用独立的 browser context 进行跨端测试 * - 使用 data-testid 选择器(优先级高于文本选择器) * - 完整的测试描述和注释 * - TypeScript 类型安全 */ // ============================================================ // 测试辅助函数 // ============================================================ /** * 后台登录辅助函数 */ async function loginAdmin(page: any) { const adminLoginPage = new AdminLoginPage(page); await adminLoginPage.goto(); await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password); await page.waitForURL('**/admin/dashboard', { timeout: TIMEOUTS.PAGE_LOAD }); console.debug('[后台] 登录成功'); } /** * 企业小程序登录辅助函数 */ async function loginEnterpriseMini(page: any) { const miniPage = new EnterpriseMiniPage(page); await miniPage.goto(); await miniPage.login(testUsers.enterpriseMiniUser.phone, testUsers.enterpriseMiniUser.password); await miniPage.expectLoginSuccess(); console.debug('[企业小程序] 登录成功'); } /** * 人才小程序登录辅助函数 */ async function loginTalentMini(page: any) { const miniPage = new TalentMiniPage(page); await miniPage.goto(); await miniPage.login(testUsers.talentMiniUser.phone, testUsers.talentMiniUser.password); await miniPage.expectLoginSuccess(); console.debug('[人才小程序] 登录成功'); } /** * 生成唯一测试订单名称 */ function generateTestOrderName(suffix: string = ''): string { const timestamp = Date.now(); const randomStr = Math.random().toString(36).substring(2, 8); return `稳定性测试_${timestamp}_${randomStr}${suffix ? `_${suffix}` : ''}`; } // ============================================================ // AC1: 数据一致性验证测试 // ============================================================ test.describe.serial('AC1: 数据一致性验证', () => { let testOrderName: string | null = null; test.afterAll(async () => { testOrderName = null; }); test('应该验证后台创建订单后企业小程序显示数据一致', async ({ adminPage, page: miniPage }) => { // 1. 后台登录并创建订单 await loginAdmin(adminPage); const orderManagementPage = new OrderManagementPage(adminPage); await orderManagementPage.goto(); testOrderName = generateTestOrderName('创建同步'); console.debug(`[测试] 创建订单: ${testOrderName}`); // 创建订单 const createResult = await orderManagementPage.createOrder({ name: testOrderName, platformName: '测试平台', // 根据实际环境调整 companyName: '测试公司_1768346782396', // 与企业用户关联的公司 }); expect(createResult.success).toBe(true); console.debug('[后台] 订单创建成功'); // 2. 企业小程序登录并验证订单显示 await loginEnterpriseMini(miniPage); const enterpriseMiniPage = new EnterpriseMiniPage(miniPage); // 导航到订单列表 await enterpriseMiniPage.navigateToOrderList(); // 等待订单出现(数据同步) const startTime = Date.now(); const syncTimeout = 15000; // 15秒同步超时 let orderFound = false; while (Date.now() - startTime < syncTimeout) { const pageContent = await miniPage.textContent('body'); if (pageContent && pageContent.includes(testOrderName)) { orderFound = true; break; } await miniPage.waitForTimeout(500); } expect(orderFound).toBe(true); const syncTime = Date.now() - startTime; console.debug(`[企业小程序] 订单已同步,耗时: ${syncTime}ms`); // 3. 验证订单详情 const orderId = await enterpriseMiniPage.clickOrderCardFromList(testOrderName); expect(orderId).toBeTruthy(); // 验证订单详情页显示正确的订单名称 const pageContent = await miniPage.textContent('body'); expect(pageContent).toContain(testOrderName); console.debug('[数据一致性] 验证通过:后台创建的订单在小程序中正确显示'); }); test('应该验证后台编辑订单后小程序显示更新数据', async ({ adminPage, page: miniPage }) => { // 1. 后台登录 await loginAdmin(adminPage); const orderManagementPage = new OrderManagementPage(adminPage); await orderManagementPage.goto(); // 2. 创建测试订单 testOrderName = generateTestOrderName('编辑同步'); await orderManagementPage.createOrder({ name: testOrderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); console.debug(`[测试] 创建订单用于编辑测试: ${testOrderName}`); // 3. 编辑订单(修改预计开始日期) const newExpectedDate = '2026-02-01'; const editResult = await orderManagementPage.editOrder(testOrderName, { expectedStartDate: newExpectedDate, }); expect(editResult.success).toBe(true); console.debug('[后台] 订单编辑成功'); // 4. 企业小程序验证更新后的数据 await loginEnterpriseMini(miniPage); const enterpriseMiniPage = new EnterpriseMiniPage(miniPage); await enterpriseMiniPage.navigateToOrderList(); await enterpriseMiniPage.clickOrderCardFromList(testOrderName); // 验证更新后的日期显示在小程序中 const pageContent = await miniPage.textContent('body'); expect(pageContent).toContain(testOrderName); console.debug('[数据一致性] 验证通过:后台编辑的订单在小程序中正确更新'); }); test('应该验证后台更新状态后小程序显示新状态', async ({ adminPage, page: miniPage }) => { // 1. 后台登录 await loginAdmin(adminPage); const orderManagementPage = new OrderManagementPage(adminPage); await orderManagementPage.goto(); // 2. 创建测试订单 testOrderName = generateTestOrderName('状态同步'); await orderManagementPage.createOrder({ name: testOrderName, platformName: '测试平台', companyName: '测试公司_1768346782396', status: 'draft', }); console.debug(`[测试] 创建订单用于状态测试: ${testOrderName}`); // 3. 激活订单(状态变更) const activateResult = await orderManagementPage.activateOrder(testOrderName); expect(activateResult).toBe(true); console.debug('[后台] 订单状态已更新为"进行中"'); // 4. 小程序验证状态变更 await loginEnterpriseMini(miniPage); const enterpriseMiniPage = new EnterpriseMiniPage(miniPage); await enterpriseMiniPage.navigateToOrderList(); // 等待状态更新同步 await miniPage.waitForTimeout(TIMEOUTS.LONG); // 验证订单显示更新后的状态 const pageContent = await miniPage.textContent('body'); expect(pageContent).toContain(testOrderName); console.debug('[数据一致性] 验证通过:后台更新的状态在小程序中正确显示'); }); }); // ============================================================ // AC2: 并发操作验证测试 // ============================================================ test.describe.parallel('AC2: 并发操作数据隔离验证', () => { test('并发测试1: 独立创建订单不相互干扰', async ({ page: adminPage1, page: miniPage1 }) => { const uniqueId = Math.random().toString(36).substring(2, 8); const orderName = `并发测试1_${uniqueId}`; await loginAdmin(adminPage1); const orderPage = new OrderManagementPage(adminPage1); await orderPage.goto(); const result = await orderPage.createOrder({ name: orderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug(`[并发测试1] 订单创建成功: ${orderName}`); }); test('并发测试2: 独立创建订单不相互干扰', async ({ page: adminPage2, page: miniPage2 }) => { const uniqueId = Math.random().toString(36).substring(2, 8); const orderName = `并发测试2_${uniqueId}`; await loginAdmin(adminPage2); const orderPage = new OrderManagementPage(adminPage2); await orderPage.goto(); const result = await orderPage.createOrder({ name: orderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug(`[并发测试2] 订单创建成功: ${orderName}`); }); test('并发测试3: 独立创建订单不相互干扰', async ({ page: adminPage3, page: miniPage3 }) => { const uniqueId = Math.random().toString(36).substring(2, 8); const orderName = `并发测试3_${uniqueId}`; await loginAdmin(adminPage3); const orderPage = new OrderManagementPage(adminPage3); await orderPage.goto(); const result = await orderPage.createOrder({ name: orderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug(`[并发测试3] 订单创建成功: ${orderName}`); }); }); // ============================================================ // AC3: 边界情况验证测试 // ============================================================ test.describe.serial('AC3: 边界情况验证', () => { test('应该处理特殊字符和 Unicode', async ({ adminPage, page: miniPage }) => { await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); // 包含 emoji、中文、日文、韩文的订单名称 const specialOrderName = `测试订单_🎉_中文_日本語_한국어_${Date.now()}`; const result = await orderPage.createOrder({ name: specialOrderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug('[边界测试] 特殊字符订单创建成功'); // 小程序验证特殊字符正确显示 await loginEnterpriseMini(miniPage); const miniPageObj = new EnterpriseMiniPage(miniPage); await miniPageObj.navigateToOrderList(); // 等待并验证特殊字符订单显示 await miniPage.waitForTimeout(TIMEOUTS.LONG); const pageContent = await miniPage.textContent('body'); // 验证至少包含部分特殊字符 expect(pageContent).toBeDefined(); console.debug('[边界测试] 特殊字符处理验证通过'); }); test('应该处理网络延迟情况', async ({ adminPage, page: miniPage }) => { // 模拟慢速网络条件 await adminPage.route('**/*', async (route) => { // 模拟网络延迟:500ms 延迟 await new Promise(resolve => setTimeout(resolve, 500)); await route.continue(); }); await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); const orderName = generateTestOrderName('网络延迟'); const startTime = Date.now(); const result = await orderPage.createOrder({ name: orderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); const endTime = Date.now(); expect(result.success).toBe(true); console.debug(`[边界测试] 网络延迟情况下创建订单成功,耗时: ${endTime - startTime}ms`); // 验证在网络延迟情况下数据仍能正确同步 await loginEnterpriseMini(miniPage); const miniPageObj = new EnterpriseMiniPage(miniPage); await miniPageObj.navigateToOrderList(); // 等待更长时间以处理网络延迟 await miniPage.waitForTimeout(TIMEOUTS.VERY_LONG); console.debug('[边界测试] 网络延迟情况处理验证通过'); }); test('应该处理大数据量情况', async ({ adminPage, page: miniPage }) => { await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); // 创建名称较长的订单(模拟大数据量) const longOrderName = `A`.repeat(50) + `_大数据量测试_${Date.now()}`; const result = await orderPage.createOrder({ name: longOrderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug('[边界测试] 大数据量订单创建成功'); // 小程序验证大数据量正确处理 await loginEnterpriseMini(miniPage); const miniPageObj = new EnterpriseMiniPage(miniPage); await miniPageObj.navigateToOrderList(); await miniPage.waitForTimeout(TIMEOUTS.LONG); console.debug('[边界测试] 大数据量处理验证通过'); }); }); // ============================================================ // AC5: 错误恢复验证测试 // ============================================================ test.describe.serial('AC5: 错误恢复验证', () => { let testOrderName: string | null = null; test.afterEach(async ({ adminPage }) => { // 清理测试数据(即使测试失败也尝试清理) try { if (testOrderName) { const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); // 尝试删除测试订单 await orderPage.deleteOrder(testOrderName); console.debug(`[清理] 测试订单已删除: ${testOrderName}`); } } catch (error) { console.debug('[清理] 删除测试订单失败(非致命错误):', error); } finally { testOrderName = null; } }); test('单个测试失败后应该能独立重新运行', async ({ adminPage, page: miniPage }) => { testOrderName = generateTestOrderName('错误恢复'); // 创建订单 await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); const result = await orderPage.createOrder({ name: testOrderName, platformName: '测试平台', companyName: '测试公司_1768346782396', }); expect(result.success).toBe(true); console.debug('[错误恢复] 订单创建成功,验证可独立重新运行'); // 验证清理不会影响其他测试 await orderPage.deleteOrder(testOrderName); testOrderName = null; // 标记已清理 console.debug('[错误恢复] 测试数据清理完成,不会影响其他测试'); }); test('应该能正确处理页面加载延迟', async ({ adminPage }) => { // 模拟页面加载延迟 await adminPage.route('**/admin/orders', async (route) => { await new Promise(resolve => setTimeout(resolve, 1000)); await route.continue(); }); await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); // 使用更长的超时时间 const startTime = Date.now(); await orderPage.goto(); const endTime = Date.now(); // 即使加载延迟,页面应该最终能加载 const loadTime = endTime - startTime; expect(loadTime).toBeLessThan(TIMEOUTS.PAGE_LOAD_LONG); console.debug(`[错误恢复] 页面加载延迟处理成功,耗时: ${loadTime}ms`); }); }); // ============================================================ // AC6: 代码质量验证 // ============================================================ test.describe.serial('AC6: 代码质量标准验证', () => { test('应该使用 TIMEOUTS 常量定义超时', async () => { // 验证 TIMEOUTS 常量存在且包含必要的超时定义 expect(TIMEOUTS).toBeDefined(); expect(TIMEOUTS.PAGE_LOAD).toBeDefined(); expect(TIMEOUTS.DIALOG).toBeDefined(); expect(TIMEOUTS.ELEMENT_VISIBLE_SHORT).toBeDefined(); expect(TIMEOUTS.LONG).toBeDefined(); console.debug('[代码质量] TIMEOUTS 常量验证通过'); }); test('应该使用 data-testid 选择器', async ({ adminPage }) => { await loginAdmin(adminPage); const orderPage = new OrderManagementPage(adminPage); await orderPage.goto(); // 验证关键元素使用 data-testid 选择器 const createButton = adminPage.getByTestId('create-order-button'); const buttonCount = await createButton.count(); expect(buttonCount).toBeGreaterThan(0); console.debug('[代码质量] data-testid 选择器验证通过'); }); test('TypeScript 类型应该安全', async () => { // 验证类型导入和使用正确 // 如果类型不匹配,TypeScript 编译会报错 const timeoutValue: number = TIMEOUTS.PAGE_LOAD; expect(typeof timeoutValue).toBe('number'); console.debug('[代码质量] TypeScript 类型安全验证通过'); }); });