| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- 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 类型安全验证通过');
- });
- });
|