import { test as base, expect, Page, Locator } from '@playwright/test'; import { TestDataGenerator } from './test-data.js'; import { TestLogger } from './test-logger.js'; import { ScreenshotHelper } from './screenshot-helper.js'; import { FormHelper } from './form-helper.js'; import { TableHelper } from './table-helper.js'; import { MockManager } from './mock-manager.js'; /** * 基础测试类型定义 */ export interface TestContext { page: Page; testData: ReturnType; testLogger: TestLogger; helpers: { screenshot: ScreenshotHelper; form: FormHelper; table: TableHelper; }; mocks: MockManager; } /** * 可复用的测试固件 * 提供统一的测试基础设施 */ export const baseTest = base.extend({ // 测试数据生成器 testData: async ({}, use) => { const generator = TestDataGenerator.getInstance(); await use(generator); }, // 测试日志记录器 testLogger: async ({}, use) => { const logger = new TestLogger(); await use(logger); }, // 测试辅助工具集合 helpers: async ({ page, testLogger }, use) => { const helpers = { screenshot: new ScreenshotHelper(page, testLogger), form: new FormHelper(page, testLogger), table: new TableHelper(page, testLogger), }; await use(helpers); }, // Mock管理器 mocks: async ({ page }, use) => { const mockManager = new MockManager(page); await use(mockManager); }, }); /** * 页面对象基类 * 所有页面对象都应继承此类 */ export abstract class BasePage { protected page: Page; protected testLogger: TestLogger; protected baseUrl: string; constructor(page: Page, testLogger: TestLogger, baseUrl: string = process.env.E2E_BASE_URL || 'http://localhost:5174') { this.page = page; this.testLogger = testLogger; this.baseUrl = baseUrl; } /** * 导航到页面 */ abstract navigate(): Promise; /** * 等待页面加载完成 */ abstract waitForLoad(): Promise; /** * 获取页面标题 */ async getPageTitle(): Promise { return await this.page.title(); } /** * 截图 */ async screenshot(name: string): Promise { await this.page.screenshot({ path: `./test-results/screenshots/${name}-${Date.now()}.png`, fullPage: true, }); } /** * 等待元素可见 */ async waitForVisible(selector: string, timeout: number = 10000): Promise { const locator = this.page.locator(selector); await locator.waitFor({ state: 'visible', timeout }); return locator; } /** * 等待元素隐藏 */ async waitForHidden(selector: string, timeout: number = 10000): Promise { const locator = this.page.locator(selector); await locator.waitFor({ state: 'hidden', timeout }); } /** * 点击元素 */ async click(selector: string, options?: { force?: boolean }): Promise { await this.page.click(selector, options); } /** * 填写输入框 */ async fill(selector: string, value: string): Promise { await this.page.fill(selector, value); } /** * 获取元素文本 */ async getText(selector: string): Promise { return await this.page.locator(selector).textContent() || ''; } /** * 检查元素是否存在 */ async exists(selector: string): Promise { return await this.page.locator(selector).count() > 0; } /** * 检查元素是否可见 */ async isVisible(selector: string): Promise { return await this.page.locator(selector).isVisible(); } } /** * 测试套件基类 * 提供统一的测试套件结构 */ export abstract class TestSuite { protected test = baseTest; /** * 运行测试套件 */ abstract run(): void; /** * 创建测试用例 */ protected createTest( name: string, testFn: (context: TestContext) => Promise ): void { this.test(name, async (context) => { const { testLogger } = context; testLogger.startTest(name); try { await testFn(context); testLogger.endTest(name, 'passed'); } catch (error) { testLogger.endTest(name, 'failed', error as Error); throw error; } }); } } export { expect };