Executor API¶
Executor 负责测试执行,通过 Playwright CLI 运行测试。继承自 EventEmitter,支持事件监听。
Executor 类¶
构造函数¶
创建 Executor 实例。构造函数会对 config 进行默认值合并:
| 字段 | 默认值 |
|---|---|
retries |
0 |
timeout |
30000 |
workers |
1 |
shards |
1 |
browsers |
['chromium'] |
htmlReport |
true |
构造时会根据配置自动初始化以下管理器(仅在对应配置 enabled 时创建):
TraceManager— 追踪管理AnnotationManager— 注解管理TagManager— 标签管理ArtifactManager— 产物管理VisualTestingManager— 视觉测试管理
execute(options?)¶
执行测试运行。
async execute(options?: {
shardIndex?: number;
shardTotal?: number;
grepPattern?: string;
tagFilter?: string[];
updateSnapshots?: boolean;
projectFilter?: string;
testFiles?: string[];
testLocations?: string[];
parentRunId?: string;
}): Promise<RunResult>
参数说明¶
| 参数 | 类型 | 说明 |
|---|---|---|
shardIndex |
number |
分片索引(从 0 开始) |
shardTotal |
number |
分片总数 |
grepPattern |
string |
匹配测试标题的正则模式 |
tagFilter |
string[] |
标签过滤器列表 |
updateSnapshots |
boolean |
是否更新快照 |
projectFilter |
string |
Playwright 项目过滤器 |
testFiles |
string[] |
指定测试文件列表 |
testLocations |
string[] |
指定测试位置列表 |
parentRunId |
string |
父运行 ID,用于重跑场景 |
environmentTag |
string |
环境标签,用于多环境报告 |
执行流程¶
- 检查是否已在运行,若正在运行则抛出
PlaywrightRunnerError(ALREADY_RUNNING) - 生成运行 ID(格式:
run_YYYYMMDD_HHmmss_随机串) - 初始化
RunResult对象 - 过滤隔离测试(quarantined tests)
- 准备运行环境(创建输出目录、初始化管理器、扫描注解和标签)
- 通过 Playwright CLI 执行测试
- 后处理(移动 HTML 报告、发现追踪文件、发现产物、运行视觉测试)
- 返回
RunResult
如果执行过程中发生异常,RunResult.status 会被设为 'failed'。无论成功或失败,都会设置 endTime 和 duration,并触发 run_completed 事件。
cancel()¶
取消当前正在运行的测试。
取消行为:
- 在 Windows 上使用
taskkill /F /T /PID终止进程树 - 在 Unix 上先发送
SIGTERM,3 秒后若进程仍在运行则发送SIGKILL - 将
RunResult.status设为'cancelled' - 触发
run_cancelled事件
其他方法¶
| 方法 | 返回类型 | 说明 |
|---|---|---|
getCurrentStatus() |
Promise<RunResult \| null> |
获取当前运行结果 |
isCurrentlyRunning() |
boolean |
检查是否正在执行 |
getConfig() |
TestConfig |
获取配置副本 |
getTestArtifacts(runId) |
Promise<{ screenshots, videos, traces }> |
获取指定运行的测试产物 |
getTraceManager() |
TraceManager \| null |
获取追踪管理器 |
getAnnotationManager() |
AnnotationManager \| null |
获取注解管理器 |
getTagManager() |
TagManager \| null |
获取标签管理器 |
getArtifactManager() |
ArtifactManager \| null |
获取产物管理器 |
getVisualManager() |
VisualTestingManager \| null |
获取视觉测试管理器 |
属性¶
| 属性 | 类型 | 说明 |
|---|---|---|
currentRun |
RunResult \| null |
当前运行结果(只读 getter) |
事件¶
Executor 继承自 EventEmitter,支持以下事件:
| 事件 | 参数 | 说明 |
|---|---|---|
run_started |
{ runId: string, timestamp: number } |
运行开始 |
test_result |
TestResult |
单个测试结果 |
run_progress |
RunProgress |
运行进度更新 |
run_completed |
RunResult |
运行完成 |
run_cancelled |
RunResult \| null |
运行被取消 |
output |
{ data: string, timestamp: number, runId: string, type?: string } |
输出数据(stdout/stderr/info) |
error |
{ error: string, runId: string } |
错误事件 |
annotations_scanned |
{ runId: string, summary } |
注解扫描完成 |
tags_scanned |
{ runId: string, summary } |
标签扫描完成 |
ParallelExecutor 类¶
并行执行器,创建多个 Executor 实例分片执行测试。
构造函数¶
创建 shardCount 个 Executor 实例,每个分片使用独立的输出目录(outputDir/shard-{i})。
方法¶
| 方法 | 返回类型 | 说明 |
|---|---|---|
execute() |
Promise<RunResult[]> |
并行执行所有分片 |
cancelAll() |
Promise<void> |
取消所有分片执行 |
PlaywrightReportParser 类¶
Playwright JSON 报告文件解析器。
构造函数¶
创建 PlaywrightReportParser 实例。
方法¶
| 方法 | 返回类型 | 说明 |
|---|---|---|
parse(filePath) |
Promise<ParsedReport> |
解析 Playwright JSON 报告文件 |
parseContent(content) |
ParsedReport |
解析 Playwright JSON 报告内容字符串 |
ProgressTracker 类¶
测试运行进度追踪器。
构造函数¶
创建 ProgressTracker 实例。
方法¶
| 方法 | 返回类型 | 说明 |
|---|---|---|
startRun(runId, totalTests) |
void |
开始追踪测试运行 |
updateProgress(runId, result) |
ProgressMessage |
使用测试结果更新进度 |
getProgress(runId) |
ProgressMessage \| null |
获取运行当前进度 |
completeRun(runId) |
void |
标记运行为已完成 |
类型定义¶
TestConfig¶
interface TestConfig {
version: string;
testDir: string;
outputDir: string;
baseURL?: string;
retries?: number;
timeout?: number;
workers?: number;
shards?: number;
reporters?: string[];
browsers?: BrowserType[];
headers?: Record<string, string>;
flakyThreshold?: number;
isolateFlaky?: boolean;
traces?: TraceConfig;
artifacts?: ArtifactConfig;
visualTesting?: VisualTestingConfig;
annotations?: AnnotationConfig;
tags?: TagConfig;
htmlReport?: boolean;
htmlReportDir?: string;
parentRunId?: string;
retryIndex?: number;
testMatch?: string[];
testIgnore?: string[];
ignoreDirs?: string[];
}
BrowserType¶
TestResult¶
interface TestResult {
id: string;
title: string;
fullTitle?: string;
file?: string;
line?: number;
column?: number;
status: 'passed' | 'failed' | 'skipped' | 'timedout';
duration: number;
error?: string;
retries: number;
manualReruns?: number;
runHistory?: TestRunHistory[];
timestamp: number;
browser: BrowserType;
shard?: number;
screenshots?: string[];
videos?: string[];
traces?: string[];
logs?: string[];
stackTrace?: string;
}
RunResult¶
interface RunResult {
id: string;
version: string;
status: 'success' | 'failed' | 'cancelled' | 'running';
startTime: number;
endTime?: number;
duration?: number;
suites: SuiteResult[];
totalTests: number;
passed: number;
failed: number;
skipped: number;
flakyTests: TestResult[];
metadata?: RunMetadata;
}
SuiteResult¶
interface SuiteResult {
name: string;
totalTests: number;
passed: number;
failed: number;
skipped: number;
duration: number;
tests: TestResult[];
timestamp: number;
}
TestRunHistory¶
interface TestRunHistory {
timestamp: number;
status: 'passed' | 'failed' | 'skipped' | 'timedout';
duration: number;
error?: string;
screenshots?: string[];
videos?: string[];
traces?: string[];
stackTrace?: string;
logs?: string[];
}
RunMetadata¶
interface RunMetadata {
annotations?: RunMetadataAnnotation[];
tags?: RunMetadataTag[];
traces?: RunMetadataTraces;
artifacts?: RunMetadataArtifacts;
visualTesting?: RunMetadataVisualTesting;
skippedQuarantinedTests?: string[];
globalErrors?: RunMetadataGlobalError[];
[key: string]: unknown;
}
RunMetadataAnnotation¶
RunMetadataTag¶
RunMetadataTraces¶
RunMetadataTraceFile¶
RunMetadataArtifacts¶
RunMetadataVisualTesting¶
interface RunMetadataVisualTesting {
passRate: number;
identical: number;
different: number;
regression: number;
new: number;
results: RunMetadataVisualResult[];
}
RunMetadataVisualResult¶
RunMetadataGlobalError¶
QuarantineConfig¶
ParsedReport¶
interface ParsedReport {
suites: SuiteResult[];
totalTests: number;
passed: number;
failed: number;
skipped: number;
duration: number;
metadata?: RunMetadata;
}
ProgressMessage¶
interface ProgressMessage {
runId: string;
totalTests: number;
completed: number;
passed: number;
failed: number;
skipped: number;
progress: number;
isCompleted: boolean;
}
PlaywrightJSONReport¶
interface PlaywrightJSONReport {
config: {
files: string[];
projects: { name: string; outputDir: string; repeatEach: number; retries: number; use: Record<string, unknown> }[];
version: string;
};
suites: {
title: string;
file: string;
specs: {
title: string;
ok: boolean;
tags: string[];
tests: {
projectName: string;
results: {
status: string;
duration: number;
error?: { message: string; stack: string };
attachments: { name: string; path?: string; contentType: string }[];
}[];
status: string;
}[];
}[];
}[];
}
示例¶
基本使用¶
import { Executor } from 'yuantest-playwright';
const executor = new Executor({
version: '1.0.0',
testDir: './e2e',
outputDir: './reports',
});
const result = await executor.execute();
console.log(`Passed: ${result.passed}/${result.totalTests}`);
监听事件¶
executor.on('run_started', (data) => {
console.log(`Run started: ${data.runId}`);
});
executor.on('test_result', (result) => {
const icon = result.status === 'passed' ? '✓' : '✗';
console.log(`${icon} ${result.title} (${result.duration}ms)`);
});
executor.on('run_progress', (progress) => {
console.log(`Progress: ${progress.passed}/${progress.totalTests}`);
});
executor.on('run_completed', (result) => {
console.log('Run completed!');
console.log(`Passed: ${result.passed}`);
console.log(`Failed: ${result.failed}`);
console.log(`Skipped: ${result.skipped}`);
});
executor.on('output', (data) => {
process.stdout.write(data.data);
});
使用过滤选项¶
const result = await executor.execute({
grepPattern: 'smoke',
projectFilter: 'chromium',
tagFilter: ['@critical'],
updateSnapshots: false,
testFiles: ['tests/login.spec.ts'],
});
分片执行¶
取消执行¶
setTimeout(async () => {
if (executor.isCurrentlyRunning()) {
await executor.cancel();
console.log('Execution cancelled');
}
}, 60000);