tdpw
Version:
CLI tool for uploading Playwright test reports to TestDino platform with TestDino storage support
252 lines • 10.8 kB
JavaScript
;
/**
* Playwright configuration and shard detection utilities
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlaywrightShardDetector = void 0;
const tslib_1 = require("tslib");
const fs_1 = require("../utils/fs");
const path_1 = tslib_1.__importDefault(require("path"));
/**
* Playwright configuration parser for shard detection
*/
class PlaywrightShardDetector {
/**
* Auto-detect shard information from Playwright configuration and environment
*/
static async detectShardInfo(workingDir) {
try {
// Strategy 1: Check environment variables first (most reliable in CI)
const envShard = this.detectFromEnvironment();
if (envShard) {
return envShard;
}
// Strategy 2: Read from Playwright configuration files
const configShard = await this.detectFromPlaywrightConfig(workingDir);
if (configShard) {
return configShard;
}
// Strategy 3: Analyze JSON reports for shard indicators
const reportShard = await this.detectFromReports(workingDir);
if (reportShard) {
return reportShard;
}
return null;
}
catch (_error) {
// Return null on any error - shard detection is best-effort
return null;
}
}
/**
* Detect shard info from environment variables
*/
static detectFromEnvironment() {
try {
const env = process.env;
// GitHub Actions matrix strategy
if (env.GITHUB_ACTIONS && env.SHARD_INDEX && env.SHARD_TOTAL) {
const shardIndex = parseInt(env.SHARD_INDEX, 10);
const shardTotal = parseInt(env.SHARD_TOTAL, 10);
if (shardIndex > 0 && shardTotal > 0) {
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
// GitLab CI parallel jobs
if (env.GITLAB_CI && env.CI_NODE_INDEX && env.CI_NODE_TOTAL) {
const shardIndex = parseInt(env.CI_NODE_INDEX, 10) + 1; // GitLab is 0-indexed
const shardTotal = parseInt(env.CI_NODE_TOTAL, 10);
if (shardIndex > 0 && shardTotal > 0) {
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
// CircleCI parallelism
if (env.CIRCLECI && env.CIRCLE_NODE_INDEX && env.CIRCLE_NODE_TOTAL) {
const shardIndex = parseInt(env.CIRCLE_NODE_INDEX, 10) + 1; // CircleCI is 0-indexed
const shardTotal = parseInt(env.CIRCLE_NODE_TOTAL, 10);
if (shardIndex > 0 && shardTotal > 0) {
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
// Generic environment variables
if (env.SHARD_INDEX && env.SHARD_TOTAL) {
const shardIndex = parseInt(env.SHARD_INDEX, 10);
const shardTotal = parseInt(env.SHARD_TOTAL, 10);
if (shardIndex > 0 && shardTotal > 0) {
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
return null;
}
catch {
return null;
}
}
/**
* Detect shard info from Playwright configuration files
*/
static async detectFromPlaywrightConfig(workingDir) {
const configFiles = [
'playwright.config.ts',
'playwright.config.js',
'playwright.config.mjs',
'playwright.config.cjs',
];
for (const configFile of configFiles) {
const configPath = path_1.default.join(workingDir, configFile);
if (await (0, fs_1.exists)(configPath)) {
try {
const configContent = await (0, fs_1.readFileBuffer)(configPath);
const configText = configContent.toString();
// Look for shard configuration patterns
const shardMatch = configText.match(/shard:\s*(\d+)\s*\/\s*(\d+)/);
if (shardMatch?.[1] && shardMatch[2]) {
const shardIndex = parseInt(shardMatch[1], 10);
const shardTotal = parseInt(shardMatch[2], 10);
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
// Look for CLI shard argument patterns
const cliShardMatch = configText.match(/--shard[=\s]+(\d+)\/(\d+)/);
if (cliShardMatch?.[1] && cliShardMatch[2]) {
const shardIndex = parseInt(cliShardMatch[1], 10);
const shardTotal = parseInt(cliShardMatch[2], 10);
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
catch {
// Continue to next config file on error
continue;
}
}
}
return null;
}
/**
* Detect shard info from JSON reports (look for metadata in reports)
*/
static async detectFromReports(workingDir) {
try {
// Common report locations
const reportPaths = [
path_1.default.join(workingDir, 'playwright-report', 'report.json'),
path_1.default.join(workingDir, 'playwright-report', 'results.json'),
path_1.default.join(workingDir, 'test-results', 'results.json'),
path_1.default.join(workingDir, 'test-results', 'report.json'),
path_1.default.join(workingDir, 'results.json'),
path_1.default.join(workingDir, 'report.json'),
];
for (const reportPath of reportPaths) {
if (await (0, fs_1.exists)(reportPath)) {
try {
const reportContent = await (0, fs_1.readFileBuffer)(reportPath);
const reportText = reportContent.toString();
// Parse JSON to extract shard information from config
try {
const reportJson = JSON.parse(reportText);
// Check for Playwright's config.shard structure (official format)
if (reportJson?.config?.shard &&
typeof reportJson.config.shard === 'object') {
const shard = reportJson.config.shard;
// Playwright uses "current" and "total" fields
if (typeof shard.current === 'number' &&
typeof shard.total === 'number') {
const shardIndex = shard.current;
const shardTotal = shard.total;
if (shardIndex > 0 &&
shardTotal > 0 &&
shardIndex <= shardTotal) {
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
}
}
catch {
// If JSON parsing fails, continue with regex-based detection
}
// Fallback: Look for shard indicators using regex patterns
const shardMatch = reportText.match(/"shard":\s*"(\d+)\/(\d+)"/);
if (shardMatch?.[1] && shardMatch[2]) {
const shardIndex = parseInt(shardMatch[1], 10);
const shardTotal = parseInt(shardMatch[2], 10);
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
// Look for Playwright CLI metadata
if (reportText.includes('--shard')) {
const cliMatch = reportText.match(/--shard[=\s]+(\d+)\/(\d+)/);
if (cliMatch?.[1] && cliMatch[2]) {
const shardIndex = parseInt(cliMatch[1], 10);
const shardTotal = parseInt(cliMatch[2], 10);
return {
shardIndex,
shardTotal,
shardId: `${shardIndex}/${shardTotal}`,
};
}
}
}
catch {
// Continue to next report on error
continue;
}
}
}
return null;
}
catch {
return null;
}
}
/**
* Validate shard information
*/
static validateShardInfo(shardInfo) {
return (shardInfo.shardIndex > 0 &&
shardInfo.shardTotal > 0 &&
shardInfo.shardIndex <= shardInfo.shardTotal &&
shardInfo.shardId === `${shardInfo.shardIndex}/${shardInfo.shardTotal}`);
}
/**
* Create default shard info (single shard)
*/
static createDefaultShardInfo() {
return {
shardIndex: 1,
shardTotal: 1,
shardId: '1/1',
};
}
}
exports.PlaywrightShardDetector = PlaywrightShardDetector;
//# sourceMappingURL=shard-detection.js.map