UNPKG

@arghajit/dummy

Version:

A Playwright reporter and dashboard for visualizing test results.

171 lines (142 loc) 6.63 kB
import * as fs from "fs"; import * as path from "path"; import { pathToFileURL } from "url"; import { dirname } from "path"; const DEFAULT_OUTPUT_DIR = "pulse-report"; async function findPlaywrightConfig() { const possibleConfigs = [ "playwright.config.ts", "playwright.config.js", "playwright.config.mjs", ]; for (const configFile of possibleConfigs) { const configPath = path.resolve(process.cwd(), configFile); if (fs.existsSync(configPath)) { return { path: configPath, exists: true }; } } return { path: null, exists: false }; } async function extractReporterOptionsFromConfig(configPath) { let fileContent = ""; try { fileContent = fs.readFileSync(configPath, "utf-8"); } catch (e) { return {}; } const options = {}; // 1. Strategy: Text Parsing (Safe & Fast) try { // Find the Pulse/Dummy reporter block // It usually looks like ["@arghajit/playwright-pulse-report", { ... }] or ["playwright-pulse-report", { ... }] const reporterBlockRegex = /\[\s*["'](?:@arghajit\/)?(?:playwright-pulse-report|dummy)["']\s*,\s*(\{[\s\S]*?\})\s*,?\s*\]/g; let match; while ((match = reporterBlockRegex.exec(fileContent)) !== null) { const block = match[1]; const outputDirMatch = block.match(/outputDir:\s*["']([^"']+)["']/); if (outputDirMatch && outputDirMatch[1]) options.outputDir = outputDirMatch[1]; const outputFileMatch = block.match(/outputFile:\s*["']([^"']+)["']/); if (outputFileMatch && outputFileMatch[1]) options.outputFile = outputFileMatch[1]; const resetOnEachRunMatch = block.match(/resetOnEachRun:\s*(true|false)/); if (resetOnEachRunMatch) options.resetOnEachRun = resetOnEachRunMatch[1] === "true"; const individualReportsSubDirMatch = block.match(/individualReportsSubDir:\s*["']([^"']+)["']/); if (individualReportsSubDirMatch && individualReportsSubDirMatch[1]) options.individualReportsSubDir = individualReportsSubDirMatch[1]; // If we found any Pulse-specific options, we're likely in the right block if (Object.keys(options).length > 0) break; } // Fallback for global outputDir if not found in reporter block if (!options.outputDir) { const globalOutputDirMatch = fileContent.match(/outputDir:\s*["']([^"']+)["']/); if (globalOutputDirMatch && globalOutputDirMatch[1]) options.outputDir = globalOutputDirMatch[1]; } } catch (e) { } // 2. Safety Check and Dynamic Import if (Object.keys(options).length < 3) { // Check if we can safely import() let canImport = true; if (configPath.endsWith(".js")) { let isModulePackage = false; try { const pkgPath = path.resolve(process.cwd(), "package.json"); if (fs.existsSync(pkgPath)) { const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")); isModulePackage = pkg.type === "module"; } } catch (e) {} if (!isModulePackage) { const hasEsmSyntax = /^\s*import\s+/m.test(fileContent) || /^\s*export\s+/m.test(fileContent); if (hasEsmSyntax) canImport = false; } } if (canImport) { try { let config; const configDir = dirname(configPath); const originalDirname = global.__dirname; const originalFilename = global.__filename; try { global.__dirname = configDir; global.__filename = configPath; if (configPath.endsWith(".ts")) { try { const { register } = await import("node:module"); const { pathToFileURL } = await import("node:url"); register("ts-node/esm", pathToFileURL("./")); config = await import(pathToFileURL(configPath).href); } catch (tsError) { const tsNode = await import("ts-node"); tsNode.register({ transpileOnly: true, compilerOptions: { module: "commonjs" } }); config = require(configPath); } } else { config = await import(pathToFileURL(configPath).href); } if (config && config.default) config = config.default; if (config) { if (config.reporter) { const reporters = Array.isArray(config.reporter) ? config.reporter : [config.reporter]; for (const reporter of reporters) { const reporterName = Array.isArray(reporter) ? reporter[0] : reporter; const reporterOptions = Array.isArray(reporter) ? reporter[1] : null; if (typeof reporterName === "string" && (reporterName.includes("playwright-pulse-report") || reporterName.includes("@arghajit/playwright-pulse-report") || reporterName.includes("@arghajit/dummy"))) { if (reporterOptions) { if (reporterOptions.outputDir) options.outputDir = reporterOptions.outputDir; if (reporterOptions.outputFile) options.outputFile = reporterOptions.outputFile; if (reporterOptions.resetOnEachRun !== undefined) options.resetOnEachRun = reporterOptions.resetOnEachRun; if (reporterOptions.individualReportsSubDir) options.individualReportsSubDir = reporterOptions.individualReportsSubDir; } } } } if (config.outputDir && !options.outputDir) options.outputDir = config.outputDir; } } finally { global.__dirname = originalDirname; global.__filename = originalFilename; } } catch (error) {} } } return options; } export async function getReporterConfig(customOutputDirFromArgs = null) { const { path: configPath, exists } = await findPlaywrightConfig(); let options = {}; if (exists) { options = await extractReporterOptionsFromConfig(configPath); } const outputDir = customOutputDirFromArgs ? path.resolve(process.cwd(), customOutputDirFromArgs) : path.resolve(process.cwd(), options.outputDir || DEFAULT_OUTPUT_DIR); const outputFile = options.outputFile || "playwright-pulse-report.json"; const resetOnEachRun = options.resetOnEachRun !== undefined ? options.resetOnEachRun : true; const individualReportsSubDir = options.individualReportsSubDir || "pulse-results"; return { outputDir, outputFile, resetOnEachRun, individualReportsSubDir }; } export async function getOutputDir(customOutputDirFromArgs = null) { const config = await getReporterConfig(customOutputDirFromArgs); return config.outputDir; }