feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
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<typeof TestDataGenerator.getInstance>;
|
||||
testLogger: TestLogger;
|
||||
helpers: {
|
||||
screenshot: ScreenshotHelper;
|
||||
form: FormHelper;
|
||||
table: TableHelper;
|
||||
};
|
||||
mocks: MockManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 可复用的测试固件
|
||||
* 提供统一的测试基础设施
|
||||
*/
|
||||
export const baseTest = base.extend<TestContext>({
|
||||
// 测试数据生成器
|
||||
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<void>;
|
||||
|
||||
/**
|
||||
* 等待页面加载完成
|
||||
*/
|
||||
abstract waitForLoad(): Promise<void>;
|
||||
|
||||
/**
|
||||
* 获取页面标题
|
||||
*/
|
||||
async getPageTitle(): Promise<string> {
|
||||
return await this.page.title();
|
||||
}
|
||||
|
||||
/**
|
||||
* 截图
|
||||
*/
|
||||
async screenshot(name: string): Promise<void> {
|
||||
await this.page.screenshot({
|
||||
path: `./test-results/screenshots/${name}-${Date.now()}.png`,
|
||||
fullPage: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待元素可见
|
||||
*/
|
||||
async waitForVisible(selector: string, timeout: number = 10000): Promise<Locator> {
|
||||
const locator = this.page.locator(selector);
|
||||
await locator.waitFor({ state: 'visible', timeout });
|
||||
return locator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待元素隐藏
|
||||
*/
|
||||
async waitForHidden(selector: string, timeout: number = 10000): Promise<void> {
|
||||
const locator = this.page.locator(selector);
|
||||
await locator.waitFor({ state: 'hidden', timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击元素
|
||||
*/
|
||||
async click(selector: string, options?: { force?: boolean }): Promise<void> {
|
||||
await this.page.click(selector, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 填写输入框
|
||||
*/
|
||||
async fill(selector: string, value: string): Promise<void> {
|
||||
await this.page.fill(selector, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元素文本
|
||||
*/
|
||||
async getText(selector: string): Promise<string> {
|
||||
return await this.page.locator(selector).textContent() || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查元素是否存在
|
||||
*/
|
||||
async exists(selector: string): Promise<boolean> {
|
||||
return await this.page.locator(selector).count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查元素是否可见
|
||||
*/
|
||||
async isVisible(selector: string): Promise<boolean> {
|
||||
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>
|
||||
): 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 };
|
||||
Reference in New Issue
Block a user