First Commit
This commit is contained in:
611
node_modules/playwright/lib/reporters/base.js
generated
vendored
Normal file
611
node_modules/playwright/lib/reporters/base.js
generated
vendored
Normal file
@@ -0,0 +1,611 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var base_exports = {};
|
||||
__export(base_exports, {
|
||||
TerminalReporter: () => TerminalReporter,
|
||||
fitToWidth: () => fitToWidth,
|
||||
formatError: () => formatError,
|
||||
formatFailure: () => formatFailure,
|
||||
formatResultFailure: () => formatResultFailure,
|
||||
formatRetry: () => formatRetry,
|
||||
internalScreen: () => internalScreen,
|
||||
kOutputSymbol: () => kOutputSymbol,
|
||||
nonTerminalScreen: () => nonTerminalScreen,
|
||||
prepareErrorStack: () => prepareErrorStack,
|
||||
relativeFilePath: () => relativeFilePath,
|
||||
resolveOutputFile: () => resolveOutputFile,
|
||||
separator: () => separator,
|
||||
stepSuffix: () => stepSuffix,
|
||||
terminalScreen: () => terminalScreen
|
||||
});
|
||||
module.exports = __toCommonJS(base_exports);
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_util = require("../util");
|
||||
var import_utilsBundle2 = require("../utilsBundle");
|
||||
const kOutputSymbol = Symbol("output");
|
||||
const DEFAULT_TTY_WIDTH = 100;
|
||||
const DEFAULT_TTY_HEIGHT = 40;
|
||||
const originalProcessStdout = process.stdout;
|
||||
const originalProcessStderr = process.stderr;
|
||||
const terminalScreen = (() => {
|
||||
let isTTY = !!originalProcessStdout.isTTY;
|
||||
let ttyWidth = originalProcessStdout.columns || 0;
|
||||
let ttyHeight = originalProcessStdout.rows || 0;
|
||||
if (process.env.PLAYWRIGHT_FORCE_TTY === "false" || process.env.PLAYWRIGHT_FORCE_TTY === "0") {
|
||||
isTTY = false;
|
||||
ttyWidth = 0;
|
||||
ttyHeight = 0;
|
||||
} else if (process.env.PLAYWRIGHT_FORCE_TTY === "true" || process.env.PLAYWRIGHT_FORCE_TTY === "1") {
|
||||
isTTY = true;
|
||||
ttyWidth = originalProcessStdout.columns || DEFAULT_TTY_WIDTH;
|
||||
ttyHeight = originalProcessStdout.rows || DEFAULT_TTY_HEIGHT;
|
||||
} else if (process.env.PLAYWRIGHT_FORCE_TTY) {
|
||||
isTTY = true;
|
||||
const sizeMatch = process.env.PLAYWRIGHT_FORCE_TTY.match(/^(\d+)x(\d+)$/);
|
||||
if (sizeMatch) {
|
||||
ttyWidth = +sizeMatch[1];
|
||||
ttyHeight = +sizeMatch[2];
|
||||
} else {
|
||||
ttyWidth = +process.env.PLAYWRIGHT_FORCE_TTY;
|
||||
ttyHeight = DEFAULT_TTY_HEIGHT;
|
||||
}
|
||||
if (isNaN(ttyWidth))
|
||||
ttyWidth = DEFAULT_TTY_WIDTH;
|
||||
if (isNaN(ttyHeight))
|
||||
ttyHeight = DEFAULT_TTY_HEIGHT;
|
||||
}
|
||||
let useColors = isTTY;
|
||||
if (process.env.DEBUG_COLORS === "0" || process.env.DEBUG_COLORS === "false" || process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false")
|
||||
useColors = false;
|
||||
else if (process.env.DEBUG_COLORS || process.env.FORCE_COLOR)
|
||||
useColors = true;
|
||||
const colors = useColors ? import_utils2.colors : import_utils2.noColors;
|
||||
return {
|
||||
resolveFiles: "cwd",
|
||||
isTTY,
|
||||
ttyWidth,
|
||||
ttyHeight,
|
||||
colors,
|
||||
stdout: originalProcessStdout,
|
||||
stderr: originalProcessStderr
|
||||
};
|
||||
})();
|
||||
const nonTerminalScreen = {
|
||||
colors: terminalScreen.colors,
|
||||
isTTY: false,
|
||||
ttyWidth: 0,
|
||||
ttyHeight: 0,
|
||||
resolveFiles: "rootDir"
|
||||
};
|
||||
const internalScreen = {
|
||||
colors: import_utils2.colors,
|
||||
isTTY: false,
|
||||
ttyWidth: 0,
|
||||
ttyHeight: 0,
|
||||
resolveFiles: "rootDir"
|
||||
};
|
||||
class TerminalReporter {
|
||||
constructor(options = {}) {
|
||||
this.totalTestCount = 0;
|
||||
this.fileDurations = /* @__PURE__ */ new Map();
|
||||
this._fatalErrors = [];
|
||||
this._failureCount = 0;
|
||||
this.screen = options.screen ?? terminalScreen;
|
||||
this._omitFailures = options.omitFailures || false;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
this.config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this.suite = suite;
|
||||
this.totalTestCount = suite.allTests().length;
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
this._appendOutput({ chunk, type: "stdout" }, result);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
this._appendOutput({ chunk, type: "stderr" }, result);
|
||||
}
|
||||
_appendOutput(output, result) {
|
||||
if (!result)
|
||||
return;
|
||||
result[kOutputSymbol] = result[kOutputSymbol] || [];
|
||||
result[kOutputSymbol].push(output);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
if (result.status !== "skipped" && result.status !== test.expectedStatus)
|
||||
++this._failureCount;
|
||||
const projectName = test.titlePath()[1];
|
||||
const relativePath = relativeTestPath(this.screen, this.config, test);
|
||||
const fileAndProject = (projectName ? `[${projectName}] \u203A ` : "") + relativePath;
|
||||
const entry = this.fileDurations.get(fileAndProject) || { duration: 0, workers: /* @__PURE__ */ new Set() };
|
||||
entry.duration += result.duration;
|
||||
entry.workers.add(result.workerIndex);
|
||||
this.fileDurations.set(fileAndProject, entry);
|
||||
}
|
||||
onError(error) {
|
||||
this._fatalErrors.push(error);
|
||||
}
|
||||
async onEnd(result) {
|
||||
this.result = result;
|
||||
}
|
||||
fitToScreen(line, prefix) {
|
||||
if (!this.screen.ttyWidth) {
|
||||
return line;
|
||||
}
|
||||
return fitToWidth(line, this.screen.ttyWidth, prefix);
|
||||
}
|
||||
generateStartingMessage() {
|
||||
const jobs = this.config.metadata.actualWorkers ?? this.config.workers;
|
||||
const shardDetails = this.config.shard ? `, shard ${this.config.shard.current} of ${this.config.shard.total}` : "";
|
||||
if (!this.totalTestCount)
|
||||
return "";
|
||||
return "\n" + this.screen.colors.dim("Running ") + this.totalTestCount + this.screen.colors.dim(` test${this.totalTestCount !== 1 ? "s" : ""} using `) + jobs + this.screen.colors.dim(` worker${jobs !== 1 ? "s" : ""}${shardDetails}`);
|
||||
}
|
||||
getSlowTests() {
|
||||
if (!this.config.reportSlowTests)
|
||||
return [];
|
||||
const fileDurations = [...this.fileDurations.entries()].filter(([key, value]) => value.workers.size === 1).map(([key, value]) => [key, value.duration]);
|
||||
fileDurations.sort((a, b) => b[1] - a[1]);
|
||||
const count = Math.min(fileDurations.length, this.config.reportSlowTests.max || Number.POSITIVE_INFINITY);
|
||||
const threshold = this.config.reportSlowTests.threshold;
|
||||
return fileDurations.filter(([, duration]) => duration > threshold).slice(0, count);
|
||||
}
|
||||
generateSummaryMessage({ didNotRun, skipped, expected, interrupted, unexpected, flaky, fatalErrors }) {
|
||||
const tokens = [];
|
||||
if (unexpected.length) {
|
||||
tokens.push(this.screen.colors.red(` ${unexpected.length} failed`));
|
||||
for (const test of unexpected)
|
||||
tokens.push(this.screen.colors.red(this.formatTestHeader(test, { indent: " " })));
|
||||
}
|
||||
if (interrupted.length) {
|
||||
tokens.push(this.screen.colors.yellow(` ${interrupted.length} interrupted`));
|
||||
for (const test of interrupted)
|
||||
tokens.push(this.screen.colors.yellow(this.formatTestHeader(test, { indent: " " })));
|
||||
}
|
||||
if (flaky.length) {
|
||||
tokens.push(this.screen.colors.yellow(` ${flaky.length} flaky`));
|
||||
for (const test of flaky)
|
||||
tokens.push(this.screen.colors.yellow(this.formatTestHeader(test, { indent: " " })));
|
||||
}
|
||||
if (skipped)
|
||||
tokens.push(this.screen.colors.yellow(` ${skipped} skipped`));
|
||||
if (didNotRun)
|
||||
tokens.push(this.screen.colors.yellow(` ${didNotRun} did not run`));
|
||||
if (expected)
|
||||
tokens.push(this.screen.colors.green(` ${expected} passed`) + this.screen.colors.dim(` (${(0, import_utilsBundle.ms)(this.result.duration)})`));
|
||||
if (fatalErrors.length && expected + unexpected.length + interrupted.length + flaky.length > 0)
|
||||
tokens.push(this.screen.colors.red(` ${fatalErrors.length === 1 ? "1 error was not a part of any test" : fatalErrors.length + " errors were not a part of any test"}, see above for details`));
|
||||
return tokens.join("\n");
|
||||
}
|
||||
generateSummary() {
|
||||
let didNotRun = 0;
|
||||
let skipped = 0;
|
||||
let expected = 0;
|
||||
const interrupted = [];
|
||||
const interruptedToPrint = [];
|
||||
const unexpected = [];
|
||||
const flaky = [];
|
||||
this.suite.allTests().forEach((test) => {
|
||||
switch (test.outcome()) {
|
||||
case "skipped": {
|
||||
if (test.results.some((result) => result.status === "interrupted")) {
|
||||
if (test.results.some((result) => !!result.error))
|
||||
interruptedToPrint.push(test);
|
||||
interrupted.push(test);
|
||||
} else if (!test.results.length || test.expectedStatus !== "skipped") {
|
||||
++didNotRun;
|
||||
} else {
|
||||
++skipped;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "expected":
|
||||
++expected;
|
||||
break;
|
||||
case "unexpected":
|
||||
unexpected.push(test);
|
||||
break;
|
||||
case "flaky":
|
||||
flaky.push(test);
|
||||
break;
|
||||
}
|
||||
});
|
||||
const failuresToPrint = [...unexpected, ...flaky, ...interruptedToPrint];
|
||||
return {
|
||||
didNotRun,
|
||||
skipped,
|
||||
expected,
|
||||
interrupted,
|
||||
unexpected,
|
||||
flaky,
|
||||
failuresToPrint,
|
||||
fatalErrors: this._fatalErrors
|
||||
};
|
||||
}
|
||||
epilogue(full) {
|
||||
const summary = this.generateSummary();
|
||||
const summaryMessage = this.generateSummaryMessage(summary);
|
||||
if (full && summary.failuresToPrint.length && !this._omitFailures)
|
||||
this._printFailures(summary.failuresToPrint);
|
||||
this._printSlowTests();
|
||||
this._printSummary(summaryMessage);
|
||||
}
|
||||
_printFailures(failures) {
|
||||
this.writeLine("");
|
||||
failures.forEach((test, index) => {
|
||||
this.writeLine(this.formatFailure(test, index + 1));
|
||||
});
|
||||
}
|
||||
_printSlowTests() {
|
||||
const slowTests = this.getSlowTests();
|
||||
slowTests.forEach(([file, duration]) => {
|
||||
this.writeLine(this.screen.colors.yellow(" Slow test file: ") + file + this.screen.colors.yellow(` (${(0, import_utilsBundle.ms)(duration)})`));
|
||||
});
|
||||
if (slowTests.length)
|
||||
this.writeLine(this.screen.colors.yellow(" Consider running tests from slow files in parallel. See: https://playwright.dev/docs/test-parallel"));
|
||||
}
|
||||
_printSummary(summary) {
|
||||
if (summary.trim())
|
||||
this.writeLine(summary);
|
||||
}
|
||||
willRetry(test) {
|
||||
return test.outcome() === "unexpected" && test.results.length <= test.retries;
|
||||
}
|
||||
formatTestTitle(test, step, omitLocation = false) {
|
||||
return formatTestTitle(this.screen, this.config, test, step, omitLocation);
|
||||
}
|
||||
formatTestHeader(test, options = {}) {
|
||||
return formatTestHeader(this.screen, this.config, test, options);
|
||||
}
|
||||
formatFailure(test, index) {
|
||||
return formatFailure(this.screen, this.config, test, index);
|
||||
}
|
||||
formatError(error) {
|
||||
return formatError(this.screen, error);
|
||||
}
|
||||
writeLine(line) {
|
||||
this.screen.stdout?.write(line ? line + "\n" : "\n");
|
||||
}
|
||||
}
|
||||
function formatFailure(screen, config, test, index) {
|
||||
const lines = [];
|
||||
const header = formatTestHeader(screen, config, test, { indent: " ", index, mode: "error" });
|
||||
lines.push(screen.colors.red(header));
|
||||
for (const result of test.results) {
|
||||
const resultLines = [];
|
||||
const errors = formatResultFailure(screen, test, result, " ");
|
||||
if (!errors.length)
|
||||
continue;
|
||||
if (result.retry) {
|
||||
resultLines.push("");
|
||||
resultLines.push(screen.colors.gray(separator(screen, ` Retry #${result.retry}`)));
|
||||
}
|
||||
resultLines.push(...errors.map((error) => "\n" + error.message));
|
||||
const attachmentGroups = groupAttachments(result.attachments);
|
||||
for (let i = 0; i < attachmentGroups.length; ++i) {
|
||||
const attachment = attachmentGroups[i];
|
||||
if (attachment.name === "error-context" && attachment.path) {
|
||||
resultLines.push("");
|
||||
resultLines.push(screen.colors.dim(` Error Context: ${relativeFilePath(screen, config, attachment.path)}`));
|
||||
continue;
|
||||
}
|
||||
if (attachment.name.startsWith("_"))
|
||||
continue;
|
||||
const hasPrintableContent = attachment.contentType.startsWith("text/");
|
||||
if (!attachment.path && !hasPrintableContent)
|
||||
continue;
|
||||
resultLines.push("");
|
||||
resultLines.push(screen.colors.dim(separator(screen, ` attachment #${i + 1}: ${screen.colors.bold(attachment.name)} (${attachment.contentType})`)));
|
||||
if (attachment.actual?.path) {
|
||||
if (attachment.expected?.path) {
|
||||
const expectedPath = relativeFilePath(screen, config, attachment.expected.path);
|
||||
resultLines.push(screen.colors.dim(` Expected: ${expectedPath}`));
|
||||
}
|
||||
const actualPath = relativeFilePath(screen, config, attachment.actual.path);
|
||||
resultLines.push(screen.colors.dim(` Received: ${actualPath}`));
|
||||
if (attachment.previous?.path) {
|
||||
const previousPath = relativeFilePath(screen, config, attachment.previous.path);
|
||||
resultLines.push(screen.colors.dim(` Previous: ${previousPath}`));
|
||||
}
|
||||
if (attachment.diff?.path) {
|
||||
const diffPath = relativeFilePath(screen, config, attachment.diff.path);
|
||||
resultLines.push(screen.colors.dim(` Diff: ${diffPath}`));
|
||||
}
|
||||
} else if (attachment.path) {
|
||||
const relativePath = relativeFilePath(screen, config, attachment.path);
|
||||
resultLines.push(screen.colors.dim(` ${relativePath}`));
|
||||
if (attachment.name === "trace") {
|
||||
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
|
||||
resultLines.push(screen.colors.dim(` Usage:`));
|
||||
resultLines.push("");
|
||||
resultLines.push(screen.colors.dim(` ${packageManagerCommand} playwright show-trace ${quotePathIfNeeded(relativePath)}`));
|
||||
resultLines.push("");
|
||||
}
|
||||
} else {
|
||||
if (attachment.contentType.startsWith("text/") && attachment.body) {
|
||||
let text = attachment.body.toString();
|
||||
if (text.length > 300)
|
||||
text = text.slice(0, 300) + "...";
|
||||
for (const line of text.split("\n"))
|
||||
resultLines.push(screen.colors.dim(` ${line}`));
|
||||
}
|
||||
}
|
||||
resultLines.push(screen.colors.dim(separator(screen, " ")));
|
||||
}
|
||||
lines.push(...resultLines);
|
||||
}
|
||||
lines.push("");
|
||||
return lines.join("\n");
|
||||
}
|
||||
function formatRetry(screen, result) {
|
||||
const retryLines = [];
|
||||
if (result.retry) {
|
||||
retryLines.push("");
|
||||
retryLines.push(screen.colors.gray(separator(screen, ` Retry #${result.retry}`)));
|
||||
}
|
||||
return retryLines;
|
||||
}
|
||||
function quotePathIfNeeded(path2) {
|
||||
if (/\s/.test(path2))
|
||||
return `"${path2}"`;
|
||||
return path2;
|
||||
}
|
||||
function formatResultFailure(screen, test, result, initialIndent) {
|
||||
const errorDetails = [];
|
||||
if (result.status === "passed" && test.expectedStatus === "failed") {
|
||||
errorDetails.push({
|
||||
message: indent(screen.colors.red(`Expected to fail, but passed.`), initialIndent)
|
||||
});
|
||||
}
|
||||
if (result.status === "interrupted") {
|
||||
errorDetails.push({
|
||||
message: indent(screen.colors.red(`Test was interrupted.`), initialIndent)
|
||||
});
|
||||
}
|
||||
for (const error of result.errors) {
|
||||
const formattedError = formatError(screen, error);
|
||||
errorDetails.push({
|
||||
message: indent(formattedError.message, initialIndent),
|
||||
location: formattedError.location
|
||||
});
|
||||
}
|
||||
return errorDetails;
|
||||
}
|
||||
function relativeFilePath(screen, config, file) {
|
||||
if (screen.resolveFiles === "cwd")
|
||||
return import_path.default.relative(process.cwd(), file);
|
||||
return import_path.default.relative(config.rootDir, file);
|
||||
}
|
||||
function relativeTestPath(screen, config, test) {
|
||||
return relativeFilePath(screen, config, test.location.file);
|
||||
}
|
||||
function stepSuffix(step) {
|
||||
const stepTitles = step ? step.titlePath() : [];
|
||||
return stepTitles.map((t) => t.split("\n")[0]).map((t) => " \u203A " + t).join("");
|
||||
}
|
||||
function formatTestTitle(screen, config, test, step, omitLocation = false) {
|
||||
const [, projectName, , ...titles] = test.titlePath();
|
||||
let location;
|
||||
if (omitLocation)
|
||||
location = `${relativeTestPath(screen, config, test)}`;
|
||||
else
|
||||
location = `${relativeTestPath(screen, config, test)}:${test.location.line}:${test.location.column}`;
|
||||
const projectTitle = projectName ? `[${projectName}] \u203A ` : "";
|
||||
const testTitle = `${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`;
|
||||
const extraTags = test.tags.filter((t) => !testTitle.includes(t));
|
||||
return `${testTitle}${stepSuffix(step)}${extraTags.length ? " " + extraTags.join(" ") : ""}`;
|
||||
}
|
||||
function formatTestHeader(screen, config, test, options = {}) {
|
||||
const title = formatTestTitle(screen, config, test);
|
||||
const header = `${options.indent || ""}${options.index ? options.index + ") " : ""}${title}`;
|
||||
let fullHeader = header;
|
||||
if (options.mode === "error") {
|
||||
const stepPaths = /* @__PURE__ */ new Set();
|
||||
for (const result of test.results.filter((r) => !!r.errors.length)) {
|
||||
const stepPath = [];
|
||||
const visit = (steps) => {
|
||||
const errors = steps.filter((s) => s.error);
|
||||
if (errors.length > 1)
|
||||
return;
|
||||
if (errors.length === 1 && errors[0].category === "test.step") {
|
||||
stepPath.push(errors[0].title);
|
||||
visit(errors[0].steps);
|
||||
}
|
||||
};
|
||||
visit(result.steps);
|
||||
stepPaths.add(["", ...stepPath].join(" \u203A "));
|
||||
}
|
||||
fullHeader = header + (stepPaths.size === 1 ? stepPaths.values().next().value : "");
|
||||
}
|
||||
return separator(screen, fullHeader);
|
||||
}
|
||||
function formatError(screen, error) {
|
||||
const message = error.message || error.value || "";
|
||||
const stack = error.stack;
|
||||
if (!stack && !error.location)
|
||||
return { message };
|
||||
const tokens = [];
|
||||
const parsedStack = stack ? prepareErrorStack(stack) : void 0;
|
||||
tokens.push(parsedStack?.message || message);
|
||||
if (error.snippet) {
|
||||
let snippet = error.snippet;
|
||||
if (!screen.colors.enabled)
|
||||
snippet = (0, import_util.stripAnsiEscapes)(snippet);
|
||||
tokens.push("");
|
||||
tokens.push(snippet);
|
||||
}
|
||||
if (parsedStack && parsedStack.stackLines.length)
|
||||
tokens.push(screen.colors.dim(parsedStack.stackLines.join("\n")));
|
||||
let location = error.location;
|
||||
if (parsedStack && !location)
|
||||
location = parsedStack.location;
|
||||
if (error.cause)
|
||||
tokens.push(screen.colors.dim("[cause]: ") + formatError(screen, error.cause).message);
|
||||
return {
|
||||
location,
|
||||
message: tokens.join("\n")
|
||||
};
|
||||
}
|
||||
function separator(screen, text = "") {
|
||||
if (text)
|
||||
text += " ";
|
||||
const columns = Math.min(100, screen.ttyWidth || 100);
|
||||
return text + screen.colors.dim("\u2500".repeat(Math.max(0, columns - (0, import_util.stripAnsiEscapes)(text).length)));
|
||||
}
|
||||
function indent(lines, tab) {
|
||||
return lines.replace(/^(?=.+$)/gm, tab);
|
||||
}
|
||||
function prepareErrorStack(stack) {
|
||||
return (0, import_utils.parseErrorStack)(stack, import_path.default.sep, !!process.env.PWDEBUGIMPL);
|
||||
}
|
||||
function characterWidth(c) {
|
||||
return import_utilsBundle2.getEastAsianWidth.eastAsianWidth(c.codePointAt(0));
|
||||
}
|
||||
function stringWidth(v) {
|
||||
let width = 0;
|
||||
for (const { segment } of new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(v))
|
||||
width += characterWidth(segment);
|
||||
return width;
|
||||
}
|
||||
function suffixOfWidth(v, width) {
|
||||
const segments = [...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(v)];
|
||||
let suffixBegin = v.length;
|
||||
for (const { segment, index } of segments.reverse()) {
|
||||
const segmentWidth = stringWidth(segment);
|
||||
if (segmentWidth > width)
|
||||
break;
|
||||
width -= segmentWidth;
|
||||
suffixBegin = index;
|
||||
}
|
||||
return v.substring(suffixBegin);
|
||||
}
|
||||
function fitToWidth(line, width, prefix) {
|
||||
const prefixLength = prefix ? (0, import_util.stripAnsiEscapes)(prefix).length : 0;
|
||||
width -= prefixLength;
|
||||
if (stringWidth(line) <= width)
|
||||
return line;
|
||||
const parts = line.split(import_util.ansiRegex);
|
||||
const taken = [];
|
||||
for (let i = parts.length - 1; i >= 0; i--) {
|
||||
if (i % 2) {
|
||||
taken.push(parts[i]);
|
||||
} else {
|
||||
let part = suffixOfWidth(parts[i], width);
|
||||
const wasTruncated = part.length < parts[i].length;
|
||||
if (wasTruncated && parts[i].length > 0) {
|
||||
part = "\u2026" + suffixOfWidth(parts[i], width - 1);
|
||||
}
|
||||
taken.push(part);
|
||||
width -= stringWidth(part);
|
||||
}
|
||||
}
|
||||
return taken.reverse().join("");
|
||||
}
|
||||
function resolveFromEnv(name) {
|
||||
const value = process.env[name];
|
||||
if (value)
|
||||
return import_path.default.resolve(process.cwd(), value);
|
||||
return void 0;
|
||||
}
|
||||
function resolveOutputFile(reporterName, options) {
|
||||
const name = reporterName.toUpperCase();
|
||||
let outputFile = resolveFromEnv(`PLAYWRIGHT_${name}_OUTPUT_FILE`);
|
||||
if (!outputFile && options.outputFile)
|
||||
outputFile = import_path.default.resolve(options.configDir, options.outputFile);
|
||||
if (outputFile)
|
||||
return { outputFile };
|
||||
let outputDir = resolveFromEnv(`PLAYWRIGHT_${name}_OUTPUT_DIR`);
|
||||
if (!outputDir && options.outputDir)
|
||||
outputDir = import_path.default.resolve(options.configDir, options.outputDir);
|
||||
if (!outputDir && options.default)
|
||||
outputDir = (0, import_util.resolveReporterOutputPath)(options.default.outputDir, options.configDir, void 0);
|
||||
if (!outputDir)
|
||||
outputDir = options.configDir;
|
||||
const reportName = process.env[`PLAYWRIGHT_${name}_OUTPUT_NAME`] ?? options.fileName ?? options.default?.fileName;
|
||||
if (!reportName)
|
||||
return void 0;
|
||||
outputFile = import_path.default.resolve(outputDir, reportName);
|
||||
return { outputFile, outputDir };
|
||||
}
|
||||
function groupAttachments(attachments) {
|
||||
const result = [];
|
||||
const attachmentsByPrefix = /* @__PURE__ */ new Map();
|
||||
for (const attachment of attachments) {
|
||||
if (!attachment.path) {
|
||||
result.push(attachment);
|
||||
continue;
|
||||
}
|
||||
const match = attachment.name.match(/^(.*)-(expected|actual|diff|previous)(\.[^.]+)?$/);
|
||||
if (!match) {
|
||||
result.push(attachment);
|
||||
continue;
|
||||
}
|
||||
const [, name, category] = match;
|
||||
let group = attachmentsByPrefix.get(name);
|
||||
if (!group) {
|
||||
group = { ...attachment, name };
|
||||
attachmentsByPrefix.set(name, group);
|
||||
result.push(group);
|
||||
}
|
||||
if (category === "expected")
|
||||
group.expected = attachment;
|
||||
else if (category === "actual")
|
||||
group.actual = attachment;
|
||||
else if (category === "diff")
|
||||
group.diff = attachment;
|
||||
else if (category === "previous")
|
||||
group.previous = attachment;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TerminalReporter,
|
||||
fitToWidth,
|
||||
formatError,
|
||||
formatFailure,
|
||||
formatResultFailure,
|
||||
formatRetry,
|
||||
internalScreen,
|
||||
kOutputSymbol,
|
||||
nonTerminalScreen,
|
||||
prepareErrorStack,
|
||||
relativeFilePath,
|
||||
resolveOutputFile,
|
||||
separator,
|
||||
stepSuffix,
|
||||
terminalScreen
|
||||
});
|
Reference in New Issue
Block a user