first commit

This commit is contained in:
2025-11-04 16:29:07 +08:00
commit 8ee74625c7
19 changed files with 4562 additions and 0 deletions

58
pages/BasePage.ts Normal file
View File

@ -0,0 +1,58 @@
/**
* 页面基类
* 提供所有页面共享的方法和属性
*/
import { Page, expect } from '@playwright/test';
import { TestConfig } from '../config/test.config';
export class BasePage {
protected page: Page;
protected config = TestConfig;
constructor(page: Page) {
this.page = page;
}
/**
* 等待页面稳定
*/
async waitForPageStable(timeout: number = this.config.waits.pageStable): Promise<void> {
console.log(`等待 ${timeout / 1000} 秒让页面稳定...`);
await this.page.waitForTimeout(timeout);
console.log('页面已稳定,继续下一步');
}
/**
* 导航到指定URL
*/
async goto(url: string): Promise<void> {
await this.page.goto(url, { timeout: this.config.timeouts.navigation });
}
/**
* 点击元素
*/
async click(selector: string): Promise<void> {
await this.page.click(selector);
}
/**
* 填充输入框
*/
async fill(selector: string, text: string): Promise<void> {
await this.page.fill(selector, text);
}
/**
* 检查元素是否可见
*/
async isVisible(selector: string, timeout?: number): Promise<boolean> {
try {
await expect(this.page.locator(selector)).toBeVisible({ timeout });
return true;
} catch {
return false;
}
}
}

View File

@ -0,0 +1,31 @@
/**
* DreamiExplore 页面对象
* 封装 DreamiExplore 相关的操作
*/
import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
export class DreamiExplorePage extends BasePage {
constructor(page: Page) {
super(page);
}
/**
* 进入 DreamiExplore
*/
async enterDreamiExplore(): Promise<void> {
await this.page.getByRole('link').filter({ hasText: 'DreamiExplore Everything' }).click();
await expect(this.page.getByRole('heading', { name: 'Hello, Admin' })).toBeVisible();
}
/**
* 测试聊天功能
*/
async testChatFunction(message: string = 'hello'): Promise<void> {
await this.page.getByRole('textbox').click();
await this.page.getByRole('textbox').fill(message);
await this.page.getByRole('button', { name: 'send' }).click();
await expect(this.page.getByRole('button', { name: '复制' })).toBeVisible({ timeout: 10000 });
}
}

229
pages/EssayWritingPage.ts Normal file
View File

@ -0,0 +1,229 @@
/**
* Essay Writing 页面对象
* 封装文书写作相关的所有操作
*/
import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
export class EssayWritingPage extends BasePage {
constructor(page: Page) {
super(page);
}
/**
* 进入 Essay Writing
*/
async enterEssayWriting(): Promise<void> {
await this.page.getByRole('button', { name: 'documents Essay Writing' }).first().click();
await expect(this.page.getByText('Notes')).toBeVisible();
}
/**
* 添加材料
*/
async addMaterial(title: string, content: string, expectedButtonText: string): Promise<void> {
await this.page.getByRole('button', { name: 'Add Material' }).click();
await this.page.getByRole('menuitem', { name: 'Manual Add' }).click();
await expect(
this.page.getByText('ClassificationGeneralGeneralAcademic Interests and AchievementsInternship and')
).toBeVisible();
await this.page.getByRole('textbox', { name: 'Title' }).click();
await this.page.getByRole('textbox', { name: 'Title' }).fill(title);
await this.page.getByRole('paragraph').filter({ hasText: /^$/ }).click();
await this.page.locator('.tiptap').fill(content);
await this.page.getByRole('button', { name: 'icon Get Suggestions' }).click();
await expect(this.page.getByRole('heading', { name: 'More Suggestions' })).toBeVisible();
await this.page.getByRole('button', { name: 'Create', exact: true }).click();
await expect(this.page.getByRole('button', { name: expectedButtonText })).toBeVisible({
timeout: 15000
});
await this.waitForPageStable(this.config.waits.shortWait);
}
/**
* 探索 Essay Idea
*/
async exploreEssayIdea(): Promise<void> {
await this.page.getByRole('button', { name: 'icon Explore Essay Idea' }).click();
await expect(this.page.getByRole('heading', { name: 'Select an essay prompt or' })).toBeVisible();
}
/**
* 加载 Recommendation
*/
async loadRecommendation(): Promise<void> {
await this.page.getByRole('button', { name: 'icon Recommendation' }).click();
await this.page.waitForTimeout(10000);
console.log('等待 Recommendation 加载完成...');
await expect(this.page.getByRole('heading', { name: 'Recommendation Material' })).toBeVisible({
timeout: this.config.timeouts.grammarCheck
});
console.log('Recommendation Material 已出现');
}
/**
* 生成 Essay Idea
*/
async generateEssayIdea(): Promise<void> {
await this.page.getByRole('button', { name: 'icon Generate Essay Idea' }).click();
await this.page.getByRole('button', { name: 'Generate' }).click();
await expect(this.page.getByRole('heading', { name: 'Essay Idea' })).toBeVisible({
timeout: this.config.timeouts.aiGeneration
});
}
/**
* 生成 Essay
*/
async generateEssay(): Promise<void> {
await this.page.getByRole('button', { name: 'icon Generate Essay' }).click();
await this.page.getByRole('button', { name: 'Generate' }).click();
console.log('等待 Essay 生成完成...');
const loadingMessage = this.page.getByText(/正在生成文书预计需要30秒请耐心等待/i);
console.log('等待加载消息出现...');
await loadingMessage.waitFor({ state: 'visible', timeout: 10000 });
console.log('加载消息已出现,文书正在生成中...');
await loadingMessage.waitFor({ state: 'hidden', timeout: this.config.timeouts.longAiGeneration });
console.log('Essay 生成完成,加载消息已消失');
await this.waitForPageStable();
}
/**
* 语法检查
*/
async performGrammarCheck(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).first().click();
await this.page.getByRole('button', { name: 'Start Grammar Check' }).click();
console.log('等待 Grammar Check 加载完成...');
await expect(this.page.getByRole('heading', { name: 'suggestions' })).toBeVisible({
timeout: this.config.timeouts.grammarCheck
});
console.log('suggestions 已出现');
await expect(this.page.getByLabel('suggestions')).toBeVisible({ timeout: 30000 });
}
/**
* 查重检查
*/
async performPlagiarismCheck(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).nth(1).click();
await this.page.getByRole('button', { name: 'Start Plagiarism Check' }).click();
console.log('等待 Plagiarism Check 加载完成...');
await expect(this.page.getByRole('button', { name: 'Re-check' })).toBeVisible({
timeout: this.config.timeouts.plagiarismCheck
});
console.log('Re-check 已出现');
}
/**
* AI检测
*/
async performAIDetection(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).nth(2).click();
await this.page.getByRole('button', { name: 'Start AI Detection' }).click();
console.log('等待 AI Detection 加载完成...');
await expect(this.page.getByRole('heading', { name: 'GPTZero Premium' })).toBeVisible({
timeout: this.config.timeouts.aiDetection
});
console.log('GPTZero Premium 已出现');
}
/**
* 人性化处理
*/
async performHumanize(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).nth(3).click();
await this.page.getByRole('button', { name: 'Start Humanize' }).click();
console.log('等待 Humanize 加载完成...');
await expect(this.page.getByText('Accept all')).toBeVisible({
timeout: this.config.timeouts.humanize
});
console.log('Accept all 已出现');
}
/**
* 润色
*/
async performPolish(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).nth(4).click();
await this.page.getByRole('button', { name: 'Start Polish' }).click();
console.log('等待 Polish 加载完成...');
await expect(this.page.getByText('All Suggestions')).toBeVisible({
timeout: this.config.timeouts.polish
});
console.log('All Suggestions 已出现');
}
/**
* 评分
*/
async performGetRated(): Promise<void> {
await this.page.getByRole('img', { name: 'trigger' }).nth(5).click();
await this.page.getByRole('button', { name: 'Get Rated' }).click();
console.log('等待 Get Rated 加载完成...');
await expect(this.page.getByRole('heading', { name: 'Your essay rating is:' })).toBeVisible({
timeout: this.config.timeouts.rated
});
console.log('Your essay rating is: 已出现');
}
/**
* Improvement 检查
*/
async performImprovementCheck(): Promise<void> {
await this.page.getByRole('tab', { name: 'Improvement' }).click();
console.log('等待 Improvement 加载完成...');
await expect(this.page.getByText('Accept all')).toBeVisible({
timeout: this.config.timeouts.improvement
});
console.log('Accept all 已出现');
}
/**
* 返回 Essay Writing (从其他页面)
*/
async returnToEssayWriting(): Promise<void> {
await this.page.getByRole('button', { name: 'Essay Writing' }).click();
await expect(this.page.getByRole('button', { name: 'icon Explore Essay Idea' })).toBeVisible({
timeout: 15000
});
}
/**
* 生成 Outline
*/
async generateOutline(): Promise<void> {
await this.page.getByRole('button', { name: 'icon Generate Outline First' }).click();
await this.page.getByRole('button', { name: 'Generate' }).click();
console.log('等待 Outline 生成...');
await expect(this.page.getByRole('heading', { name: 'Untitled Document' })).toBeVisible({
timeout: this.config.timeouts.aiGeneration
});
console.log('Outline 生成完成');
}
/**
* 生成 Draft
*/
async generateDraft(level: string, length: string): Promise<void> {
await this.page.getByRole('button', { name: 'icon Generate Draft' }).click();
await this.page.getByRole('button', { name: level }).click();
await this.page.getByPlaceholder('Enter the expected length...').click();
await this.page.getByPlaceholder('Enter the expected length...').fill(length);
await this.page.getByRole('button', { name: 'Generate' }).click();
console.log('等待 Draft 生成完成...');
const loadingMessage = this.page.getByText(/正在生成文书预计需要30秒请耐心等待/i);
console.log('等待加载消息出现...');
await loadingMessage.waitFor({ state: 'visible', timeout: 10000 });
console.log('加载消息已出现,文书正在生成中...');
}
}

50
pages/LoginPage.ts Normal file
View File

@ -0,0 +1,50 @@
/**
* 登录页面对象
* 封装登录相关的操作
*/
import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
export class LoginPage extends BasePage {
constructor(page: Page) {
super(page);
}
/**
* 访问首页
*/
async visitHomePage(): Promise<void> {
await this.goto(this.config.env.baseUrl);
await expect(this.page.getByRole('button', { name: 'Log in' })).toBeVisible();
}
/**
* 点击登录按钮
*/
async clickLoginButton(): Promise<void> {
await this.page.getByRole('button', { name: 'Log in' }).click();
await expect(this.page.getByRole('textbox', { name: 'Email Address' })).toBeVisible();
}
/**
* 输入登录凭证并登录
*/
async login(email: string, password: string): Promise<void> {
await this.page.getByRole('textbox', { name: 'Email Address' }).click();
await this.page.getByRole('textbox', { name: 'Email Address' }).fill(email);
await this.page.getByRole('textbox', { name: 'Psssword' }).click();
await this.page.getByRole('textbox', { name: 'Psssword' }).fill(password);
await this.page.getByRole('button', { name: 'Log in' }).click();
await expect(this.page.getByRole('link').filter({ hasText: '学生工作台' })).toBeVisible();
}
/**
* 完整登录流程
*/
async performLogin(): Promise<void> {
await this.visitHomePage();
await this.clickLoginButton();
await this.login(this.config.credentials.email, this.config.credentials.password);
}
}

64
pages/StudentPage.ts Normal file
View File

@ -0,0 +1,64 @@
/**
* 学生工作台页面对象
* 封装学生管理相关的操作
*/
import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
export interface StudentData {
name: string;
branchText: RegExp;
branchValue: RegExp;
counselorEmail: RegExp;
contractCategory: string;
contractName: string;
}
export class StudentPage extends BasePage {
constructor(page: Page) {
super(page);
}
/**
* 返回学生工作台
*/
async goToStudentWorkbench(): Promise<void> {
await this.page.getByRole('link').filter({ hasText: '学生工作台' }).click();
await expect(this.page.getByText('Student Name')).toBeVisible();
}
/**
* 创建新学生
*/
async createNewStudent(studentData: StudentData): Promise<void> {
await this.page.getByRole('button', { name: 'New Student' }).click();
// 填写学生名称
await this.page.getByRole('textbox', { name: 'Name *', exact: true }).click();
await this.page.getByRole('textbox', { name: 'Name *', exact: true }).fill(studentData.name);
// 选择分公司
await this.page.locator('div').filter({ hasText: studentData.branchText }).nth(2).click();
await this.page.locator('div').filter({ hasText: studentData.branchValue }).nth(1).click();
// 选择顾问
await this.page.getByText('Select counselor').click();
await this.page.locator('div').filter({ hasText: studentData.counselorEmail }).nth(1).click();
// 点击日期选择器关闭按钮
await this.page.locator('svg').nth(5).click();
// 填写合同信息
await this.page.getByRole('textbox', { name: 'Contract Category *' }).click();
await this.page.getByRole('textbox', { name: 'Contract Category *' }).fill(studentData.contractCategory);
await this.page.getByRole('textbox', { name: 'Contract Name *' }).click();
await this.page.getByRole('textbox', { name: 'Contract Name *' }).fill(studentData.contractName);
// 确认创建
await this.page.getByRole('button', { name: 'Confirm' }).click();
// 验证学生创建成功
await expect(this.page.getByText(studentData.name).first()).toBeVisible();
}
}