优化分批执行点击菜单

This commit is contained in:
dengqichen 2025-03-11 09:25:11 +08:00
parent f7fdf43abb
commit 47d7883874
9 changed files with 253 additions and 81 deletions

View File

@ -1,23 +1,25 @@
# 基础配置 # 基础配置
BASE_URL=https://ibp-test.longi.com/main/#/login?debug=ly BASE_URL=https://ibp-test.longi.com/main/#/login?debug=ly
USERNAME=zidonghuatest
PASSWORD=Lianyu_123 # 登录配置
IBP_USERNAME=zidonghuatest
IBP_PASSWORD=Lianyu_123
# 测试配置 # 测试配置
TEST_DATA_DIR=test-data TEST_DATA_DIR=test-data
TEST_BATCH_SIZE=5 TEST_BATCH_SIZE=2
TEST_RETRY_COUNT=3 TEST_RETRY_COUNT=3
TEST_BATCH_INTERVAL=1000 TEST_BATCH_INTERVAL=2000
TEST_MAX_RETRY_DELAY=5000 TEST_MAX_RETRY_DELAY=10000
# 超时配置 # 超时配置
MENU_TIME_OUT=30000 MENU_TIME_OUT=60000
EXPECT_TIMEOUT=3600000 EXPECT_TIMEOUT=3600000
# 浏览器配置 # 浏览器配置
BROWSER_HEADLESS=false BROWSER_HEADLESS=false
BROWSER_SLOW_MO=50 BROWSER_SLOW_MO=100
BROWSER_TIMEOUT=60000 BROWSER_TIMEOUT=120000
VIEWPORT_WIDTH=1920 VIEWPORT_WIDTH=1920
VIEWPORT_HEIGHT=1080 VIEWPORT_HEIGHT=1080
@ -27,5 +29,5 @@ TEST_PROGRESS_FILE_PATH=test-data/test-progress.json
# 页面加载配置 # 页面加载配置
PAGE_LOAD_MAX_RETRIES=5 PAGE_LOAD_MAX_RETRIES=5
PAGE_LOAD_RETRY_INTERVAL=2000 PAGE_LOAD_RETRY_INTERVAL=3000
PAGE_LOAD_STABILITY_DELAY=1000 PAGE_LOAD_STABILITY_DELAY=2000

View File

@ -1 +0,0 @@

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

View File

@ -9,61 +9,70 @@ $scriptPath = Join-Path $currentPath "run-tests.bat"
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
# Task Configuration # Task Configuration
$taskName = "Playwright_AutoTest" $taskNamePrefix = "Playwright_AutoTest"
$taskDesc = "Run Playwright tests daily" $taskDesc = "Run Playwright tests daily"
function Show-Menu { function Show-Menu {
Clear-Host Clear-Host
Write-Host "`n================== Playwright Test Manager ==================`n" Write-Host "`n================== Playwright Test Manager ==================`n"
Write-Host "1. View Task Status" Write-Host "1. View All Tasks Status"
Write-Host "2. Set Daily Task (Default: 23:00)" Write-Host "2. Set Daily Task - DEV Environment (Default: 23:00)"
Write-Host "3. Change Task Time" Write-Host "3. Set Daily Task - UAT Environment"
Write-Host "4. Run Test Now" Write-Host "4. Run Test Now"
Write-Host "5. Delete Task" Write-Host "5. Delete Tasks"
Write-Host "Q. Exit" Write-Host "Q. Exit"
Write-Host "`nEnter your choice (1-5, or Q to exit): " -NoNewline Write-Host "`nEnter your choice (1-5, or Q to exit): " -NoNewline
} }
function Get-TaskStatus { function Get-TaskStatus {
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue $environments = @("Dev", "UAT")
if ($task) { $found = $false
Write-Host "`nTask Status:"
Write-Host "Name: $taskName" Write-Host "`nTasks Status:"
Write-Host "State: $($task.State)" foreach ($env in $environments) {
$taskName = "${taskNamePrefix}_$env"
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
$trigger = $task.Triggers[0] if ($task) {
if ($trigger) { $found = $true
Write-Host "Schedule: Daily at $($trigger.StartBoundary.Split('T')[1].Substring(0,5))" Write-Host "`n$env Environment Task:"
# 安全地处理 NextRunTime Write-Host "Name: $taskName"
try { Write-Host "State: $($task.State)"
if ($task.NextRunTime) {
Write-Host "Next Run: $($task.NextRunTime.ToString('yyyy-MM-dd HH:mm'))" $trigger = $task.Triggers[0]
} else { if ($trigger) {
Write-Host "Next Run: Not yet scheduled" Write-Host "Schedule: Daily at $($trigger.StartBoundary.Split('T')[1].Substring(0,5))"
try {
if ($task.NextRunTime) {
Write-Host "Next Run: $($task.NextRunTime.ToString('yyyy-MM-dd HH:mm'))"
} else {
Write-Host "Next Run: Not yet scheduled"
}
} catch {
Write-Host "Next Run: Not available"
} }
} catch {
Write-Host "Next Run: Not available"
} }
} else {
Write-Host "Warning: No trigger found. Task needs to be reconfigured." Write-Host "Last Result: $($task.LastTaskResult)"
Write-Host "Working Directory: $($task.Actions[0].WorkingDirectory)"
Write-Host "Run As User: $($task.Principal.UserId)"
} }
}
Write-Host "Last Result: $($task.LastTaskResult)"
Write-Host "Working Directory: $($task.Actions[0].WorkingDirectory)" if (-not $found) {
Write-Host "Run As User: $($task.Principal.UserId)" Write-Host "`nNo tasks found. Please set up tasks using options 2 or 3."
Write-Host "Run Level: $($task.Principal.RunLevel)"
} else {
Write-Host "`nNo task found. Please set up a task using option 2."
} }
Pause-Script Pause-Script
} }
function Set-DailyTask { function Set-DailyTask {
param ( param (
[string]$runTime = "23:00" [string]$runTime = "23:00",
[string]$environment
) )
Write-Host "`nSetting up daily task..." $taskName = "${taskNamePrefix}_$environment"
Write-Host "`nSetting up daily task for $environment environment..."
$scriptPath = Join-Path $PSScriptRoot "run-tests.bat" $scriptPath = Join-Path $PSScriptRoot "run-tests.bat"
if (-not (Test-Path $scriptPath)) { if (-not (Test-Path $scriptPath)) {
@ -81,8 +90,9 @@ function Set-DailyTask {
} }
try { try {
# 创建任务操作 # 创建任务操作 - 添加环境参数
$action = New-ScheduledTaskAction -Execute $scriptPath -WorkingDirectory $PSScriptRoot $envArg = $environment.ToLower()
$action = New-ScheduledTaskAction -Execute $scriptPath -WorkingDirectory $PSScriptRoot -Argument $envArg
if (-not $action) { if (-not $action) {
throw "Failed to create task action" throw "Failed to create task action"
} }
@ -127,7 +137,7 @@ function Set-DailyTask {
} else { } else {
# 创建新任务 # 创建新任务
$result = Register-ScheduledTask -TaskName $taskName ` $result = Register-ScheduledTask -TaskName $taskName `
-Description $taskDesc ` -Description "$taskDesc ($environment Environment)" `
-Action $action ` -Action $action `
-Trigger $trigger ` -Trigger $trigger `
-Settings $settings ` -Settings $settings `
@ -145,6 +155,7 @@ function Set-DailyTask {
if ($updatedTask) { if ($updatedTask) {
Write-Host "`nTask Details:" Write-Host "`nTask Details:"
Write-Host "Task Name: $taskName" Write-Host "Task Name: $taskName"
Write-Host "Environment: $environment"
Write-Host "Run Time: Daily at $runTime" Write-Host "Run Time: Daily at $runTime"
if ($updatedTask.NextRunTime) { if ($updatedTask.NextRunTime) {
Write-Host "Next Run: $($updatedTask.NextRunTime.ToString('yyyy-MM-dd HH:mm'))" Write-Host "Next Run: $($updatedTask.NextRunTime.ToString('yyyy-MM-dd HH:mm'))"
@ -166,10 +177,25 @@ function Set-DailyTask {
} }
function Update-TaskTime { function Update-TaskTime {
Write-Host "`nSelect environment:"
Write-Host "1. Development (dev)"
Write-Host "2. UAT"
Write-Host "`nEnter your choice (1-2): " -NoNewline
$envChoice = Read-Host
$environment = switch ($envChoice) {
"1" { "dev" }
"2" { "uat" }
default {
Write-Host "`nInvalid choice. Using default (dev)"
"dev"
}
}
Write-Host "`nEnter new time (HH:mm, e.g. 02:00): " -NoNewline Write-Host "`nEnter new time (HH:mm, e.g. 02:00): " -NoNewline
$newTime = Read-Host $newTime = Read-Host
if ($newTime -match "^([01]?[0-9]|2[0-3]):[0-5][0-9]$") { if ($newTime -match "^([01]?[0-9]|2[0-3]):[0-5][0-9]$") {
Set-DailyTask -runTime $newTime Set-DailyTask -runTime $newTime -environment $environment
} else { } else {
Write-Host "`nInvalid time format" Write-Host "`nInvalid time format"
Pause-Script Pause-Script
@ -177,11 +203,26 @@ function Update-TaskTime {
} }
function Start-TestNow { function Start-TestNow {
Write-Host "`nStarting test..." Write-Host "`nSelect environment:"
Write-Host "1. Development (dev)"
Write-Host "2. UAT"
Write-Host "`nEnter your choice (1-2): " -NoNewline
$envChoice = Read-Host
$env = switch ($envChoice) {
"1" { "dev" }
"2" { "uat" }
default {
Write-Host "`nInvalid choice. Using default (dev)"
"dev"
}
}
Write-Host "`nStarting test in $env environment..."
try { try {
$scriptPath = Join-Path $PSScriptRoot "run-tests.bat" $scriptPath = Join-Path $PSScriptRoot "run-tests.bat"
# 使用cmd直接运行这样可以看到实时输出 # 使用cmd直接运行这样可以看到实时输出
& cmd /c $scriptPath & cmd /c $scriptPath $env
Write-Host "`nTest completed" Write-Host "`nTest completed"
} catch { } catch {
Write-Host "`nError: $_" Write-Host "`nError: $_"
@ -190,16 +231,37 @@ function Start-TestNow {
} }
function Remove-AutomationTask { function Remove-AutomationTask {
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue Write-Host "`nSelect tasks to delete:"
if ($task) { Write-Host "1. DEV Environment Task"
try { Write-Host "2. UAT Environment Task"
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false Write-Host "3. Both Tasks"
Write-Host "`nTask deleted" Write-Host "`nEnter your choice (1-3): " -NoNewline
} catch {
Write-Host "`nError: $_" $choice = Read-Host
$tasksToDelete = switch ($choice) {
"1" { @("Dev") }
"2" { @("UAT") }
"3" { @("Dev", "UAT") }
default {
Write-Host "`nInvalid choice."
Pause-Script
return
}
}
foreach ($env in $tasksToDelete) {
$taskName = "${taskNamePrefix}_$env"
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
if ($task) {
try {
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
Write-Host "`nTask '$taskName' deleted"
} catch {
Write-Host "`nError deleting task '$taskName': $_"
}
} else {
Write-Host "`nTask '$taskName' not found"
} }
} else {
Write-Host "`nNo task found"
} }
Pause-Script Pause-Script
} }
@ -216,8 +278,17 @@ do {
switch ($choice.ToUpper()) { switch ($choice.ToUpper()) {
"1" { Get-TaskStatus } "1" { Get-TaskStatus }
"2" { Set-DailyTask } "2" { Set-DailyTask -environment "Dev" }
"3" { Update-TaskTime } "3" {
Write-Host "`nEnter time for UAT task (HH:mm, e.g. 02:00): " -NoNewline
$uatTime = Read-Host
if ($uatTime -match "^([01]?[0-9]|2[0-3]):[0-5][0-9]$") {
Set-DailyTask -runTime $uatTime -environment "UAT"
} else {
Write-Host "`nInvalid time format"
Pause-Script
}
}
"4" { Start-TestNow } "4" { Start-TestNow }
"5" { Remove-AutomationTask } "5" { Remove-AutomationTask }
"Q" { exit } "Q" { exit }

View File

@ -2,6 +2,18 @@
const {defineConfig, devices} = require('@playwright/test'); const {defineConfig, devices} = require('@playwright/test');
const testLifecycle = require('./src/hooks/testLifecycle'); const testLifecycle = require('./src/hooks/testLifecycle');
/**
* Read environment variables and process them
*/
function getBaseUrl() {
const baseUrl = process.env.BASE_URL;
if (!baseUrl) {
throw new Error('BASE_URL environment variable is not set');
}
// 确保基础URL不包含hash和query参数
return baseUrl.split('#')[0].split('?')[0];
}
/** /**
* @see https://playwright.dev/docs/test-configuration * @see https://playwright.dev/docs/test-configuration
* @type {import('@playwright/test').PlaywrightTestConfig} * @type {import('@playwright/test').PlaywrightTestConfig}
@ -25,7 +37,7 @@ const config = {
/* 共享设置 */ /* 共享设置 */
use: { use: {
/* 基础URL */ /* 基础URL */
baseURL: process.env.BASE_URL, baseURL: getBaseUrl(),
/* 收集测试追踪信息 */ /* 收集测试追踪信息 */
trace: 'on-first-retry', trace: 'on-first-retry',
/* 自动截图 */ /* 自动截图 */

View File

@ -5,9 +5,19 @@ cd /d %~dp0
:: 设置控制台编码为UTF-8 :: 设置控制台编码为UTF-8
chcp 65001 > nul chcp 65001 > nul
:: 设置默认环境为dev
if "%1"=="" (
set TEST_ENV=dev
) else (
set TEST_ENV=%1
)
echo [Batch] Preparing to run tests in %TEST_ENV% environment...
:: 运行测试并发送报告 :: 运行测试并发送报告
set NODE_ENV=%TEST_ENV%
node src/scripts/runTestsAndSendReport.js node src/scripts/runTestsAndSendReport.js
echo. echo.
echo Execution completed echo [Batch] Execution completed
pause pause

View File

@ -76,10 +76,34 @@ class BasePage {
* @param {string} url 目标URL * @param {string} url 目标URL
*/ */
async navigate(url) { async navigate(url) {
// 先进行初始导航
await this.page.goto(url, { await this.page.goto(url, {
waitUntil: 'networkidle', waitUntil: 'networkidle',
timeout: this.config.timeout.navigate timeout: this.config.timeout.navigate
}); });
// 获取当前URL
const currentUrl = await this.page.url();
// 如果原始URL包含hash或query参数但当前URL没有则重新导航
if (url !== currentUrl) {
// 解析原始URL中的hash和query参数
const urlParts = url.split('#');
if (urlParts.length > 1) {
// 等待一下以确保页面已经初步加载
await this.page.waitForTimeout(1000);
// 使用evaluate来设置完整的URL
await this.page.evaluate((fullUrl) => {
window.location.href = fullUrl;
}, url);
// 等待页面加载完成
await this.page.waitForLoadState('networkidle', {
timeout: this.config.timeout.navigate
});
}
}
} }
/** /**

View File

@ -51,8 +51,12 @@ class LongiLoginPage extends BasePage {
* 导航到登录页面 * 导航到登录页面
*/ */
async navigateToLoginPage() { async navigateToLoginPage() {
console.log('当前使用的 BASE_URL:', process.env.BASE_URL); const baseUrl = process.env.BASE_URL;
await this.navigate(process.env.BASE_URL); console.log('当前使用的 BASE_URL:', baseUrl);
// 确保使用完整的URL包括hash和query参数
const fullUrl = baseUrl.includes('#') ? baseUrl : `${baseUrl}#/login?debug=ly`;
await this.navigate(fullUrl);
await this.waitForPageLoad(); await this.waitForPageLoad();
} }

View File

@ -2,72 +2,122 @@ const { execSync } = require('child_process');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const emailService = require('../services/EmailService'); const emailService = require('../services/EmailService');
const dotenv = require('dotenv');
// 获取环境参数
const env = process.env.TEST_ENV || 'dev'; // 默认使用dev环境
console.log(`[Node] Starting test execution process...`);
console.log(`[Node] Current environment: ${env}`);
async function runTestsAndSendReport() { async function runTestsAndSendReport() {
let testOutput = ''; let testOutput = '';
let testSuccess = false; let testSuccess = false;
const startTime = new Date(); const startTime = new Date();
console.log(`[Node] Test started at: ${startTime.toLocaleString()}`);
try { try {
// 根据环境设置加载对应的环境变量文件
const envFile = `.env.${env}`;
console.log(`[Node] Loading environment file: ${envFile}`);
// 检查环境文件是否存在
if (!fs.existsSync(envFile)) {
console.error(`[Node] Error: Environment file ${envFile} not found!`);
throw new Error(`Environment file ${envFile} not found`);
}
console.log(`[Node] Environment file found successfully`);
// 加载环境变量
dotenv.config({ path: envFile });
console.log(`[Node] Environment variables loaded successfully`);
// 运行测试并捕获输出 // 运行测试并捕获输出
console.log('开始执行测试...'); console.log('[Node] ==========================================');
testOutput = execSync('npx playwright test', { encoding: 'utf8' }); console.log('[Node] Starting Playwright test execution...');
console.log('[Node] ==========================================');
testOutput = execSync('npx playwright test', {
encoding: 'utf8',
env: {
...process.env,
NODE_ENV: env
},
stdio: 'inherit' // 这将允许实时显示测试输出
});
testSuccess = true; testSuccess = true;
console.log('测试执行完成'); console.log('[Node] ==========================================');
console.log('[Node] Test execution completed successfully');
console.log('[Node] ==========================================');
} catch (error) { } catch (error) {
console.log('[Node] ==========================================');
console.error('[Node] Test execution failed with error:');
console.error(error.message);
console.log('[Node] ==========================================');
testOutput = error.output ? error.output.join('\n') : error.message; testOutput = error.output ? error.output.join('\n') : error.message;
console.error('测试执行失败:', testOutput);
} }
const endTime = new Date(); const endTime = new Date();
const duration = (endTime - startTime) / 1000 / 60; // 转换为分钟 const duration = (endTime - startTime) / 1000 / 60; // 转换为分钟
console.log(`[Node] Test duration: ${duration.toFixed(2)} minutes`);
// 读取性能报告 // 读取性能报告
console.log('[Node] Attempting to read performance report...');
let performanceData = ''; let performanceData = '';
try { try {
const reportPath = path.join(process.cwd(), 'test-results', 'performance-report.html'); const reportPath = path.join(process.cwd(), 'test-results', 'performance-report.html');
if (fs.existsSync(reportPath)) { if (fs.existsSync(reportPath)) {
performanceData = fs.readFileSync(reportPath, 'utf8'); performanceData = fs.readFileSync(reportPath, 'utf8');
console.log('[Node] Performance report read successfully');
} else {
console.log('[Node] No performance report found');
} }
} catch (error) { } catch (error) {
console.error('读取性能报告失败:', error); console.error('[Node] Failed to read performance report:', error.message);
} }
// 构建邮件内容 // 构建邮件内容
console.log('[Node] Preparing email report...');
const emailHtml = ` const emailHtml = `
<h1>Playwright 自动化测试报告</h1> <h1>Playwright 自动化测试报告 (${env}环境)</h1>
<div style="margin: 20px 0; padding: 10px; background-color: ${testSuccess ? '#e6ffe6' : '#ffe6e6'}; border-radius: 5px;"> <div style="margin: 20px 0; padding: 10px; background-color: ${testSuccess ? '#e6ffe6' : '#ffe6e6'}; border-radius: 5px;">
<h2>测试结果: ${testSuccess ? '成功 ✅' : '失败 ❌'}</h2> <h2>测试结果: ${testSuccess ? '成功 ✅' : '失败 ❌'}</h2>
<p>执行环境: ${env}</p>
<p>执行时间: ${startTime.toLocaleString()}</p> <p>执行时间: ${startTime.toLocaleString()}</p>
<p>持续时间: ${duration.toFixed(2)} 分钟</p> <p>持续时间: ${duration.toFixed(2)} 分钟</p>
</div> </div>
<h2>测试输出</h2>
<pre style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; overflow-x: auto;">
${testOutput}
</pre>
${performanceData ? '<h2>性能报告</h2>' + performanceData : ''} ${performanceData ? '<h2>性能报告</h2>' + performanceData : ''}
`; `;
// 发送邮件 // 发送邮件
try { try {
console.log('正在发送测试报告邮件...'); console.log('[Node] ==========================================');
console.log('[Node] Sending test report email...');
const result = await emailService.sendMail({ const result = await emailService.sendMail({
to: 'dengqichen@iscmtech.com', to: 'dengqichen@iscmtech.com',
subject: `[${testSuccess ? '成功' : '失败'}] Playwright自动化测试报告 - ${startTime.toLocaleDateString()}`, subject: `[${testSuccess ? '成功' : '失败'}] Playwright自动化测试报告 (${env}) - ${startTime.toLocaleDateString()}`,
html: emailHtml html: emailHtml
}); });
if (result.success) { if (result.success) {
console.log('测试报告邮件发送成功'); console.log('[Node] Test report email sent successfully');
} else { } else {
console.error('测试报告邮件发送失败:', result.error); console.error('[Node] Failed to send test report email:', result.error);
} }
console.log('[Node] ==========================================');
} catch (error) { } catch (error) {
console.error('发送邮件时发生错误:', error); console.log('[Node] ==========================================');
console.error('[Node] Error sending email:', error.message);
console.log('[Node] ==========================================');
} }
} }
// 执行脚本 // 执行脚本
runTestsAndSendReport(); console.log('[Node] ==========================================');
console.log('[Node] Starting test automation process...');
console.log('[Node] ==========================================');
runTestsAndSendReport().catch(error => {
console.error('[Node] Fatal error:', error);
process.exit(1);
});