Files
everything-is-suitable/everything-is-suitable-test/e2e/pages/base-page.ts
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

415 lines
13 KiB
TypeScript

import { Page, Locator, expect } from '@playwright/test';
import { testConfig } from '../core/test-config';
import { testLogger } from '../core/test-logger';
import { ScreenshotHelper } from '../helpers/screenshot-helper';
export class BasePage {
protected page: Page;
protected screenshotHelper: ScreenshotHelper;
protected baseURL: string;
protected timeout: {
default: number;
navigation: number;
element: number;
network: number;
};
constructor(page: Page) {
this.page = page;
this.screenshotHelper = new ScreenshotHelper(page);
this.baseURL = testConfig.getEnvironment().baseURL;
this.timeout = testConfig.getEnvironment().timeout;
}
async navigate(path: string = ''): Promise<void> {
const url = path.startsWith('http') ? path : `${this.baseURL}${path}`;
testLogger.info(`导航到页面: ${url}`);
try {
await this.page.goto(url, {
timeout: this.timeout.navigation,
waitUntil: 'networkidle'
});
await this.page.waitForLoadState('networkidle', {
timeout: this.timeout.network
});
testLogger.info(`页面加载完成: ${url}`);
} catch (error) {
testLogger.error(`页面导航失败: ${url}`, error as Error);
await this.screenshotHelper.takeScreenshot('navigation-error');
throw error;
}
}
async reload(): Promise<void> {
testLogger.info('重新加载页面');
try {
await this.page.reload({
timeout: this.timeout.navigation,
waitUntil: 'networkidle'
});
await this.page.waitForLoadState('networkidle', {
timeout: this.timeout.network
});
testLogger.info('页面重新加载完成');
} catch (error) {
testLogger.error('页面重新加载失败', error as Error);
await this.screenshotHelper.takeScreenshot('reload-error');
throw error;
}
}
async goBack(): Promise<void> {
testLogger.info('返回上一页');
await this.page.goBack();
}
async goForward(): Promise<void> {
testLogger.info('前进到下一页');
await this.page.goForward();
}
async waitForLoad(timeout?: number): Promise<void> {
const loadTimeout = timeout || this.timeout.navigation;
testLogger.debug(`等待页面加载完成, 超时时间: ${loadTimeout}ms`);
try {
await this.page.waitForLoadState('networkidle', {
timeout: loadTimeout
});
testLogger.debug('页面加载完成');
} catch (error) {
testLogger.error('等待页面加载超时', error as Error);
await this.screenshotHelper.takeScreenshot('wait-load-error');
throw error;
}
}
async waitForURL(urlPattern: string | RegExp, timeout?: number): Promise<void> {
const waitTimeout = timeout || this.timeout.navigation;
testLogger.debug(`等待URL匹配: ${urlPattern}, 超时时间: ${waitTimeout}ms`);
try {
await this.page.waitForURL(urlPattern, {
timeout: waitTimeout
});
testLogger.debug(`URL匹配成功: ${this.page.url()}`);
} catch (error) {
testLogger.error(`等待URL匹配失败: ${urlPattern}`, error as Error);
await this.screenshotHelper.takeScreenshot('wait-url-error');
throw error;
}
}
async waitForElement(selector: string, timeout?: number): Promise<Locator> {
const waitTimeout = timeout || this.timeout.element;
testLogger.debug(`等待元素可见: ${selector}, 超时时间: ${waitTimeout}ms`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: waitTimeout
});
testLogger.debug(`元素可见: ${selector}`);
return locator;
} catch (error) {
testLogger.error(`等待元素超时: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('wait-element-error');
throw error;
}
}
async waitForElementHidden(selector: string, timeout?: number): Promise<void> {
const waitTimeout = timeout || this.timeout.element;
testLogger.debug(`等待元素隐藏: ${selector}, 超时时间: ${waitTimeout}ms`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'hidden',
timeout: waitTimeout
});
testLogger.debug(`元素已隐藏: ${selector}`);
} catch (error) {
testLogger.error(`等待元素隐藏超时: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('wait-hidden-error');
throw error;
}
}
async click(selector: string, options?: { timeout?: number; force?: boolean }): Promise<void> {
const clickTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`点击元素: ${selector}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: clickTimeout
});
await locator.click({
timeout: clickTimeout,
force: options?.force
});
testLogger.debug(`元素点击成功: ${selector}`);
} catch (error) {
testLogger.error(`点击元素失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('click-error');
throw error;
}
}
async fill(selector: string, value: string, options?: { timeout?: number }): Promise<void> {
const fillTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`填充输入框: ${selector}, 值: ${value}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: fillTimeout
});
await locator.fill(value, {
timeout: fillTimeout
});
testLogger.debug(`输入框填充成功: ${selector}`);
} catch (error) {
testLogger.error(`填充输入框失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('fill-error');
throw error;
}
}
async selectOption(selector: string, value: string | string[], options?: { timeout?: number }): Promise<void> {
const selectTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`选择下拉选项: ${selector}, 值: ${value}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: selectTimeout
});
await locator.selectOption(value, {
timeout: selectTimeout
});
testLogger.debug(`下拉选项选择成功: ${selector}`);
} catch (error) {
testLogger.error(`选择下拉选项失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('select-error');
throw error;
}
}
async check(selector: string, options?: { timeout?: number }): Promise<void> {
const checkTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`勾选复选框: ${selector}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: checkTimeout
});
await locator.check({
timeout: checkTimeout
});
testLogger.debug(`复选框勾选成功: ${selector}`);
} catch (error) {
testLogger.error(`勾选复选框失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('check-error');
throw error;
}
}
async uncheck(selector: string, options?: { timeout?: number }): Promise<void> {
const uncheckTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`取消勾选复选框: ${selector}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: uncheckTimeout
});
await locator.uncheck({
timeout: uncheckTimeout
});
testLogger.debug(`复选框取消勾选成功: ${selector}`);
} catch (error) {
testLogger.error(`取消勾选复选框失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('uncheck-error');
throw error;
}
}
async getText(selector: string, options?: { timeout?: number }): Promise<string> {
const textTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`获取元素文本: ${selector}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: textTimeout
});
const text = await locator.textContent();
testLogger.debug(`元素文本: ${selector} = ${text}`);
return text || '';
} catch (error) {
testLogger.error(`获取元素文本失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('get-text-error');
throw error;
}
}
async getAttribute(selector: string, attributeName: string, options?: { timeout?: number }): Promise<string | null> {
const attrTimeout = options?.timeout || this.timeout.element;
testLogger.debug(`获取元素属性: ${selector}, 属性名: ${attributeName}`);
try {
const locator = this.page.locator(selector);
await locator.waitFor({
state: 'visible',
timeout: attrTimeout
});
const attribute = await locator.getAttribute(attributeName);
testLogger.debug(`元素属性: ${selector}[${attributeName}] = ${attribute}`);
return attribute;
} catch (error) {
testLogger.error(`获取元素属性失败: ${selector}`, error as Error);
await this.screenshotHelper.takeScreenshot('get-attribute-error');
throw error;
}
}
async isVisible(selector: string): Promise<boolean> {
try {
const locator = this.page.locator(selector);
const visible = await locator.isVisible({ timeout: 5000 });
testLogger.debug(`元素可见性: ${selector} = ${visible}`);
return visible;
} catch (error) {
testLogger.debug(`元素不可见: ${selector}`);
return false;
}
}
async isEnabled(selector: string): Promise<boolean> {
try {
const locator = this.page.locator(selector);
const enabled = await locator.isEnabled({ timeout: 5000 });
testLogger.debug(`元素可用性: ${selector} = ${enabled}`);
return enabled;
} catch (error) {
testLogger.debug(`元素不可用: ${selector}`);
return false;
}
}
async waitForTimeout(ms: number): Promise<void> {
testLogger.debug(`等待 ${ms}ms`);
await this.page.waitForTimeout(ms);
}
async executeScript(script: string, ...args: any[]): Promise<any> {
testLogger.debug('执行JavaScript脚本');
try {
const result = await this.page.evaluate(script, ...args);
testLogger.debug('JavaScript脚本执行成功');
return result;
} catch (error) {
testLogger.error('JavaScript脚本执行失败', error as Error);
throw error;
}
}
async scrollToElement(selector: string): Promise<void> {
testLogger.debug(`滚动到元素: ${selector}`);
try {
const locator = this.page.locator(selector);
await locator.scrollIntoViewIfNeeded();
testLogger.debug(`滚动到元素成功: ${selector}`);
} catch (error) {
testLogger.error(`滚动到元素失败: ${selector}`, error as Error);
throw error;
}
}
async takeScreenshot(name: string): Promise<string> {
return await this.screenshotHelper.takeScreenshot(name);
}
async takeElementScreenshot(selector: string, name: string): Promise<string> {
return await this.screenshotHelper.takeElementScreenshot(selector, name);
}
getCurrentURL(): string {
return this.page.url();
}
getTitle(): Promise<string> {
return this.page.title();
}
async expectVisible(selector: string, timeout?: number): Promise<void> {
const locator = await this.waitForElement(selector, timeout);
await expect(locator).toBeVisible();
}
async expectHidden(selector: string, timeout?: number): Promise<void> {
const locator = this.page.locator(selector);
await expect(locator).toBeHidden({ timeout });
}
async expectText(selector: string, expectedText: string, timeout?: number): Promise<void> {
const locator = await this.waitForElement(selector, timeout);
await expect(locator).toHaveText(expectedText);
}
async expectValue(selector: string, expectedValue: string, timeout?: number): Promise<void> {
const locator = await this.waitForElement(selector, timeout);
await expect(locator).toHaveValue(expectedValue);
}
async expectAttribute(selector: string, attributeName: string, expectedValue: string, timeout?: number): Promise<void> {
const locator = await this.waitForElement(selector, timeout);
await expect(locator).toHaveAttribute(attributeName, expectedValue);
}
async expectCount(selector: string, expectedCount: number, timeout?: number): Promise<void> {
const locator = this.page.locator(selector);
await expect(locator).toHaveCount(expectedCount, { timeout });
}
}