268 lines
12 KiB
TypeScript
268 lines
12 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||
import * as fs from 'fs';
|
||
import * as path from 'path';
|
||
|
||
test('test', async ({ page }) => {
|
||
test.setTimeout(600000); // 设置超时时间为10分钟,因为有多个 AI 生成步骤和长时间等待
|
||
|
||
// 错误收集数组
|
||
const errors: { step: string; error: string; timestamp: string; pageUrl: string }[] = [];
|
||
|
||
// 登录信息(用于报告)
|
||
const loginInfo = {
|
||
email: 'xdf.admin@applify.ai',
|
||
password: 'b9#0!;+{Tx4649op'
|
||
};
|
||
|
||
// 辅助函数:执行步骤并捕获错误
|
||
const executeStep = async (stepName: string, stepFunction: () => Promise<void>) => {
|
||
try {
|
||
console.log(`\n[执行] ${stepName}`);
|
||
await stepFunction();
|
||
console.log(`[成功] ${stepName}`);
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||
const timestamp = new Date().toISOString();
|
||
const pageUrl = page.url(); // 获取出错时的页面URL
|
||
errors.push({ step: stepName, error: errorMessage, timestamp, pageUrl });
|
||
console.error(`[失败] ${stepName}: ${errorMessage}`);
|
||
console.error(`[页面URL] ${pageUrl}`);
|
||
// 继续执行下一步,不中断测试流程
|
||
}
|
||
};
|
||
|
||
// 步骤1: 访问首页并登录
|
||
await executeStep('访问首页', async () => {
|
||
await page.goto('https://pre.prodream.cn/en');
|
||
await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible();
|
||
});
|
||
|
||
await executeStep('点击登录按钮', async () => {
|
||
await page.getByRole('button', { name: 'Log in' }).click();
|
||
await expect(page.getByRole('textbox', { name: 'Email Address' })).toBeVisible();
|
||
});
|
||
|
||
await executeStep('输入登录信息', async () => {
|
||
await page.getByRole('textbox', { name: 'Email Address' }).click();
|
||
await page.getByRole('textbox', { name: 'Email Address' }).fill('xdf.admin@applify.ai');
|
||
await page.getByRole('textbox', { name: 'Psssword' }).click();
|
||
await page.getByRole('textbox', { name: 'Psssword' }).fill('b9#0!;+{Tx4649op');
|
||
await page.getByRole('button', { name: 'Log in' }).click();
|
||
await expect(page.getByRole('link').filter({ hasText: '学生工作台' })).toBeVisible();
|
||
});
|
||
|
||
// 步骤2: 测试 DreamiExplore
|
||
await executeStep('进入 DreamiExplore', async () => {
|
||
await page.getByRole('link').filter({ hasText: 'DreamiExplore Everything' }).click();
|
||
await expect(page.getByRole('heading', { name: 'Hello, Admin' })).toBeVisible();
|
||
});
|
||
|
||
await executeStep('测试聊天功能', async () => {
|
||
await page.getByRole('textbox').click();
|
||
await page.getByRole('textbox').fill('hello');
|
||
await page.getByRole('button', { name: 'send' }).click();
|
||
await expect(page.getByRole('button', { name: '复制' })).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
// 步骤3: 创建新学生
|
||
await executeStep('返回学生工作台', async () => {
|
||
await page.getByRole('link').filter({ hasText: '学生工作台' }).click();
|
||
await expect(page.getByText('Student Name')).toBeVisible();
|
||
});
|
||
|
||
await executeStep('创建新学生', async () => {
|
||
await page.getByRole('button', { name: 'New Student' }).click();
|
||
await page.getByRole('textbox', { name: 'Name *', exact: true }).click();
|
||
await page.getByRole('textbox', { name: 'Name *', exact: true }).fill('黄子旭测试');
|
||
await page.locator('div').filter({ hasText: /^请选择分公司$/ }).nth(2).click();
|
||
await page.locator('div').filter({ hasText: /^1$/ }).nth(1).click();
|
||
await page.getByText('Select counselor').click();
|
||
await page.locator('div').filter({ hasText: /^2-2@2\.com$/ }).nth(1).click();
|
||
await page.locator('svg').nth(5).click();
|
||
await page.getByRole('textbox', { name: 'Contract Category *' }).click();
|
||
await page.getByRole('textbox', { name: 'Contract Category *' }).fill('11');
|
||
await page.getByRole('textbox', { name: 'Contract Name *' }).click();
|
||
await page.getByRole('textbox', { name: 'Contract Name *' }).fill('11');
|
||
await page.getByRole('button', { name: 'Confirm' }).click();
|
||
// 等待学生创建成功,使用 first() 处理多个匹配
|
||
await expect(page.getByText('黄子旭测试').first()).toBeVisible();
|
||
});
|
||
|
||
// 步骤4: Essay Writing 流程
|
||
await executeStep('进入 Essay Writing', async () => {
|
||
await page.getByRole('button', { name: 'documents Essay Writing' }).first().click();
|
||
await expect(page.getByText('Notes')).toBeVisible();
|
||
});
|
||
|
||
await executeStep('添加材料', async () => {
|
||
await page.getByRole('button', { name: 'Add Material' }).click();
|
||
await page.getByRole('menuitem', { name: 'Manual Add' }).click();
|
||
await expect(page.getByText('ClassificationGeneralGeneralAcademic Interests and AchievementsInternship and')).toBeVisible();
|
||
await page.getByRole('textbox', { name: 'Title' }).click();
|
||
await page.getByRole('textbox', { name: 'Title' }).fill('i like Math and English');
|
||
await page.getByRole('paragraph').filter({ hasText: /^$/ }).click();
|
||
await page.locator('.tiptap').fill('i like Math and English');
|
||
await page.getByRole('button', { name: 'icon Get Suggestions' }).click();
|
||
await expect(page.getByRole('heading', { name: 'More Suggestions' })).toBeVisible();
|
||
await page.getByRole('button', { name: 'Create', exact: true }).click();
|
||
await expect(page.getByRole('button', { name: 'General i like Math and' })).toBeVisible({ timeout: 15000 });
|
||
// 等待页面稳定后再点击
|
||
await page.waitForTimeout(1000);
|
||
});
|
||
|
||
await executeStep('探索 Essay Idea', async () => {
|
||
await page.getByRole('button', { name: 'icon Explore Essay Idea' }).click();
|
||
await expect(page.getByRole('heading', { name: 'Select an essay prompt or' })).toBeVisible();
|
||
});
|
||
|
||
await executeStep('加载 Recommendation', async () => {
|
||
// 点击 Recommendation 按钮
|
||
await page.getByRole('button', { name: 'icon Recommendation' }).click();
|
||
await page.waitForTimeout(10000);
|
||
console.log('等待 Recommendation 加载完成...');
|
||
await expect(page.getByRole('heading', { name: 'Recommendation Material' })).toBeVisible({ timeout: 120000 });
|
||
console.log('Recommendation Material 已出现');
|
||
});
|
||
|
||
await executeStep('生成 Essay Idea', async () => {
|
||
await page.getByRole('button', { name: 'icon Generate Essay Idea' }).click();
|
||
await page.getByRole('button', { name: 'Generate' }).click();
|
||
// AI 生成需要时间,增加超时
|
||
await expect(page.getByRole('heading', { name: 'Essay Idea' })).toBeVisible({ timeout: 60000 });
|
||
});
|
||
|
||
await executeStep('生成 Essay', async () => {
|
||
await page.getByRole('button', { name: 'icon Generate Essay' }).click();
|
||
await page.getByRole('button', { name: 'Generate' }).click();
|
||
// 等待 Essay 生成完成 - 通过检测占位符文本消失来判断
|
||
console.log('等待 Essay 生成完成...');
|
||
const placeholderText = page.getByText(/正在生成文书,预计需要30秒,请耐心等待/i);
|
||
// 等待占位符文本消失,最多等待 4 分钟(240秒)
|
||
await placeholderText.waitFor({ state: 'hidden', timeout: 240000 });
|
||
console.log('Essay 生成完成,占位符已消失');
|
||
// 等待 10 秒钟让页面稳定
|
||
await page.waitForTimeout(10000);
|
||
});
|
||
|
||
// 步骤5: 各种检查功能
|
||
await executeStep('语法检查 (Grammar Check)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).first().click();
|
||
await page.getByRole('button', { name: 'Start Grammar Check' }).click();
|
||
// 语法检查需要时间
|
||
console.log('等待 Start Grammar Check 加载完成...');
|
||
await expect(page.getByRole('heading', { name: 'suggestions' })).toBeVisible({ timeout: 120000 });
|
||
console.log('suggestions 已出现');
|
||
await expect(page.getByLabel('suggestions')).toBeVisible({ timeout: 30000 });
|
||
});
|
||
|
||
await executeStep('查重检查 (Plagiarism Check)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).nth(1).click();
|
||
await page.getByRole('button', { name: 'Start Plagiarism Check' }).click();
|
||
console.log('等待 Start Plagiarism Check 加载完成...');
|
||
// 查重检查需要较长时间
|
||
await expect(page.getByRole('button', { name: 'Re-check' })).toBeVisible({ timeout: 100000 });
|
||
console.log('Re-check 已出现');
|
||
});
|
||
|
||
await executeStep('AI检测 (AI Detection)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).nth(2).click();
|
||
await page.getByRole('button', { name: 'Start AI Detection' }).click();
|
||
console.log('等待 Start AI Detection 加载完成...');
|
||
await expect(page.getByRole('heading', { name: 'GPTZero Premium' })).toBeVisible({ timeout: 80000 });
|
||
console.log('GPTZero Premium 已出现');
|
||
});
|
||
|
||
await executeStep('人性化处理 (Humanize)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).nth(3).click();
|
||
await page.getByRole('button', { name: 'Start Humanize' }).click();
|
||
console.log('等待 Start Humanize 加载完成...');
|
||
await expect(page.getByText('Accept all')).toBeVisible({ timeout: 110000 });
|
||
console.log('Accept all 已出现');
|
||
});
|
||
|
||
await executeStep('润色 (Polish)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).nth(4).click();
|
||
await page.getByRole('button', { name: 'Start Polish' }).click();
|
||
console.log('等待 Start Polish 加载完成...');
|
||
await expect(page.getByText('All Suggestions')).toBeVisible({ timeout: 110000 });
|
||
console.log('All Suggestions 已出现');
|
||
});
|
||
|
||
await executeStep('评分 (Get Rated)', async () => {
|
||
await page.getByRole('img', { name: 'trigger' }).nth(5).click();
|
||
await page.getByRole('button', { name: 'Get Rated' }).click();
|
||
console.log('等待 Get Rated 加载完成...');
|
||
await expect(page.getByRole('heading', { name: 'Your essay rating is:' })).toBeVisible({ timeout: 120000 });
|
||
console.log('Your essay rating is: 已出现');
|
||
});
|
||
|
||
await executeStep('Improvement 检查', async () => {
|
||
await page.getByRole('tab', { name: 'Improvement' }).click();
|
||
console.log('等待 Improvement 加载完成...');
|
||
await expect(page.getByRole('heading', { name: 'Suggestions' })).toBeVisible({ timeout: 120000 });
|
||
console.log('Suggestions 已出现)');
|
||
});
|
||
|
||
// 最后输出错误汇总
|
||
console.log('\n\n========== 测试执行完成 ==========');
|
||
|
||
// 生成错误报告文件
|
||
const generateErrorReport = () => {
|
||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||
const reportPath = path.join(process.cwd(), `test-error-report-${timestamp}.txt`);
|
||
|
||
let report = '========== 测试错误报告 ==========\n\n';
|
||
report += `报告生成时间: ${new Date().toLocaleString('zh-CN')}\n\n`;
|
||
|
||
// 第一部分:登录账号信息(只显示一次)
|
||
report += '【登录账号信息】\n';
|
||
report += `账号: ${loginInfo.email}\n`;
|
||
report += `密码: ${loginInfo.password}\n`;
|
||
report += `测试环境: https://pre.prodream.cn/en\n\n`;
|
||
report += `${'='.repeat(60)}\n\n`;
|
||
|
||
if (errors.length === 0) {
|
||
report += '✅ 所有功能测试通过,未发现问题!\n';
|
||
} else {
|
||
report += `发现 ${errors.length} 个问题,详情如下:\n\n`;
|
||
|
||
// 每个错误按照格式:问题功能 + 页面链接
|
||
errors.forEach((err, index) => {
|
||
report += `【问题 ${index + 1}】\n`;
|
||
report += `问题功能: ${err.step}\n`;
|
||
report += `页面链接: ${err.pageUrl}\n`;
|
||
report += `错误详情: ${err.error}\n`;
|
||
report += `发生时间: ${new Date(err.timestamp).toLocaleString('zh-CN')}\n`;
|
||
report += '\n';
|
||
});
|
||
|
||
report += `${'='.repeat(60)}\n`;
|
||
report += `\n说明: 测试过程中遇到错误会自动跳过并继续执行后续步骤。\n`;
|
||
}
|
||
|
||
fs.writeFileSync(reportPath, report, 'utf-8');
|
||
return reportPath;
|
||
};
|
||
|
||
if (errors.length === 0) {
|
||
console.log('✅ 所有步骤执行成功!');
|
||
} else {
|
||
console.log(`\n⚠️ 发现 ${errors.length} 个问题:\n`);
|
||
errors.forEach((err, index) => {
|
||
console.log(`【问题 ${index + 1}】`);
|
||
console.log(` 问题功能: ${err.step}`);
|
||
console.log(` 页面链接: ${err.pageUrl}`);
|
||
console.log(` 错误详情: ${err.error}`);
|
||
console.log('');
|
||
});
|
||
|
||
// 生成并保存错误报告文件
|
||
const reportPath = generateErrorReport();
|
||
console.log(`📄 详细错误报告已保存到: ${reportPath}`);
|
||
console.log(`\n账号: ${loginInfo.email}`);
|
||
console.log(`密码: ${loginInfo.password}\n`);
|
||
|
||
// 不抛出错误,让测试标记为通过,但在日志中记录所有失败步骤
|
||
}
|
||
});
|