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
|
||||
});
|
135
node_modules/playwright/lib/reporters/blob.js
generated
vendored
Normal file
135
node_modules/playwright/lib/reporters/blob.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
"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 blob_exports = {};
|
||||
__export(blob_exports, {
|
||||
BlobReporter: () => BlobReporter,
|
||||
currentBlobReportVersion: () => currentBlobReportVersion
|
||||
});
|
||||
module.exports = __toCommonJS(blob_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_stream = require("stream");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_zipBundle = require("playwright-core/lib/zipBundle");
|
||||
var import_base = require("./base");
|
||||
var import_teleEmitter = require("./teleEmitter");
|
||||
const currentBlobReportVersion = 2;
|
||||
class BlobReporter extends import_teleEmitter.TeleReporterEmitter {
|
||||
constructor(options) {
|
||||
super((message) => this._messages.push(message));
|
||||
this._messages = [];
|
||||
this._attachments = [];
|
||||
this._options = options;
|
||||
if (this._options.fileName && !this._options.fileName.endsWith(".zip"))
|
||||
throw new Error(`Blob report file name must end with .zip extension: ${this._options.fileName}`);
|
||||
this._salt = (0, import_utils2.createGuid)();
|
||||
}
|
||||
onConfigure(config) {
|
||||
const metadata = {
|
||||
version: currentBlobReportVersion,
|
||||
userAgent: (0, import_utils2.getUserAgent)(),
|
||||
name: process.env.PWTEST_BOT_NAME,
|
||||
shard: config.shard ?? void 0,
|
||||
pathSeparator: import_path.default.sep
|
||||
};
|
||||
this._messages.push({
|
||||
method: "onBlobReportMetadata",
|
||||
params: metadata
|
||||
});
|
||||
this._config = config;
|
||||
super.onConfigure(config);
|
||||
}
|
||||
async onEnd(result) {
|
||||
await super.onEnd(result);
|
||||
const zipFileName = await this._prepareOutputFile();
|
||||
const zipFile = new import_zipBundle.yazl.ZipFile();
|
||||
const zipFinishPromise = new import_utils2.ManualPromise();
|
||||
const finishPromise = zipFinishPromise.catch((e) => {
|
||||
throw new Error(`Failed to write report ${zipFileName}: ` + e.message);
|
||||
});
|
||||
zipFile.on("error", (error) => zipFinishPromise.reject(error));
|
||||
zipFile.outputStream.pipe(import_fs.default.createWriteStream(zipFileName)).on("close", () => {
|
||||
zipFinishPromise.resolve(void 0);
|
||||
}).on("error", (error) => zipFinishPromise.reject(error));
|
||||
for (const { originalPath, zipEntryPath } of this._attachments) {
|
||||
if (!import_fs.default.statSync(originalPath, { throwIfNoEntry: false })?.isFile())
|
||||
continue;
|
||||
zipFile.addFile(originalPath, zipEntryPath);
|
||||
}
|
||||
const lines = this._messages.map((m) => JSON.stringify(m) + "\n");
|
||||
const content = import_stream.Readable.from(lines);
|
||||
zipFile.addReadStream(content, "report.jsonl");
|
||||
zipFile.end();
|
||||
await finishPromise;
|
||||
}
|
||||
async _prepareOutputFile() {
|
||||
const { outputFile, outputDir } = (0, import_base.resolveOutputFile)("BLOB", {
|
||||
...this._options,
|
||||
default: {
|
||||
fileName: this._defaultReportName(this._config),
|
||||
outputDir: "blob-report"
|
||||
}
|
||||
});
|
||||
if (!process.env.PWTEST_BLOB_DO_NOT_REMOVE)
|
||||
await (0, import_utils.removeFolders)([outputDir]);
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(outputFile), { recursive: true });
|
||||
return outputFile;
|
||||
}
|
||||
_defaultReportName(config) {
|
||||
let reportName = "report";
|
||||
if (this._options._commandHash)
|
||||
reportName += "-" + (0, import_utils.sanitizeForFilePath)(this._options._commandHash);
|
||||
if (config.shard) {
|
||||
const paddedNumber = `${config.shard.current}`.padStart(`${config.shard.total}`.length, "0");
|
||||
reportName = `${reportName}-${paddedNumber}`;
|
||||
}
|
||||
return `${reportName}.zip`;
|
||||
}
|
||||
_serializeAttachments(attachments) {
|
||||
return super._serializeAttachments(attachments).map((attachment) => {
|
||||
if (!attachment.path)
|
||||
return attachment;
|
||||
const sha1 = (0, import_utils2.calculateSha1)(attachment.path + this._salt);
|
||||
const extension = import_utilsBundle.mime.getExtension(attachment.contentType) || "dat";
|
||||
const newPath = `resources/${sha1}.${extension}`;
|
||||
this._attachments.push({ originalPath: attachment.path, zipEntryPath: newPath });
|
||||
return {
|
||||
...attachment,
|
||||
path: newPath
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
BlobReporter,
|
||||
currentBlobReportVersion
|
||||
});
|
82
node_modules/playwright/lib/reporters/dot.js
generated
vendored
Normal file
82
node_modules/playwright/lib/reporters/dot.js
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var dot_exports = {};
|
||||
__export(dot_exports, {
|
||||
default: () => dot_default
|
||||
});
|
||||
module.exports = __toCommonJS(dot_exports);
|
||||
var import_base = require("./base");
|
||||
class DotReporter extends import_base.TerminalReporter {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this._counter = 0;
|
||||
}
|
||||
onBegin(suite) {
|
||||
super.onBegin(suite);
|
||||
this.writeLine(this.generateStartingMessage());
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
super.onStdOut(chunk, test, result);
|
||||
if (!this.config.quiet)
|
||||
this.screen.stdout.write(chunk);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
super.onStdErr(chunk, test, result);
|
||||
if (!this.config.quiet)
|
||||
this.screen.stderr.write(chunk);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
super.onTestEnd(test, result);
|
||||
if (this._counter === 80) {
|
||||
this.screen.stdout.write("\n");
|
||||
this._counter = 0;
|
||||
}
|
||||
++this._counter;
|
||||
if (result.status === "skipped") {
|
||||
this.screen.stdout.write(this.screen.colors.yellow("\xB0"));
|
||||
return;
|
||||
}
|
||||
if (this.willRetry(test)) {
|
||||
this.screen.stdout.write(this.screen.colors.gray("\xD7"));
|
||||
return;
|
||||
}
|
||||
switch (test.outcome()) {
|
||||
case "expected":
|
||||
this.screen.stdout.write(this.screen.colors.green("\xB7"));
|
||||
break;
|
||||
case "unexpected":
|
||||
this.screen.stdout.write(this.screen.colors.red(result.status === "timedOut" ? "T" : "F"));
|
||||
break;
|
||||
case "flaky":
|
||||
this.screen.stdout.write(this.screen.colors.yellow("\xB1"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
onError(error) {
|
||||
super.onError(error);
|
||||
this.writeLine("\n" + this.formatError(error).message);
|
||||
this._counter = 0;
|
||||
}
|
||||
async onEnd(result) {
|
||||
await super.onEnd(result);
|
||||
this.screen.stdout.write("\n");
|
||||
this.epilogue(true);
|
||||
}
|
||||
}
|
||||
var dot_default = DotReporter;
|
32
node_modules/playwright/lib/reporters/empty.js
generated
vendored
Normal file
32
node_modules/playwright/lib/reporters/empty.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var empty_exports = {};
|
||||
__export(empty_exports, {
|
||||
default: () => empty_default
|
||||
});
|
||||
module.exports = __toCommonJS(empty_exports);
|
||||
class EmptyReporter {
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var empty_default = EmptyReporter;
|
128
node_modules/playwright/lib/reporters/github.js
generated
vendored
Normal file
128
node_modules/playwright/lib/reporters/github.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
"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 github_exports = {};
|
||||
__export(github_exports, {
|
||||
GitHubReporter: () => GitHubReporter,
|
||||
default: () => github_default
|
||||
});
|
||||
module.exports = __toCommonJS(github_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_base = require("./base");
|
||||
var import_util = require("../util");
|
||||
class GitHubLogger {
|
||||
_log(message, type = "notice", options = {}) {
|
||||
message = message.replace(/\n/g, "%0A");
|
||||
const configs = Object.entries(options).map(([key, option]) => `${key}=${option}`).join(",");
|
||||
process.stdout.write((0, import_util.stripAnsiEscapes)(`::${type} ${configs}::${message}
|
||||
`));
|
||||
}
|
||||
debug(message, options) {
|
||||
this._log(message, "debug", options);
|
||||
}
|
||||
error(message, options) {
|
||||
this._log(message, "error", options);
|
||||
}
|
||||
notice(message, options) {
|
||||
this._log(message, "notice", options);
|
||||
}
|
||||
warning(message, options) {
|
||||
this._log(message, "warning", options);
|
||||
}
|
||||
}
|
||||
class GitHubReporter extends import_base.TerminalReporter {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.githubLogger = new GitHubLogger();
|
||||
this.screen = { ...this.screen, colors: import_utils.noColors };
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
async onEnd(result) {
|
||||
await super.onEnd(result);
|
||||
this._printAnnotations();
|
||||
}
|
||||
onError(error) {
|
||||
const errorMessage = this.formatError(error).message;
|
||||
this.githubLogger.error(errorMessage);
|
||||
}
|
||||
_printAnnotations() {
|
||||
const summary = this.generateSummary();
|
||||
const summaryMessage = this.generateSummaryMessage(summary);
|
||||
if (summary.failuresToPrint.length)
|
||||
this._printFailureAnnotations(summary.failuresToPrint);
|
||||
this._printSlowTestAnnotations();
|
||||
this._printSummaryAnnotation(summaryMessage);
|
||||
}
|
||||
_printSlowTestAnnotations() {
|
||||
this.getSlowTests().forEach(([file, duration]) => {
|
||||
const filePath = workspaceRelativePath(import_path.default.join(process.cwd(), file));
|
||||
this.githubLogger.warning(`${filePath} took ${(0, import_utilsBundle.ms)(duration)}`, {
|
||||
title: "Slow Test",
|
||||
file: filePath
|
||||
});
|
||||
});
|
||||
}
|
||||
_printSummaryAnnotation(summary) {
|
||||
this.githubLogger.notice(summary, {
|
||||
title: "\u{1F3AD} Playwright Run Summary"
|
||||
});
|
||||
}
|
||||
_printFailureAnnotations(failures) {
|
||||
failures.forEach((test, index) => {
|
||||
const title = this.formatTestTitle(test);
|
||||
const header = this.formatTestHeader(test, { indent: " ", index: index + 1, mode: "error" });
|
||||
for (const result of test.results) {
|
||||
const errors = (0, import_base.formatResultFailure)(this.screen, test, result, " ");
|
||||
for (const error of errors) {
|
||||
const options = {
|
||||
file: workspaceRelativePath(error.location?.file || test.location.file),
|
||||
title
|
||||
};
|
||||
if (error.location) {
|
||||
options.line = error.location.line;
|
||||
options.col = error.location.column;
|
||||
}
|
||||
const message = [header, ...(0, import_base.formatRetry)(this.screen, result), error.message].join("\n");
|
||||
this.githubLogger.error(message, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function workspaceRelativePath(filePath) {
|
||||
return import_path.default.relative(process.env["GITHUB_WORKSPACE"] ?? "", filePath);
|
||||
}
|
||||
var github_default = GitHubReporter;
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
GitHubReporter
|
||||
});
|
631
node_modules/playwright/lib/reporters/html.js
generated
vendored
Normal file
631
node_modules/playwright/lib/reporters/html.js
generated
vendored
Normal file
@@ -0,0 +1,631 @@
|
||||
"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 html_exports = {};
|
||||
__export(html_exports, {
|
||||
default: () => html_default,
|
||||
showHTMLReport: () => showHTMLReport,
|
||||
startHtmlReportServer: () => startHtmlReportServer
|
||||
});
|
||||
module.exports = __toCommonJS(html_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_stream = require("stream");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_utilsBundle2 = require("playwright-core/lib/utilsBundle");
|
||||
var import_zipBundle = require("playwright-core/lib/zipBundle");
|
||||
var import_base = require("./base");
|
||||
var import_babelBundle = require("../transform/babelBundle");
|
||||
var import_util = require("../util");
|
||||
const htmlReportOptions = ["always", "never", "on-failure"];
|
||||
const isHtmlReportOption = (type) => {
|
||||
return htmlReportOptions.includes(type);
|
||||
};
|
||||
class HtmlReporter {
|
||||
constructor(options) {
|
||||
this._topLevelErrors = [];
|
||||
this._options = options;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
onConfigure(config) {
|
||||
this.config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
const { outputFolder, open: open2, attachmentsBaseURL, host, port } = this._resolveOptions();
|
||||
this._outputFolder = outputFolder;
|
||||
this._open = open2;
|
||||
this._host = host;
|
||||
this._port = port;
|
||||
this._attachmentsBaseURL = attachmentsBaseURL;
|
||||
const reportedWarnings = /* @__PURE__ */ new Set();
|
||||
for (const project of this.config.projects) {
|
||||
if (this._isSubdirectory(outputFolder, project.outputDir) || this._isSubdirectory(project.outputDir, outputFolder)) {
|
||||
const key = outputFolder + "|" + project.outputDir;
|
||||
if (reportedWarnings.has(key))
|
||||
continue;
|
||||
reportedWarnings.add(key);
|
||||
writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
|
||||
writeLine(`
|
||||
html reporter folder: ${import_utils2.colors.bold(outputFolder)}
|
||||
test results folder: ${import_utils2.colors.bold(project.outputDir)}`);
|
||||
writeLine("");
|
||||
writeLine(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
|
||||
`);
|
||||
}
|
||||
}
|
||||
this.suite = suite;
|
||||
}
|
||||
_resolveOptions() {
|
||||
const outputFolder = reportFolderFromEnv() ?? (0, import_util.resolveReporterOutputPath)("playwright-report", this._options.configDir, this._options.outputFolder);
|
||||
return {
|
||||
outputFolder,
|
||||
open: getHtmlReportOptionProcessEnv() || this._options.open || "on-failure",
|
||||
attachmentsBaseURL: process.env.PLAYWRIGHT_HTML_ATTACHMENTS_BASE_URL || this._options.attachmentsBaseURL || "data/",
|
||||
host: process.env.PLAYWRIGHT_HTML_HOST || this._options.host,
|
||||
port: process.env.PLAYWRIGHT_HTML_PORT ? +process.env.PLAYWRIGHT_HTML_PORT : this._options.port
|
||||
};
|
||||
}
|
||||
_isSubdirectory(parentDir, dir) {
|
||||
const relativePath = import_path.default.relative(parentDir, dir);
|
||||
return !!relativePath && !relativePath.startsWith("..") && !import_path.default.isAbsolute(relativePath);
|
||||
}
|
||||
onError(error) {
|
||||
this._topLevelErrors.push(error);
|
||||
}
|
||||
async onEnd(result) {
|
||||
const projectSuites = this.suite.suites;
|
||||
await (0, import_utils.removeFolders)([this._outputFolder]);
|
||||
let noSnippets;
|
||||
if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === "false" || process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === "0")
|
||||
noSnippets = false;
|
||||
else if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS)
|
||||
noSnippets = true;
|
||||
noSnippets = noSnippets || this._options.noSnippets;
|
||||
const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL, process.env.PLAYWRIGHT_HTML_TITLE || this._options.title, noSnippets);
|
||||
this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);
|
||||
}
|
||||
async onExit() {
|
||||
if (process.env.CI || !this._buildResult)
|
||||
return;
|
||||
const { ok, singleTestId } = this._buildResult;
|
||||
const shouldOpen = !this._options._isTestServer && (this._open === "always" || !ok && this._open === "on-failure");
|
||||
if (shouldOpen) {
|
||||
await showHTMLReport(this._outputFolder, this._host, this._port, singleTestId);
|
||||
} else if (this._options._mode === "test" && !this._options._isTestServer) {
|
||||
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
|
||||
const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? "" : " " + import_path.default.relative(process.cwd(), this._outputFolder);
|
||||
const hostArg = this._host ? ` --host ${this._host}` : "";
|
||||
const portArg = this._port ? ` --port ${this._port}` : "";
|
||||
writeLine("");
|
||||
writeLine("To open last HTML report run:");
|
||||
writeLine(import_utils2.colors.cyan(`
|
||||
${packageManagerCommand} playwright show-report${relativeReportPath}${hostArg}${portArg}
|
||||
`));
|
||||
}
|
||||
}
|
||||
}
|
||||
function reportFolderFromEnv() {
|
||||
const envValue = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT;
|
||||
return envValue ? import_path.default.resolve(envValue) : void 0;
|
||||
}
|
||||
function getHtmlReportOptionProcessEnv() {
|
||||
const htmlOpenEnv = process.env.PLAYWRIGHT_HTML_OPEN || process.env.PW_TEST_HTML_REPORT_OPEN;
|
||||
if (!htmlOpenEnv)
|
||||
return void 0;
|
||||
if (!isHtmlReportOption(htmlOpenEnv)) {
|
||||
writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(", ")}`));
|
||||
return void 0;
|
||||
}
|
||||
return htmlOpenEnv;
|
||||
}
|
||||
function standaloneDefaultFolder() {
|
||||
return reportFolderFromEnv() ?? (0, import_util.resolveReporterOutputPath)("playwright-report", process.cwd(), void 0);
|
||||
}
|
||||
async function showHTMLReport(reportFolder, host = "localhost", port, testId) {
|
||||
const folder = reportFolder ?? standaloneDefaultFolder();
|
||||
try {
|
||||
(0, import_utils.assert)(import_fs.default.statSync(folder).isDirectory());
|
||||
} catch (e) {
|
||||
writeLine(import_utils2.colors.red(`No report found at "${folder}"`));
|
||||
(0, import_utils.gracefullyProcessExitDoNotHang)(1);
|
||||
return;
|
||||
}
|
||||
const server = startHtmlReportServer(folder);
|
||||
await server.start({ port, host, preferredPort: port ? void 0 : 9323 });
|
||||
let url = server.urlPrefix("human-readable");
|
||||
writeLine("");
|
||||
writeLine(import_utils2.colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));
|
||||
if (testId)
|
||||
url += `#?testId=${testId}`;
|
||||
url = url.replace("0.0.0.0", "localhost");
|
||||
await (0, import_utilsBundle.open)(url, { wait: true }).catch(() => {
|
||||
});
|
||||
await new Promise(() => {
|
||||
});
|
||||
}
|
||||
function startHtmlReportServer(folder) {
|
||||
const server = new import_utils.HttpServer();
|
||||
server.routePrefix("/", (request, response) => {
|
||||
let relativePath = new URL("http://localhost" + request.url).pathname;
|
||||
if (relativePath.startsWith("/trace/file")) {
|
||||
const url = new URL("http://localhost" + request.url);
|
||||
try {
|
||||
return server.serveFile(request, response, url.searchParams.get("path"));
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (relativePath.endsWith("/stall.js"))
|
||||
return true;
|
||||
if (relativePath === "/")
|
||||
relativePath = "/index.html";
|
||||
const absolutePath = import_path.default.join(folder, ...relativePath.split("/"));
|
||||
return server.serveFile(request, response, absolutePath);
|
||||
});
|
||||
return server;
|
||||
}
|
||||
class HtmlBuilder {
|
||||
constructor(config, outputDir, attachmentsBaseURL, title, noSnippets = false) {
|
||||
this._stepsInFile = new import_utils.MultiMap();
|
||||
this._hasTraces = false;
|
||||
this._config = config;
|
||||
this._reportFolder = outputDir;
|
||||
this._noSnippets = noSnippets;
|
||||
import_fs.default.mkdirSync(this._reportFolder, { recursive: true });
|
||||
this._dataZipFile = new import_zipBundle.yazl.ZipFile();
|
||||
this._attachmentsBaseURL = attachmentsBaseURL;
|
||||
this._title = title;
|
||||
}
|
||||
async build(metadata, projectSuites, result, topLevelErrors) {
|
||||
const data = /* @__PURE__ */ new Map();
|
||||
for (const projectSuite of projectSuites) {
|
||||
for (const fileSuite of projectSuite.suites) {
|
||||
const fileName = this._relativeLocation(fileSuite.location).file;
|
||||
const fileId = (0, import_utils.calculateSha1)((0, import_utils.toPosixPath)(fileName)).slice(0, 20);
|
||||
let fileEntry = data.get(fileId);
|
||||
if (!fileEntry) {
|
||||
fileEntry = {
|
||||
testFile: { fileId, fileName, tests: [] },
|
||||
testFileSummary: { fileId, fileName, tests: [], stats: emptyStats() }
|
||||
};
|
||||
data.set(fileId, fileEntry);
|
||||
}
|
||||
const { testFile, testFileSummary } = fileEntry;
|
||||
const testEntries = [];
|
||||
this._processSuite(fileSuite, projectSuite.project().name, [], testEntries);
|
||||
for (const test of testEntries) {
|
||||
testFile.tests.push(test.testCase);
|
||||
testFileSummary.tests.push(test.testCaseSummary);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this._noSnippets)
|
||||
createSnippets(this._stepsInFile);
|
||||
let ok = true;
|
||||
for (const [fileId, { testFile, testFileSummary }] of data) {
|
||||
const stats = testFileSummary.stats;
|
||||
for (const test of testFileSummary.tests) {
|
||||
if (test.outcome === "expected")
|
||||
++stats.expected;
|
||||
if (test.outcome === "skipped")
|
||||
++stats.skipped;
|
||||
if (test.outcome === "unexpected")
|
||||
++stats.unexpected;
|
||||
if (test.outcome === "flaky")
|
||||
++stats.flaky;
|
||||
++stats.total;
|
||||
}
|
||||
stats.ok = stats.unexpected + stats.flaky === 0;
|
||||
if (!stats.ok)
|
||||
ok = false;
|
||||
const testCaseSummaryComparator = (t1, t2) => {
|
||||
const w1 = (t1.outcome === "unexpected" ? 1e3 : 0) + (t1.outcome === "flaky" ? 1 : 0);
|
||||
const w2 = (t2.outcome === "unexpected" ? 1e3 : 0) + (t2.outcome === "flaky" ? 1 : 0);
|
||||
return w2 - w1;
|
||||
};
|
||||
testFileSummary.tests.sort(testCaseSummaryComparator);
|
||||
this._addDataFile(fileId + ".json", testFile);
|
||||
}
|
||||
const htmlReport = {
|
||||
metadata,
|
||||
title: this._title,
|
||||
startTime: result.startTime.getTime(),
|
||||
duration: result.duration,
|
||||
files: [...data.values()].map((e) => e.testFileSummary),
|
||||
projectNames: projectSuites.map((r) => r.project().name),
|
||||
stats: { ...[...data.values()].reduce((a, e) => addStats(a, e.testFileSummary.stats), emptyStats()) },
|
||||
errors: topLevelErrors.map((error) => (0, import_base.formatError)(import_base.internalScreen, error).message)
|
||||
};
|
||||
htmlReport.files.sort((f1, f2) => {
|
||||
const w1 = f1.stats.unexpected * 1e3 + f1.stats.flaky;
|
||||
const w2 = f2.stats.unexpected * 1e3 + f2.stats.flaky;
|
||||
return w2 - w1;
|
||||
});
|
||||
this._addDataFile("report.json", htmlReport);
|
||||
let singleTestId;
|
||||
if (htmlReport.stats.total === 1) {
|
||||
const testFile = data.values().next().value.testFile;
|
||||
singleTestId = testFile.tests[0].testId;
|
||||
}
|
||||
if (process.env.PW_HMR === "1") {
|
||||
const redirectFile = import_path.default.join(this._reportFolder, "index.html");
|
||||
await this._writeReportData(redirectFile);
|
||||
async function redirect() {
|
||||
const hmrURL = new URL("http://localhost:44224");
|
||||
const popup = window.open(hmrURL);
|
||||
const listener = (evt) => {
|
||||
if (evt.source === popup && evt.data === "ready") {
|
||||
const element = document.getElementById("playwrightReportBase64");
|
||||
popup.postMessage(element?.textContent ?? "", hmrURL.origin);
|
||||
window.removeEventListener("message", listener);
|
||||
window.close();
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
}
|
||||
import_fs.default.appendFileSync(redirectFile, `<script>(${redirect.toString()})()</script>`);
|
||||
return { ok, singleTestId };
|
||||
}
|
||||
const appFolder = import_path.default.join(require.resolve("playwright-core"), "..", "lib", "vite", "htmlReport");
|
||||
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(appFolder, "index.html"), import_path.default.join(this._reportFolder, "index.html"));
|
||||
if (this._hasTraces) {
|
||||
const traceViewerFolder = import_path.default.join(require.resolve("playwright-core"), "..", "lib", "vite", "traceViewer");
|
||||
const traceViewerTargetFolder = import_path.default.join(this._reportFolder, "trace");
|
||||
const traceViewerAssetsTargetFolder = import_path.default.join(traceViewerTargetFolder, "assets");
|
||||
import_fs.default.mkdirSync(traceViewerAssetsTargetFolder, { recursive: true });
|
||||
for (const file of import_fs.default.readdirSync(traceViewerFolder)) {
|
||||
if (file.endsWith(".map") || file.includes("watch") || file.includes("assets"))
|
||||
continue;
|
||||
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(traceViewerFolder, file), import_path.default.join(traceViewerTargetFolder, file));
|
||||
}
|
||||
for (const file of import_fs.default.readdirSync(import_path.default.join(traceViewerFolder, "assets"))) {
|
||||
if (file.endsWith(".map") || file.includes("xtermModule"))
|
||||
continue;
|
||||
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(traceViewerFolder, "assets", file), import_path.default.join(traceViewerAssetsTargetFolder, file));
|
||||
}
|
||||
}
|
||||
await this._writeReportData(import_path.default.join(this._reportFolder, "index.html"));
|
||||
return { ok, singleTestId };
|
||||
}
|
||||
async _writeReportData(filePath) {
|
||||
import_fs.default.appendFileSync(filePath, '<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,');
|
||||
await new Promise((f) => {
|
||||
this._dataZipFile.end(void 0, () => {
|
||||
this._dataZipFile.outputStream.pipe(new Base64Encoder()).pipe(import_fs.default.createWriteStream(filePath, { flags: "a" })).on("close", f);
|
||||
});
|
||||
});
|
||||
import_fs.default.appendFileSync(filePath, "</script>");
|
||||
}
|
||||
_addDataFile(fileName, data) {
|
||||
this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);
|
||||
}
|
||||
_processSuite(suite, projectName, path2, outTests) {
|
||||
const newPath = [...path2, suite.title];
|
||||
suite.entries().forEach((e) => {
|
||||
if (e.type === "test")
|
||||
outTests.push(this._createTestEntry(e, projectName, newPath));
|
||||
else
|
||||
this._processSuite(e, projectName, newPath, outTests);
|
||||
});
|
||||
}
|
||||
_createTestEntry(test, projectName, path2) {
|
||||
const duration = test.results.reduce((a, r) => a + r.duration, 0);
|
||||
const location = this._relativeLocation(test.location);
|
||||
path2 = path2.slice(1).filter((path3) => path3.length > 0);
|
||||
const results = test.results.map((r) => this._createTestResult(test, r));
|
||||
return {
|
||||
testCase: {
|
||||
testId: test.id,
|
||||
title: test.title,
|
||||
projectName,
|
||||
location,
|
||||
duration,
|
||||
annotations: this._serializeAnnotations(test.annotations),
|
||||
tags: test.tags,
|
||||
outcome: test.outcome(),
|
||||
path: path2,
|
||||
results,
|
||||
ok: test.outcome() === "expected" || test.outcome() === "flaky"
|
||||
},
|
||||
testCaseSummary: {
|
||||
testId: test.id,
|
||||
title: test.title,
|
||||
projectName,
|
||||
location,
|
||||
duration,
|
||||
annotations: this._serializeAnnotations(test.annotations),
|
||||
tags: test.tags,
|
||||
outcome: test.outcome(),
|
||||
path: path2,
|
||||
ok: test.outcome() === "expected" || test.outcome() === "flaky",
|
||||
results: results.map((result) => {
|
||||
return { attachments: result.attachments.map((a) => ({ name: a.name, contentType: a.contentType, path: a.path })) };
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
_serializeAttachments(attachments) {
|
||||
let lastAttachment;
|
||||
return attachments.map((a) => {
|
||||
if (a.name === "trace")
|
||||
this._hasTraces = true;
|
||||
if ((a.name === "stdout" || a.name === "stderr") && a.contentType === "text/plain") {
|
||||
if (lastAttachment && lastAttachment.name === a.name && lastAttachment.contentType === a.contentType) {
|
||||
lastAttachment.body += (0, import_util.stripAnsiEscapes)(a.body);
|
||||
return null;
|
||||
}
|
||||
a.body = (0, import_util.stripAnsiEscapes)(a.body);
|
||||
lastAttachment = a;
|
||||
return a;
|
||||
}
|
||||
if (a.path) {
|
||||
let fileName = a.path;
|
||||
try {
|
||||
const buffer = import_fs.default.readFileSync(a.path);
|
||||
const sha1 = (0, import_utils.calculateSha1)(buffer) + import_path.default.extname(a.path);
|
||||
fileName = this._attachmentsBaseURL + sha1;
|
||||
import_fs.default.mkdirSync(import_path.default.join(this._reportFolder, "data"), { recursive: true });
|
||||
import_fs.default.writeFileSync(import_path.default.join(this._reportFolder, "data", sha1), buffer);
|
||||
} catch (e) {
|
||||
}
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
path: fileName,
|
||||
body: a.body
|
||||
};
|
||||
}
|
||||
if (a.body instanceof Buffer) {
|
||||
if (isTextContentType(a.contentType)) {
|
||||
const charset = a.contentType.match(/charset=(.*)/)?.[1];
|
||||
try {
|
||||
const body = a.body.toString(charset || "utf-8");
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
body
|
||||
};
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
import_fs.default.mkdirSync(import_path.default.join(this._reportFolder, "data"), { recursive: true });
|
||||
const extension = (0, import_utils.sanitizeForFilePath)(import_path.default.extname(a.name).replace(/^\./, "")) || import_utilsBundle2.mime.getExtension(a.contentType) || "dat";
|
||||
const sha1 = (0, import_utils.calculateSha1)(a.body) + "." + extension;
|
||||
import_fs.default.writeFileSync(import_path.default.join(this._reportFolder, "data", sha1), a.body);
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
path: this._attachmentsBaseURL + sha1
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
body: a.body
|
||||
};
|
||||
}).filter(Boolean);
|
||||
}
|
||||
_serializeAnnotations(annotations) {
|
||||
return annotations.map((a) => ({
|
||||
type: a.type,
|
||||
description: a.description === void 0 ? void 0 : String(a.description),
|
||||
location: a.location ? {
|
||||
file: a.location.file,
|
||||
line: a.location.line,
|
||||
column: a.location.column
|
||||
} : void 0
|
||||
}));
|
||||
}
|
||||
_createTestResult(test, result) {
|
||||
return {
|
||||
duration: result.duration,
|
||||
startTime: result.startTime.toISOString(),
|
||||
retry: result.retry,
|
||||
steps: dedupeSteps(result.steps).map((s) => this._createTestStep(s, result)),
|
||||
errors: (0, import_base.formatResultFailure)(import_base.internalScreen, test, result, "").map((error) => {
|
||||
return {
|
||||
message: error.message,
|
||||
codeframe: error.location ? createErrorCodeframe(error.message, error.location) : void 0
|
||||
};
|
||||
}),
|
||||
status: result.status,
|
||||
annotations: this._serializeAnnotations(result.annotations),
|
||||
attachments: this._serializeAttachments([
|
||||
...result.attachments,
|
||||
...result.stdout.map((m) => stdioAttachment(m, "stdout")),
|
||||
...result.stderr.map((m) => stdioAttachment(m, "stderr"))
|
||||
])
|
||||
};
|
||||
}
|
||||
_createTestStep(dedupedStep, result) {
|
||||
const { step, duration, count } = dedupedStep;
|
||||
const skipped = dedupedStep.step.annotations?.find((a) => a.type === "skip");
|
||||
let title = step.title;
|
||||
if (skipped)
|
||||
title = `${title} (skipped${skipped.description ? ": " + skipped.description : ""})`;
|
||||
const testStep = {
|
||||
title,
|
||||
startTime: step.startTime.toISOString(),
|
||||
duration,
|
||||
steps: dedupeSteps(step.steps).map((s) => this._createTestStep(s, result)),
|
||||
attachments: step.attachments.map((s) => {
|
||||
const index = result.attachments.indexOf(s);
|
||||
if (index === -1)
|
||||
throw new Error("Unexpected, attachment not found");
|
||||
return index;
|
||||
}),
|
||||
location: this._relativeLocation(step.location),
|
||||
error: step.error?.message,
|
||||
count,
|
||||
skipped: !!skipped
|
||||
};
|
||||
if (step.location)
|
||||
this._stepsInFile.set(step.location.file, testStep);
|
||||
return testStep;
|
||||
}
|
||||
_relativeLocation(location) {
|
||||
if (!location)
|
||||
return void 0;
|
||||
const file = (0, import_utils.toPosixPath)(import_path.default.relative(this._config.rootDir, location.file));
|
||||
return {
|
||||
file,
|
||||
line: location.line,
|
||||
column: location.column
|
||||
};
|
||||
}
|
||||
}
|
||||
const emptyStats = () => {
|
||||
return {
|
||||
total: 0,
|
||||
expected: 0,
|
||||
unexpected: 0,
|
||||
flaky: 0,
|
||||
skipped: 0,
|
||||
ok: true
|
||||
};
|
||||
};
|
||||
const addStats = (stats, delta) => {
|
||||
stats.total += delta.total;
|
||||
stats.skipped += delta.skipped;
|
||||
stats.expected += delta.expected;
|
||||
stats.unexpected += delta.unexpected;
|
||||
stats.flaky += delta.flaky;
|
||||
stats.ok = stats.ok && delta.ok;
|
||||
return stats;
|
||||
};
|
||||
class Base64Encoder extends import_stream.Transform {
|
||||
_transform(chunk, encoding, callback) {
|
||||
if (this._remainder) {
|
||||
chunk = Buffer.concat([this._remainder, chunk]);
|
||||
this._remainder = void 0;
|
||||
}
|
||||
const remaining = chunk.length % 3;
|
||||
if (remaining) {
|
||||
this._remainder = chunk.slice(chunk.length - remaining);
|
||||
chunk = chunk.slice(0, chunk.length - remaining);
|
||||
}
|
||||
chunk = chunk.toString("base64");
|
||||
this.push(Buffer.from(chunk));
|
||||
callback();
|
||||
}
|
||||
_flush(callback) {
|
||||
if (this._remainder)
|
||||
this.push(Buffer.from(this._remainder.toString("base64")));
|
||||
callback();
|
||||
}
|
||||
}
|
||||
function isTextContentType(contentType) {
|
||||
return contentType.startsWith("text/") || contentType.startsWith("application/json");
|
||||
}
|
||||
function stdioAttachment(chunk, type) {
|
||||
return {
|
||||
name: type,
|
||||
contentType: "text/plain",
|
||||
body: typeof chunk === "string" ? chunk : chunk.toString("utf-8")
|
||||
};
|
||||
}
|
||||
function dedupeSteps(steps) {
|
||||
const result = [];
|
||||
let lastResult = void 0;
|
||||
for (const step of steps) {
|
||||
const canDedupe = !step.error && step.duration >= 0 && step.location?.file && !step.steps.length;
|
||||
const lastStep = lastResult?.step;
|
||||
if (canDedupe && lastResult && lastStep && step.category === lastStep.category && step.title === lastStep.title && step.location?.file === lastStep.location?.file && step.location?.line === lastStep.location?.line && step.location?.column === lastStep.location?.column) {
|
||||
++lastResult.count;
|
||||
lastResult.duration += step.duration;
|
||||
continue;
|
||||
}
|
||||
lastResult = { step, count: 1, duration: step.duration };
|
||||
result.push(lastResult);
|
||||
if (!canDedupe)
|
||||
lastResult = void 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function createSnippets(stepsInFile) {
|
||||
for (const file of stepsInFile.keys()) {
|
||||
let source;
|
||||
try {
|
||||
source = import_fs.default.readFileSync(file, "utf-8") + "\n//";
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
const lines = source.split("\n").length;
|
||||
const highlighted = (0, import_babelBundle.codeFrameColumns)(source, { start: { line: lines, column: 1 } }, { highlightCode: true, linesAbove: lines, linesBelow: 0 });
|
||||
const highlightedLines = highlighted.split("\n");
|
||||
const lineWithArrow = highlightedLines[highlightedLines.length - 1];
|
||||
for (const step of stepsInFile.get(file)) {
|
||||
if (step.location.line < 2 || step.location.line >= lines)
|
||||
continue;
|
||||
const snippetLines = highlightedLines.slice(step.location.line - 2, step.location.line + 1);
|
||||
const index = lineWithArrow.indexOf("^");
|
||||
const shiftedArrow = lineWithArrow.slice(0, index) + " ".repeat(step.location.column - 1) + lineWithArrow.slice(index);
|
||||
snippetLines.splice(2, 0, shiftedArrow);
|
||||
step.snippet = snippetLines.join("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
function createErrorCodeframe(message, location) {
|
||||
let source;
|
||||
try {
|
||||
source = import_fs.default.readFileSync(location.file, "utf-8") + "\n//";
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
return (0, import_babelBundle.codeFrameColumns)(
|
||||
source,
|
||||
{
|
||||
start: {
|
||||
line: location.line,
|
||||
column: location.column
|
||||
}
|
||||
},
|
||||
{
|
||||
highlightCode: false,
|
||||
linesAbove: 100,
|
||||
linesBelow: 100,
|
||||
message: (0, import_util.stripAnsiEscapes)(message).split("\n")[0] || void 0
|
||||
}
|
||||
);
|
||||
}
|
||||
function writeLine(line) {
|
||||
process.stdout.write(line + "\n");
|
||||
}
|
||||
var html_default = HtmlReporter;
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
showHTMLReport,
|
||||
startHtmlReportServer
|
||||
});
|
130
node_modules/playwright/lib/reporters/internalReporter.js
generated
vendored
Normal file
130
node_modules/playwright/lib/reporters/internalReporter.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
"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 internalReporter_exports = {};
|
||||
__export(internalReporter_exports, {
|
||||
InternalReporter: () => InternalReporter
|
||||
});
|
||||
module.exports = __toCommonJS(internalReporter_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_base = require("./base");
|
||||
var import_multiplexer = require("./multiplexer");
|
||||
var import_test = require("../common/test");
|
||||
var import_babelBundle = require("../transform/babelBundle");
|
||||
var import_reporterV2 = require("./reporterV2");
|
||||
class InternalReporter {
|
||||
constructor(reporters) {
|
||||
this._didBegin = false;
|
||||
this._reporter = new import_multiplexer.Multiplexer(reporters.map(import_reporterV2.wrapReporterAsV2));
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
this._config = config;
|
||||
this._startTime = /* @__PURE__ */ new Date();
|
||||
this._monotonicStartTime = (0, import_utils.monotonicTime)();
|
||||
this._reporter.onConfigure?.(config);
|
||||
}
|
||||
onBegin(suite) {
|
||||
this._didBegin = true;
|
||||
this._reporter.onBegin?.(suite);
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
this._reporter.onStdOut?.(chunk, test, result);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
this._reporter.onStdErr?.(chunk, test, result);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
this._addSnippetToTestErrors(test, result);
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
}
|
||||
async onEnd(result) {
|
||||
if (!this._didBegin) {
|
||||
this.onBegin(new import_test.Suite("", "root"));
|
||||
}
|
||||
return await this._reporter.onEnd?.({
|
||||
...result,
|
||||
startTime: this._startTime,
|
||||
duration: (0, import_utils.monotonicTime)() - this._monotonicStartTime
|
||||
});
|
||||
}
|
||||
async onExit() {
|
||||
await this._reporter.onExit?.();
|
||||
}
|
||||
onError(error) {
|
||||
addLocationAndSnippetToError(this._config, error);
|
||||
this._reporter.onError?.(error);
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
this._reporter.onStepBegin?.(test, result, step);
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
this._addSnippetToStepError(test, step);
|
||||
this._reporter.onStepEnd?.(test, result, step);
|
||||
}
|
||||
printsToStdio() {
|
||||
return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
|
||||
}
|
||||
_addSnippetToTestErrors(test, result) {
|
||||
for (const error of result.errors)
|
||||
addLocationAndSnippetToError(this._config, error, test.location.file);
|
||||
}
|
||||
_addSnippetToStepError(test, step) {
|
||||
if (step.error)
|
||||
addLocationAndSnippetToError(this._config, step.error, test.location.file);
|
||||
}
|
||||
}
|
||||
function addLocationAndSnippetToError(config, error, file) {
|
||||
if (error.stack && !error.location)
|
||||
error.location = (0, import_base.prepareErrorStack)(error.stack).location;
|
||||
const location = error.location;
|
||||
if (!location)
|
||||
return;
|
||||
try {
|
||||
const tokens = [];
|
||||
const source = import_fs.default.readFileSync(location.file, "utf8");
|
||||
const codeFrame = (0, import_babelBundle.codeFrameColumns)(source, { start: location }, { highlightCode: true });
|
||||
if (!file || import_fs.default.realpathSync(file) !== location.file) {
|
||||
tokens.push(import_base.internalScreen.colors.gray(` at `) + `${(0, import_base.relativeFilePath)(import_base.internalScreen, config, location.file)}:${location.line}`);
|
||||
tokens.push("");
|
||||
}
|
||||
tokens.push(codeFrame);
|
||||
error.snippet = tokens.join("\n");
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
InternalReporter
|
||||
});
|
254
node_modules/playwright/lib/reporters/json.js
generated
vendored
Normal file
254
node_modules/playwright/lib/reporters/json.js
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
"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 json_exports = {};
|
||||
__export(json_exports, {
|
||||
default: () => json_default,
|
||||
serializePatterns: () => serializePatterns
|
||||
});
|
||||
module.exports = __toCommonJS(json_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_base = require("./base");
|
||||
var import_config = require("../common/config");
|
||||
class JSONReporter {
|
||||
constructor(options) {
|
||||
this._errors = [];
|
||||
this._resolvedOutputFile = (0, import_base.resolveOutputFile)("JSON", options)?.outputFile;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
printsToStdio() {
|
||||
return !this._resolvedOutputFile;
|
||||
}
|
||||
onConfigure(config) {
|
||||
this.config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this.suite = suite;
|
||||
}
|
||||
onError(error) {
|
||||
this._errors.push(error);
|
||||
}
|
||||
async onEnd(result) {
|
||||
await outputReport(this._serializeReport(result), this._resolvedOutputFile);
|
||||
}
|
||||
_serializeReport(result) {
|
||||
const report = {
|
||||
config: {
|
||||
...removePrivateFields(this.config),
|
||||
rootDir: (0, import_utils.toPosixPath)(this.config.rootDir),
|
||||
projects: this.config.projects.map((project) => {
|
||||
return {
|
||||
outputDir: (0, import_utils.toPosixPath)(project.outputDir),
|
||||
repeatEach: project.repeatEach,
|
||||
retries: project.retries,
|
||||
metadata: project.metadata,
|
||||
id: (0, import_config.getProjectId)(project),
|
||||
name: project.name,
|
||||
testDir: (0, import_utils.toPosixPath)(project.testDir),
|
||||
testIgnore: serializePatterns(project.testIgnore),
|
||||
testMatch: serializePatterns(project.testMatch),
|
||||
timeout: project.timeout
|
||||
};
|
||||
})
|
||||
},
|
||||
suites: this._mergeSuites(this.suite.suites),
|
||||
errors: this._errors,
|
||||
stats: {
|
||||
startTime: result.startTime.toISOString(),
|
||||
duration: result.duration,
|
||||
expected: 0,
|
||||
skipped: 0,
|
||||
unexpected: 0,
|
||||
flaky: 0
|
||||
}
|
||||
};
|
||||
for (const test of this.suite.allTests())
|
||||
++report.stats[test.outcome()];
|
||||
return report;
|
||||
}
|
||||
_mergeSuites(suites) {
|
||||
const fileSuites = new import_utils.MultiMap();
|
||||
for (const projectSuite of suites) {
|
||||
const projectId = (0, import_config.getProjectId)(projectSuite.project());
|
||||
const projectName = projectSuite.project().name;
|
||||
for (const fileSuite of projectSuite.suites) {
|
||||
const file = fileSuite.location.file;
|
||||
const serialized = this._serializeSuite(projectId, projectName, fileSuite);
|
||||
if (serialized)
|
||||
fileSuites.set(file, serialized);
|
||||
}
|
||||
}
|
||||
const results = [];
|
||||
for (const [, suites2] of fileSuites) {
|
||||
const result = {
|
||||
title: suites2[0].title,
|
||||
file: suites2[0].file,
|
||||
column: 0,
|
||||
line: 0,
|
||||
specs: []
|
||||
};
|
||||
for (const suite of suites2)
|
||||
this._mergeTestsFromSuite(result, suite);
|
||||
results.push(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
_relativeLocation(location) {
|
||||
if (!location)
|
||||
return { file: "", line: 0, column: 0 };
|
||||
return {
|
||||
file: (0, import_utils.toPosixPath)(import_path.default.relative(this.config.rootDir, location.file)),
|
||||
line: location.line,
|
||||
column: location.column
|
||||
};
|
||||
}
|
||||
_locationMatches(s1, s2) {
|
||||
return s1.file === s2.file && s1.line === s2.line && s1.column === s2.column;
|
||||
}
|
||||
_mergeTestsFromSuite(to, from) {
|
||||
for (const fromSuite of from.suites || []) {
|
||||
const toSuite = (to.suites || []).find((s) => s.title === fromSuite.title && this._locationMatches(s, fromSuite));
|
||||
if (toSuite) {
|
||||
this._mergeTestsFromSuite(toSuite, fromSuite);
|
||||
} else {
|
||||
if (!to.suites)
|
||||
to.suites = [];
|
||||
to.suites.push(fromSuite);
|
||||
}
|
||||
}
|
||||
for (const spec of from.specs || []) {
|
||||
const toSpec = to.specs.find((s) => s.title === spec.title && s.file === (0, import_utils.toPosixPath)(import_path.default.relative(this.config.rootDir, spec.file)) && s.line === spec.line && s.column === spec.column);
|
||||
if (toSpec)
|
||||
toSpec.tests.push(...spec.tests);
|
||||
else
|
||||
to.specs.push(spec);
|
||||
}
|
||||
}
|
||||
_serializeSuite(projectId, projectName, suite) {
|
||||
if (!suite.allTests().length)
|
||||
return null;
|
||||
const suites = suite.suites.map((suite2) => this._serializeSuite(projectId, projectName, suite2)).filter((s) => s);
|
||||
return {
|
||||
title: suite.title,
|
||||
...this._relativeLocation(suite.location),
|
||||
specs: suite.tests.map((test) => this._serializeTestSpec(projectId, projectName, test)),
|
||||
suites: suites.length ? suites : void 0
|
||||
};
|
||||
}
|
||||
_serializeTestSpec(projectId, projectName, test) {
|
||||
return {
|
||||
title: test.title,
|
||||
ok: test.ok(),
|
||||
tags: test.tags.map((tag) => tag.substring(1)),
|
||||
// Strip '@'.
|
||||
tests: [this._serializeTest(projectId, projectName, test)],
|
||||
id: test.id,
|
||||
...this._relativeLocation(test.location)
|
||||
};
|
||||
}
|
||||
_serializeTest(projectId, projectName, test) {
|
||||
return {
|
||||
timeout: test.timeout,
|
||||
annotations: test.annotations,
|
||||
expectedStatus: test.expectedStatus,
|
||||
projectId,
|
||||
projectName,
|
||||
results: test.results.map((r) => this._serializeTestResult(r, test)),
|
||||
status: test.outcome()
|
||||
};
|
||||
}
|
||||
_serializeTestResult(result, test) {
|
||||
const steps = result.steps.filter((s) => s.category === "test.step");
|
||||
const jsonResult = {
|
||||
workerIndex: result.workerIndex,
|
||||
parallelIndex: result.parallelIndex,
|
||||
status: result.status,
|
||||
duration: result.duration,
|
||||
error: result.error,
|
||||
errors: result.errors.map((e) => this._serializeError(e)),
|
||||
stdout: result.stdout.map((s) => stdioEntry(s)),
|
||||
stderr: result.stderr.map((s) => stdioEntry(s)),
|
||||
retry: result.retry,
|
||||
steps: steps.length ? steps.map((s) => this._serializeTestStep(s)) : void 0,
|
||||
startTime: result.startTime.toISOString(),
|
||||
annotations: result.annotations,
|
||||
attachments: result.attachments.map((a) => ({
|
||||
name: a.name,
|
||||
contentType: a.contentType,
|
||||
path: a.path,
|
||||
body: a.body?.toString("base64")
|
||||
}))
|
||||
};
|
||||
if (result.error?.stack)
|
||||
jsonResult.errorLocation = (0, import_base.prepareErrorStack)(result.error.stack).location;
|
||||
return jsonResult;
|
||||
}
|
||||
_serializeError(error) {
|
||||
return (0, import_base.formatError)(import_base.nonTerminalScreen, error);
|
||||
}
|
||||
_serializeTestStep(step) {
|
||||
const steps = step.steps.filter((s) => s.category === "test.step");
|
||||
return {
|
||||
title: step.title,
|
||||
duration: step.duration,
|
||||
error: step.error,
|
||||
steps: steps.length ? steps.map((s) => this._serializeTestStep(s)) : void 0
|
||||
};
|
||||
}
|
||||
}
|
||||
async function outputReport(report, resolvedOutputFile) {
|
||||
const reportString = JSON.stringify(report, void 0, 2);
|
||||
if (resolvedOutputFile) {
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(resolvedOutputFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(resolvedOutputFile, reportString);
|
||||
} else {
|
||||
console.log(reportString);
|
||||
}
|
||||
}
|
||||
function stdioEntry(s) {
|
||||
if (typeof s === "string")
|
||||
return { text: s };
|
||||
return { buffer: s.toString("base64") };
|
||||
}
|
||||
function removePrivateFields(config) {
|
||||
return Object.fromEntries(Object.entries(config).filter(([name, value]) => !name.startsWith("_")));
|
||||
}
|
||||
function serializePatterns(patterns) {
|
||||
if (!Array.isArray(patterns))
|
||||
patterns = [patterns];
|
||||
return patterns.map((s) => s.toString());
|
||||
}
|
||||
var json_default = JSONReporter;
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
serializePatterns
|
||||
});
|
230
node_modules/playwright/lib/reporters/junit.js
generated
vendored
Normal file
230
node_modules/playwright/lib/reporters/junit.js
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
"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 junit_exports = {};
|
||||
__export(junit_exports, {
|
||||
default: () => junit_default
|
||||
});
|
||||
module.exports = __toCommonJS(junit_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_base = require("./base");
|
||||
var import_util = require("../util");
|
||||
class JUnitReporter {
|
||||
constructor(options) {
|
||||
this.totalTests = 0;
|
||||
this.totalFailures = 0;
|
||||
this.totalSkipped = 0;
|
||||
this.stripANSIControlSequences = false;
|
||||
this.includeProjectInTestName = false;
|
||||
this.stripANSIControlSequences = (0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_JUNIT_STRIP_ANSI", !!options.stripANSIControlSequences);
|
||||
this.includeProjectInTestName = (0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME", !!options.includeProjectInTestName);
|
||||
this.configDir = options.configDir;
|
||||
this.resolvedOutputFile = (0, import_base.resolveOutputFile)("JUNIT", options)?.outputFile;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
printsToStdio() {
|
||||
return !this.resolvedOutputFile;
|
||||
}
|
||||
onConfigure(config) {
|
||||
this.config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this.suite = suite;
|
||||
this.timestamp = /* @__PURE__ */ new Date();
|
||||
}
|
||||
async onEnd(result) {
|
||||
const children = [];
|
||||
for (const projectSuite of this.suite.suites) {
|
||||
for (const fileSuite of projectSuite.suites)
|
||||
children.push(await this._buildTestSuite(projectSuite.title, fileSuite));
|
||||
}
|
||||
const tokens = [];
|
||||
const self = this;
|
||||
const root = {
|
||||
name: "testsuites",
|
||||
attributes: {
|
||||
id: process.env[`PLAYWRIGHT_JUNIT_SUITE_ID`] || "",
|
||||
name: process.env[`PLAYWRIGHT_JUNIT_SUITE_NAME`] || "",
|
||||
tests: self.totalTests,
|
||||
failures: self.totalFailures,
|
||||
skipped: self.totalSkipped,
|
||||
errors: 0,
|
||||
time: result.duration / 1e3
|
||||
},
|
||||
children
|
||||
};
|
||||
serializeXML(root, tokens, this.stripANSIControlSequences);
|
||||
const reportString = tokens.join("\n");
|
||||
if (this.resolvedOutputFile) {
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(this.resolvedOutputFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(this.resolvedOutputFile, reportString);
|
||||
} else {
|
||||
console.log(reportString);
|
||||
}
|
||||
}
|
||||
async _buildTestSuite(projectName, suite) {
|
||||
let tests = 0;
|
||||
let skipped = 0;
|
||||
let failures = 0;
|
||||
let duration = 0;
|
||||
const children = [];
|
||||
const testCaseNamePrefix = projectName && this.includeProjectInTestName ? `[${projectName}] ` : "";
|
||||
for (const test of suite.allTests()) {
|
||||
++tests;
|
||||
if (test.outcome() === "skipped")
|
||||
++skipped;
|
||||
if (!test.ok())
|
||||
++failures;
|
||||
for (const result of test.results)
|
||||
duration += result.duration;
|
||||
await this._addTestCase(suite.title, testCaseNamePrefix, test, children);
|
||||
}
|
||||
this.totalTests += tests;
|
||||
this.totalSkipped += skipped;
|
||||
this.totalFailures += failures;
|
||||
const entry = {
|
||||
name: "testsuite",
|
||||
attributes: {
|
||||
name: suite.title,
|
||||
timestamp: this.timestamp.toISOString(),
|
||||
hostname: projectName,
|
||||
tests,
|
||||
failures,
|
||||
skipped,
|
||||
time: duration / 1e3,
|
||||
errors: 0
|
||||
},
|
||||
children
|
||||
};
|
||||
return entry;
|
||||
}
|
||||
async _addTestCase(suiteName, namePrefix, test, entries) {
|
||||
const entry = {
|
||||
name: "testcase",
|
||||
attributes: {
|
||||
// Skip root, project, file
|
||||
name: namePrefix + test.titlePath().slice(3).join(" \u203A "),
|
||||
// filename
|
||||
classname: suiteName,
|
||||
time: test.results.reduce((acc, value) => acc + value.duration, 0) / 1e3
|
||||
},
|
||||
children: []
|
||||
};
|
||||
entries.push(entry);
|
||||
const properties = {
|
||||
name: "properties",
|
||||
children: []
|
||||
};
|
||||
for (const annotation of test.annotations) {
|
||||
const property = {
|
||||
name: "property",
|
||||
attributes: {
|
||||
name: annotation.type,
|
||||
value: annotation?.description ? annotation.description : ""
|
||||
}
|
||||
};
|
||||
properties.children?.push(property);
|
||||
}
|
||||
if (properties.children?.length)
|
||||
entry.children.push(properties);
|
||||
if (test.outcome() === "skipped") {
|
||||
entry.children.push({ name: "skipped" });
|
||||
return;
|
||||
}
|
||||
if (!test.ok()) {
|
||||
entry.children.push({
|
||||
name: "failure",
|
||||
attributes: {
|
||||
message: `${import_path.default.basename(test.location.file)}:${test.location.line}:${test.location.column} ${test.title}`,
|
||||
type: "FAILURE"
|
||||
},
|
||||
text: (0, import_util.stripAnsiEscapes)((0, import_base.formatFailure)(import_base.nonTerminalScreen, this.config, test))
|
||||
});
|
||||
}
|
||||
const systemOut = [];
|
||||
const systemErr = [];
|
||||
for (const result of test.results) {
|
||||
systemOut.push(...result.stdout.map((item) => item.toString()));
|
||||
systemErr.push(...result.stderr.map((item) => item.toString()));
|
||||
for (const attachment of result.attachments) {
|
||||
if (!attachment.path)
|
||||
continue;
|
||||
let attachmentPath = import_path.default.relative(this.configDir, attachment.path);
|
||||
try {
|
||||
if (this.resolvedOutputFile)
|
||||
attachmentPath = import_path.default.relative(import_path.default.dirname(this.resolvedOutputFile), attachment.path);
|
||||
} catch {
|
||||
systemOut.push(`
|
||||
Warning: Unable to make attachment path ${attachment.path} relative to report output file ${this.resolvedOutputFile}`);
|
||||
}
|
||||
try {
|
||||
await import_fs.default.promises.access(attachment.path);
|
||||
systemOut.push(`
|
||||
[[ATTACHMENT|${attachmentPath}]]
|
||||
`);
|
||||
} catch {
|
||||
systemErr.push(`
|
||||
Warning: attachment ${attachmentPath} is missing`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (systemOut.length)
|
||||
entry.children.push({ name: "system-out", text: systemOut.join("") });
|
||||
if (systemErr.length)
|
||||
entry.children.push({ name: "system-err", text: systemErr.join("") });
|
||||
}
|
||||
}
|
||||
function serializeXML(entry, tokens, stripANSIControlSequences) {
|
||||
const attrs = [];
|
||||
for (const [name, value] of Object.entries(entry.attributes || {}))
|
||||
attrs.push(`${name}="${escape(String(value), stripANSIControlSequences, false)}"`);
|
||||
tokens.push(`<${entry.name}${attrs.length ? " " : ""}${attrs.join(" ")}>`);
|
||||
for (const child of entry.children || [])
|
||||
serializeXML(child, tokens, stripANSIControlSequences);
|
||||
if (entry.text)
|
||||
tokens.push(escape(entry.text, stripANSIControlSequences, true));
|
||||
tokens.push(`</${entry.name}>`);
|
||||
}
|
||||
const discouragedXMLCharacters = /[\u0000-\u0008\u000b-\u000c\u000e-\u001f\u007f-\u0084\u0086-\u009f]/g;
|
||||
function escape(text, stripANSIControlSequences, isCharacterData) {
|
||||
if (stripANSIControlSequences)
|
||||
text = (0, import_util.stripAnsiEscapes)(text);
|
||||
if (isCharacterData) {
|
||||
text = "<![CDATA[" + text.replace(/]]>/g, "]]>") + "]]>";
|
||||
} else {
|
||||
const escapeRe = /[&"'<>]/g;
|
||||
text = text.replace(escapeRe, (c) => ({ "&": "&", '"': """, "'": "'", "<": "<", ">": ">" })[c]);
|
||||
}
|
||||
text = text.replace(discouragedXMLCharacters, "");
|
||||
return text;
|
||||
}
|
||||
var junit_default = JUnitReporter;
|
113
node_modules/playwright/lib/reporters/line.js
generated
vendored
Normal file
113
node_modules/playwright/lib/reporters/line.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var line_exports = {};
|
||||
__export(line_exports, {
|
||||
default: () => line_default
|
||||
});
|
||||
module.exports = __toCommonJS(line_exports);
|
||||
var import_base = require("./base");
|
||||
class LineReporter extends import_base.TerminalReporter {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this._current = 0;
|
||||
this._failures = 0;
|
||||
this._didBegin = false;
|
||||
}
|
||||
onBegin(suite) {
|
||||
super.onBegin(suite);
|
||||
const startingMessage = this.generateStartingMessage();
|
||||
if (startingMessage) {
|
||||
this.writeLine(startingMessage);
|
||||
this.writeLine();
|
||||
}
|
||||
this._didBegin = true;
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
super.onStdOut(chunk, test, result);
|
||||
this._dumpToStdio(test, chunk, this.screen.stdout);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
super.onStdErr(chunk, test, result);
|
||||
this._dumpToStdio(test, chunk, this.screen.stderr);
|
||||
}
|
||||
_dumpToStdio(test, chunk, stream) {
|
||||
if (this.config.quiet)
|
||||
return;
|
||||
if (!process.env.PW_TEST_DEBUG_REPORTERS)
|
||||
stream.write(`\x1B[1A\x1B[2K`);
|
||||
if (test && this._lastTest !== test) {
|
||||
const title = this.screen.colors.dim(this.formatTestTitle(test));
|
||||
stream.write(this.fitToScreen(title) + `
|
||||
`);
|
||||
this._lastTest = test;
|
||||
}
|
||||
stream.write(chunk);
|
||||
if (chunk[chunk.length - 1] !== "\n")
|
||||
this.writeLine();
|
||||
this.writeLine();
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
++this._current;
|
||||
this._updateLine(test, result, void 0);
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
if (this.screen.isTTY && step.category === "test.step")
|
||||
this._updateLine(test, result, step);
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
if (this.screen.isTTY && step.category === "test.step")
|
||||
this._updateLine(test, result, step.parent);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
super.onTestEnd(test, result);
|
||||
if (!this.willRetry(test) && (test.outcome() === "flaky" || test.outcome() === "unexpected" || result.status === "interrupted")) {
|
||||
if (!process.env.PW_TEST_DEBUG_REPORTERS)
|
||||
this.screen.stdout.write(`\x1B[1A\x1B[2K`);
|
||||
this.writeLine(this.formatFailure(test, ++this._failures));
|
||||
this.writeLine();
|
||||
}
|
||||
}
|
||||
_updateLine(test, result, step) {
|
||||
const retriesPrefix = this.totalTestCount < this._current ? ` (retries)` : ``;
|
||||
const prefix = `[${this._current}/${this.totalTestCount}]${retriesPrefix} `;
|
||||
const currentRetrySuffix = result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : "";
|
||||
const title = this.formatTestTitle(test, step) + currentRetrySuffix;
|
||||
if (process.env.PW_TEST_DEBUG_REPORTERS)
|
||||
this.screen.stdout.write(`${prefix + title}
|
||||
`);
|
||||
else
|
||||
this.screen.stdout.write(`\x1B[1A\x1B[2K${prefix + this.fitToScreen(title, prefix)}
|
||||
`);
|
||||
}
|
||||
onError(error) {
|
||||
super.onError(error);
|
||||
const message = this.formatError(error).message + "\n";
|
||||
if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
|
||||
this.screen.stdout.write(`\x1B[1A\x1B[2K`);
|
||||
this.screen.stdout.write(message);
|
||||
this.writeLine();
|
||||
}
|
||||
async onEnd(result) {
|
||||
if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
|
||||
this.screen.stdout.write(`\x1B[1A\x1B[2K`);
|
||||
await super.onEnd(result);
|
||||
this.epilogue(false);
|
||||
}
|
||||
}
|
||||
var line_default = LineReporter;
|
231
node_modules/playwright/lib/reporters/list.js
generated
vendored
Normal file
231
node_modules/playwright/lib/reporters/list.js
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var list_exports = {};
|
||||
__export(list_exports, {
|
||||
default: () => list_default
|
||||
});
|
||||
module.exports = __toCommonJS(list_exports);
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_base = require("./base");
|
||||
var import_util = require("../util");
|
||||
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === "win32" && process.env.TERM_PROGRAM !== "vscode" && !process.env.WT_SESSION;
|
||||
const POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? "ok" : "\u2713";
|
||||
const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? "x" : "\u2718";
|
||||
class ListReporter extends import_base.TerminalReporter {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this._lastRow = 0;
|
||||
this._lastColumn = 0;
|
||||
this._testRows = /* @__PURE__ */ new Map();
|
||||
this._stepRows = /* @__PURE__ */ new Map();
|
||||
this._resultIndex = /* @__PURE__ */ new Map();
|
||||
this._stepIndex = /* @__PURE__ */ new Map();
|
||||
this._needNewLine = false;
|
||||
this._printSteps = (0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_LIST_PRINT_STEPS", options?.printSteps);
|
||||
}
|
||||
onBegin(suite) {
|
||||
super.onBegin(suite);
|
||||
const startingMessage = this.generateStartingMessage();
|
||||
if (startingMessage) {
|
||||
this.writeLine(startingMessage);
|
||||
this.writeLine("");
|
||||
}
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
const index = String(this._resultIndex.size + 1);
|
||||
this._resultIndex.set(result, index);
|
||||
if (!this.screen.isTTY)
|
||||
return;
|
||||
this._maybeWriteNewLine();
|
||||
this._testRows.set(test, this._lastRow);
|
||||
const prefix = this._testPrefix(index, "");
|
||||
const line = this.screen.colors.dim(this.formatTestTitle(test)) + this._retrySuffix(result);
|
||||
this._appendLine(line, prefix);
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
super.onStdOut(chunk, test, result);
|
||||
this._dumpToStdio(test, chunk, this.screen.stdout);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
super.onStdErr(chunk, test, result);
|
||||
this._dumpToStdio(test, chunk, this.screen.stderr);
|
||||
}
|
||||
getStepIndex(testIndex, result, step) {
|
||||
if (this._stepIndex.has(step))
|
||||
return this._stepIndex.get(step);
|
||||
const ordinal = (result[lastStepOrdinalSymbol] || 0) + 1;
|
||||
result[lastStepOrdinalSymbol] = ordinal;
|
||||
const stepIndex = `${testIndex}.${ordinal}`;
|
||||
this._stepIndex.set(step, stepIndex);
|
||||
return stepIndex;
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
if (step.category !== "test.step")
|
||||
return;
|
||||
const testIndex = this._resultIndex.get(result) || "";
|
||||
if (!this.screen.isTTY)
|
||||
return;
|
||||
if (this._printSteps) {
|
||||
this._maybeWriteNewLine();
|
||||
this._stepRows.set(step, this._lastRow);
|
||||
const prefix = this._testPrefix(this.getStepIndex(testIndex, result, step), "");
|
||||
const line = test.title + this.screen.colors.dim((0, import_base.stepSuffix)(step));
|
||||
this._appendLine(line, prefix);
|
||||
} else {
|
||||
this._updateOrAppendLine(this._testRows, test, this.screen.colors.dim(this.formatTestTitle(test, step)) + this._retrySuffix(result), this._testPrefix(testIndex, ""));
|
||||
}
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
if (step.category !== "test.step")
|
||||
return;
|
||||
const testIndex = this._resultIndex.get(result) || "";
|
||||
if (!this._printSteps) {
|
||||
if (this.screen.isTTY)
|
||||
this._updateOrAppendLine(this._testRows, test, this.screen.colors.dim(this.formatTestTitle(test, step.parent)) + this._retrySuffix(result), this._testPrefix(testIndex, ""));
|
||||
return;
|
||||
}
|
||||
const index = this.getStepIndex(testIndex, result, step);
|
||||
const title = this.screen.isTTY ? test.title + this.screen.colors.dim((0, import_base.stepSuffix)(step)) : this.formatTestTitle(test, step);
|
||||
const prefix = this._testPrefix(index, "");
|
||||
let text = "";
|
||||
if (step.error)
|
||||
text = this.screen.colors.red(title);
|
||||
else
|
||||
text = title;
|
||||
text += this.screen.colors.dim(` (${(0, import_utilsBundle.ms)(step.duration)})`);
|
||||
this._updateOrAppendLine(this._stepRows, step, text, prefix);
|
||||
}
|
||||
_maybeWriteNewLine() {
|
||||
if (this._needNewLine) {
|
||||
this._needNewLine = false;
|
||||
this.screen.stdout.write("\n");
|
||||
++this._lastRow;
|
||||
this._lastColumn = 0;
|
||||
}
|
||||
}
|
||||
_updateLineCountAndNewLineFlagForOutput(text) {
|
||||
this._needNewLine = text[text.length - 1] !== "\n";
|
||||
if (!this.screen.ttyWidth)
|
||||
return;
|
||||
for (const ch of text) {
|
||||
if (ch === "\n") {
|
||||
this._lastColumn = 0;
|
||||
++this._lastRow;
|
||||
continue;
|
||||
}
|
||||
++this._lastColumn;
|
||||
if (this._lastColumn > this.screen.ttyWidth) {
|
||||
this._lastColumn = 0;
|
||||
++this._lastRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
_dumpToStdio(test, chunk, stream) {
|
||||
if (this.config.quiet)
|
||||
return;
|
||||
const text = chunk.toString("utf-8");
|
||||
this._updateLineCountAndNewLineFlagForOutput(text);
|
||||
stream.write(chunk);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
super.onTestEnd(test, result);
|
||||
const title = this.formatTestTitle(test);
|
||||
let prefix = "";
|
||||
let text = "";
|
||||
let index = this._resultIndex.get(result);
|
||||
if (!index) {
|
||||
index = String(this._resultIndex.size + 1);
|
||||
this._resultIndex.set(result, index);
|
||||
}
|
||||
if (result.status === "skipped") {
|
||||
prefix = this._testPrefix(index, this.screen.colors.green("-"));
|
||||
text = this.screen.colors.cyan(title) + this._retrySuffix(result);
|
||||
} else {
|
||||
const statusMark = result.status === "passed" ? POSITIVE_STATUS_MARK : NEGATIVE_STATUS_MARK;
|
||||
if (result.status === test.expectedStatus) {
|
||||
prefix = this._testPrefix(index, this.screen.colors.green(statusMark));
|
||||
text = title;
|
||||
} else {
|
||||
prefix = this._testPrefix(index, this.screen.colors.red(statusMark));
|
||||
text = this.screen.colors.red(title);
|
||||
}
|
||||
text += this._retrySuffix(result) + this.screen.colors.dim(` (${(0, import_utilsBundle.ms)(result.duration)})`);
|
||||
}
|
||||
this._updateOrAppendLine(this._testRows, test, text, prefix);
|
||||
}
|
||||
_updateOrAppendLine(entityRowNumbers, entity, text, prefix) {
|
||||
const row = entityRowNumbers.get(entity);
|
||||
if (row !== void 0 && this.screen.isTTY && this._lastRow - row < this.screen.ttyHeight) {
|
||||
this._updateLine(row, text, prefix);
|
||||
} else {
|
||||
this._maybeWriteNewLine();
|
||||
entityRowNumbers.set(entity, this._lastRow);
|
||||
this._appendLine(text, prefix);
|
||||
}
|
||||
}
|
||||
_appendLine(text, prefix) {
|
||||
const line = prefix + this.fitToScreen(text, prefix);
|
||||
if (process.env.PW_TEST_DEBUG_REPORTERS) {
|
||||
this.screen.stdout.write("#" + this._lastRow + " : " + line + "\n");
|
||||
} else {
|
||||
this.screen.stdout.write(line);
|
||||
this.screen.stdout.write("\n");
|
||||
}
|
||||
++this._lastRow;
|
||||
this._lastColumn = 0;
|
||||
}
|
||||
_updateLine(row, text, prefix) {
|
||||
const line = prefix + this.fitToScreen(text, prefix);
|
||||
if (process.env.PW_TEST_DEBUG_REPORTERS)
|
||||
this.screen.stdout.write("#" + row + " : " + line + "\n");
|
||||
else
|
||||
this._updateLineForTTY(row, line);
|
||||
}
|
||||
_updateLineForTTY(row, line) {
|
||||
if (row !== this._lastRow)
|
||||
this.screen.stdout.write(`\x1B[${this._lastRow - row}A`);
|
||||
this.screen.stdout.write("\x1B[2K\x1B[0G");
|
||||
this.screen.stdout.write(line);
|
||||
if (row !== this._lastRow)
|
||||
this.screen.stdout.write(`\x1B[${this._lastRow - row}E`);
|
||||
}
|
||||
_testPrefix(index, statusMark) {
|
||||
const statusMarkLength = (0, import_util.stripAnsiEscapes)(statusMark).length;
|
||||
const indexLength = Math.ceil(Math.log10(this.totalTestCount + 1));
|
||||
return " " + statusMark + " ".repeat(3 - statusMarkLength) + this.screen.colors.dim(index.padStart(indexLength) + " ");
|
||||
}
|
||||
_retrySuffix(result) {
|
||||
return result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : "";
|
||||
}
|
||||
onError(error) {
|
||||
super.onError(error);
|
||||
this._maybeWriteNewLine();
|
||||
const message = this.formatError(error).message + "\n";
|
||||
this._updateLineCountAndNewLineFlagForOutput(message);
|
||||
this.screen.stdout.write(message);
|
||||
}
|
||||
async onEnd(result) {
|
||||
await super.onEnd(result);
|
||||
this.screen.stdout.write("\n");
|
||||
this.epilogue(true);
|
||||
}
|
||||
}
|
||||
const lastStepOrdinalSymbol = Symbol("lastStepOrdinal");
|
||||
var list_default = ListReporter;
|
66
node_modules/playwright/lib/reporters/listModeReporter.js
generated
vendored
Normal file
66
node_modules/playwright/lib/reporters/listModeReporter.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
"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 listModeReporter_exports = {};
|
||||
__export(listModeReporter_exports, {
|
||||
default: () => listModeReporter_default
|
||||
});
|
||||
module.exports = __toCommonJS(listModeReporter_exports);
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_base = require("./base");
|
||||
class ListModeReporter {
|
||||
constructor(options) {
|
||||
this.screen = options?.screen ?? import_base.terminalScreen;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
this.config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this._writeLine(`Listing tests:`);
|
||||
const tests = suite.allTests();
|
||||
const files = /* @__PURE__ */ new Set();
|
||||
for (const test of tests) {
|
||||
const [, projectName, , ...titles] = test.titlePath();
|
||||
const location = `${import_path.default.relative(this.config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;
|
||||
const projectTitle = projectName ? `[${projectName}] \u203A ` : "";
|
||||
this._writeLine(` ${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`);
|
||||
files.add(test.location.file);
|
||||
}
|
||||
this._writeLine(`Total: ${tests.length} ${tests.length === 1 ? "test" : "tests"} in ${files.size} ${files.size === 1 ? "file" : "files"}`);
|
||||
}
|
||||
onError(error) {
|
||||
this.screen.stderr.write("\n" + (0, import_base.formatError)(import_base.terminalScreen, error).message + "\n");
|
||||
}
|
||||
_writeLine(line) {
|
||||
this.screen.stdout.write(line + "\n");
|
||||
}
|
||||
}
|
||||
var listModeReporter_default = ListModeReporter;
|
144
node_modules/playwright/lib/reporters/markdown.js
generated
vendored
Normal file
144
node_modules/playwright/lib/reporters/markdown.js
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
"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 markdown_exports = {};
|
||||
__export(markdown_exports, {
|
||||
default: () => markdown_default
|
||||
});
|
||||
module.exports = __toCommonJS(markdown_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
class MarkdownReporter {
|
||||
constructor(options) {
|
||||
this._fatalErrors = [];
|
||||
this._options = options;
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
onBegin(config, suite) {
|
||||
this._config = config;
|
||||
this._suite = suite;
|
||||
}
|
||||
onError(error) {
|
||||
this._fatalErrors.push(error);
|
||||
}
|
||||
async onEnd(result) {
|
||||
const summary = this._generateSummary();
|
||||
const lines = [];
|
||||
if (this._fatalErrors.length)
|
||||
lines.push(`**${this._fatalErrors.length} fatal errors, not part of any test**`);
|
||||
if (summary.unexpected.length) {
|
||||
lines.push(`**${summary.unexpected.length} failed**`);
|
||||
this._printTestList(":x:", summary.unexpected, lines);
|
||||
}
|
||||
if (summary.flaky.length) {
|
||||
lines.push(`<details>`);
|
||||
lines.push(`<summary><b>${summary.flaky.length} flaky</b></summary>`);
|
||||
this._printTestList(":warning:", summary.flaky, lines, " <br/>");
|
||||
lines.push(`</details>`);
|
||||
lines.push(``);
|
||||
}
|
||||
if (summary.interrupted.length) {
|
||||
lines.push(`<details>`);
|
||||
lines.push(`<summary><b>${summary.interrupted.length} interrupted</b></summary>`);
|
||||
this._printTestList(":warning:", summary.interrupted, lines, " <br/>");
|
||||
lines.push(`</details>`);
|
||||
lines.push(``);
|
||||
}
|
||||
const skipped = summary.skipped ? `, ${summary.skipped} skipped` : "";
|
||||
const didNotRun = summary.didNotRun ? `, ${summary.didNotRun} did not run` : "";
|
||||
lines.push(`**${summary.expected} passed${skipped}${didNotRun}**`);
|
||||
lines.push(``);
|
||||
await this.publishReport(lines.join("\n"));
|
||||
}
|
||||
async publishReport(report) {
|
||||
const maybeRelativeFile = this._options.outputFile || "report.md";
|
||||
const reportFile = import_path.default.resolve(this._options.configDir, maybeRelativeFile);
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(reportFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(reportFile, report);
|
||||
}
|
||||
_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;
|
||||
}
|
||||
});
|
||||
return {
|
||||
didNotRun,
|
||||
skipped,
|
||||
expected,
|
||||
interrupted,
|
||||
unexpected,
|
||||
flaky
|
||||
};
|
||||
}
|
||||
_printTestList(prefix, tests, lines, suffix) {
|
||||
for (const test of tests)
|
||||
lines.push(`${prefix} ${formatTestTitle(this._config.rootDir, test)}${suffix || ""}`);
|
||||
lines.push(``);
|
||||
}
|
||||
}
|
||||
function formatTestTitle(rootDir, test) {
|
||||
const [, projectName, , ...titles] = test.titlePath();
|
||||
const relativeTestPath = import_path.default.relative(rootDir, test.location.file);
|
||||
const location = `${relativeTestPath}:${test.location.line}`;
|
||||
const projectTitle = projectName ? `[${projectName}] \u203A ` : "";
|
||||
const testTitle = `${projectTitle}${location} \u203A ${titles.join(" \u203A ")}`;
|
||||
const extraTags = test.tags.filter((t) => !testTitle.includes(t));
|
||||
const formattedTags = extraTags.map((t) => `\`${t}\``).join(" ");
|
||||
return `${testTitle}${extraTags.length ? " " + formattedTags : ""}`;
|
||||
}
|
||||
var markdown_default = MarkdownReporter;
|
533
node_modules/playwright/lib/reporters/merge.js
generated
vendored
Normal file
533
node_modules/playwright/lib/reporters/merge.js
generated
vendored
Normal file
@@ -0,0 +1,533 @@
|
||||
"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 merge_exports = {};
|
||||
__export(merge_exports, {
|
||||
createMergedReport: () => createMergedReport
|
||||
});
|
||||
module.exports = __toCommonJS(merge_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_blob = require("./blob");
|
||||
var import_multiplexer = require("./multiplexer");
|
||||
var import_stringInternPool = require("../isomorphic/stringInternPool");
|
||||
var import_teleReceiver = require("../isomorphic/teleReceiver");
|
||||
var import_reporters = require("../runner/reporters");
|
||||
var import_util = require("../util");
|
||||
async function createMergedReport(config, dir, reporterDescriptions, rootDirOverride) {
|
||||
const reporters = await (0, import_reporters.createReporters)(config, "merge", false, reporterDescriptions);
|
||||
const multiplexer = new import_multiplexer.Multiplexer(reporters);
|
||||
const stringPool = new import_stringInternPool.StringInternPool();
|
||||
let printStatus = () => {
|
||||
};
|
||||
if (!multiplexer.printsToStdio()) {
|
||||
printStatus = printStatusToStdout;
|
||||
printStatus(`merging reports from ${dir}`);
|
||||
}
|
||||
const shardFiles = await sortedShardFiles(dir);
|
||||
if (shardFiles.length === 0)
|
||||
throw new Error(`No report files found in ${dir}`);
|
||||
const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);
|
||||
const pathSeparator = rootDirOverride ? import_path.default.sep : eventData.pathSeparatorFromMetadata ?? import_path.default.sep;
|
||||
const receiver = new import_teleReceiver.TeleReporterReceiver(multiplexer, {
|
||||
mergeProjects: false,
|
||||
mergeTestCases: false,
|
||||
resolvePath: (rootDir, relativePath) => stringPool.internString(rootDir + pathSeparator + relativePath),
|
||||
configOverrides: config.config
|
||||
});
|
||||
printStatus(`processing test events`);
|
||||
const dispatchEvents = async (events) => {
|
||||
for (const event of events) {
|
||||
if (event.method === "onEnd")
|
||||
printStatus(`building final report`);
|
||||
await receiver.dispatch(event);
|
||||
if (event.method === "onEnd")
|
||||
printStatus(`finished building report`);
|
||||
}
|
||||
};
|
||||
await dispatchEvents(eventData.prologue);
|
||||
for (const { reportFile, eventPatchers, metadata } of eventData.reports) {
|
||||
const reportJsonl = await import_fs.default.promises.readFile(reportFile);
|
||||
const events = parseTestEvents(reportJsonl);
|
||||
new import_stringInternPool.JsonStringInternalizer(stringPool).traverse(events);
|
||||
eventPatchers.patchers.push(new AttachmentPathPatcher(dir));
|
||||
if (metadata.name)
|
||||
eventPatchers.patchers.push(new GlobalErrorPatcher(metadata.name));
|
||||
eventPatchers.patchEvents(events);
|
||||
await dispatchEvents(events);
|
||||
}
|
||||
await dispatchEvents(eventData.epilogue);
|
||||
}
|
||||
const commonEventNames = ["onBlobReportMetadata", "onConfigure", "onProject", "onBegin", "onEnd"];
|
||||
const commonEvents = new Set(commonEventNames);
|
||||
const commonEventRegex = new RegExp(`${commonEventNames.join("|")}`);
|
||||
function parseCommonEvents(reportJsonl) {
|
||||
return splitBufferLines(reportJsonl).map((line) => line.toString("utf8")).filter((line) => commonEventRegex.test(line)).map((line) => JSON.parse(line)).filter((event) => commonEvents.has(event.method));
|
||||
}
|
||||
function parseTestEvents(reportJsonl) {
|
||||
return splitBufferLines(reportJsonl).map((line) => line.toString("utf8")).filter((line) => line.length).map((line) => JSON.parse(line)).filter((event) => !commonEvents.has(event.method));
|
||||
}
|
||||
function splitBufferLines(buffer) {
|
||||
const lines = [];
|
||||
let start = 0;
|
||||
while (start < buffer.length) {
|
||||
const end = buffer.indexOf(10, start);
|
||||
if (end === -1) {
|
||||
lines.push(buffer.slice(start));
|
||||
break;
|
||||
}
|
||||
lines.push(buffer.slice(start, end));
|
||||
start = end + 1;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
async function extractAndParseReports(dir, shardFiles, internalizer, printStatus) {
|
||||
const shardEvents = [];
|
||||
await import_fs.default.promises.mkdir(import_path.default.join(dir, "resources"), { recursive: true });
|
||||
const reportNames = new UniqueFileNameGenerator();
|
||||
for (const file of shardFiles) {
|
||||
const absolutePath = import_path.default.join(dir, file);
|
||||
printStatus(`extracting: ${(0, import_util.relativeFilePath)(absolutePath)}`);
|
||||
const zipFile = new import_utils.ZipFile(absolutePath);
|
||||
const entryNames = await zipFile.entries();
|
||||
for (const entryName of entryNames.sort()) {
|
||||
let fileName = import_path.default.join(dir, entryName);
|
||||
const content = await zipFile.read(entryName);
|
||||
if (entryName.endsWith(".jsonl")) {
|
||||
fileName = reportNames.makeUnique(fileName);
|
||||
let parsedEvents = parseCommonEvents(content);
|
||||
internalizer.traverse(parsedEvents);
|
||||
const metadata = findMetadata(parsedEvents, file);
|
||||
parsedEvents = modernizer.modernize(metadata.version, parsedEvents);
|
||||
shardEvents.push({
|
||||
file,
|
||||
localPath: fileName,
|
||||
metadata,
|
||||
parsedEvents
|
||||
});
|
||||
}
|
||||
await import_fs.default.promises.writeFile(fileName, content);
|
||||
}
|
||||
zipFile.close();
|
||||
}
|
||||
return shardEvents;
|
||||
}
|
||||
function findMetadata(events, file) {
|
||||
if (events[0]?.method !== "onBlobReportMetadata")
|
||||
throw new Error(`No metadata event found in ${file}`);
|
||||
const metadata = events[0].params;
|
||||
if (metadata.version > import_blob.currentBlobReportVersion)
|
||||
throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
|
||||
return metadata;
|
||||
}
|
||||
async function mergeEvents(dir, shardReportFiles, stringPool, printStatus, rootDirOverride) {
|
||||
const internalizer = new import_stringInternPool.JsonStringInternalizer(stringPool);
|
||||
const configureEvents = [];
|
||||
const projectEvents = [];
|
||||
const endEvents = [];
|
||||
const blobs = await extractAndParseReports(dir, shardReportFiles, internalizer, printStatus);
|
||||
blobs.sort((a, b) => {
|
||||
const nameA = a.metadata.name ?? "";
|
||||
const nameB = b.metadata.name ?? "";
|
||||
if (nameA !== nameB)
|
||||
return nameA.localeCompare(nameB);
|
||||
const shardA = a.metadata.shard?.current ?? 0;
|
||||
const shardB = b.metadata.shard?.current ?? 0;
|
||||
if (shardA !== shardB)
|
||||
return shardA - shardB;
|
||||
return a.file.localeCompare(b.file);
|
||||
});
|
||||
printStatus(`merging events`);
|
||||
const reports = [];
|
||||
const globalTestIdSet = /* @__PURE__ */ new Set();
|
||||
for (let i = 0; i < blobs.length; ++i) {
|
||||
const { parsedEvents, metadata, localPath } = blobs[i];
|
||||
const eventPatchers = new JsonEventPatchers();
|
||||
eventPatchers.patchers.push(new IdsPatcher(
|
||||
stringPool,
|
||||
metadata.name,
|
||||
String(i),
|
||||
globalTestIdSet
|
||||
));
|
||||
if (rootDirOverride)
|
||||
eventPatchers.patchers.push(new PathSeparatorPatcher(metadata.pathSeparator));
|
||||
eventPatchers.patchEvents(parsedEvents);
|
||||
for (const event of parsedEvents) {
|
||||
if (event.method === "onConfigure")
|
||||
configureEvents.push(event);
|
||||
else if (event.method === "onProject")
|
||||
projectEvents.push(event);
|
||||
else if (event.method === "onEnd")
|
||||
endEvents.push(event);
|
||||
}
|
||||
reports.push({
|
||||
eventPatchers,
|
||||
reportFile: localPath,
|
||||
metadata
|
||||
});
|
||||
}
|
||||
return {
|
||||
prologue: [
|
||||
mergeConfigureEvents(configureEvents, rootDirOverride),
|
||||
...projectEvents,
|
||||
{ method: "onBegin", params: void 0 }
|
||||
],
|
||||
reports,
|
||||
epilogue: [
|
||||
mergeEndEvents(endEvents),
|
||||
{ method: "onExit", params: void 0 }
|
||||
],
|
||||
pathSeparatorFromMetadata: blobs[0]?.metadata.pathSeparator
|
||||
};
|
||||
}
|
||||
function mergeConfigureEvents(configureEvents, rootDirOverride) {
|
||||
if (!configureEvents.length)
|
||||
throw new Error("No configure events found");
|
||||
let config = {
|
||||
configFile: void 0,
|
||||
globalTimeout: 0,
|
||||
maxFailures: 0,
|
||||
metadata: {},
|
||||
rootDir: "",
|
||||
version: "",
|
||||
workers: 0
|
||||
};
|
||||
for (const event of configureEvents)
|
||||
config = mergeConfigs(config, event.params.config);
|
||||
if (rootDirOverride) {
|
||||
config.rootDir = rootDirOverride;
|
||||
} else {
|
||||
const rootDirs = new Set(configureEvents.map((e) => e.params.config.rootDir));
|
||||
if (rootDirs.size > 1) {
|
||||
throw new Error([
|
||||
`Blob reports being merged were recorded with different test directories, and`,
|
||||
`merging cannot proceed. This may happen if you are merging reports from`,
|
||||
`machines with different environments, like different operating systems or`,
|
||||
`if the tests ran with different playwright configs.`,
|
||||
``,
|
||||
`You can force merge by specifying a merge config file with "-c" option. If`,
|
||||
`you'd like all test paths to be correct, make sure 'testDir' in the merge config`,
|
||||
`file points to the actual tests location.`,
|
||||
``,
|
||||
`Found directories:`,
|
||||
...rootDirs
|
||||
].join("\n"));
|
||||
}
|
||||
}
|
||||
return {
|
||||
method: "onConfigure",
|
||||
params: {
|
||||
config
|
||||
}
|
||||
};
|
||||
}
|
||||
function mergeConfigs(to, from) {
|
||||
return {
|
||||
...to,
|
||||
...from,
|
||||
metadata: {
|
||||
...to.metadata,
|
||||
...from.metadata,
|
||||
actualWorkers: (to.metadata.actualWorkers || 0) + (from.metadata.actualWorkers || 0)
|
||||
},
|
||||
workers: to.workers + from.workers
|
||||
};
|
||||
}
|
||||
function mergeEndEvents(endEvents) {
|
||||
let startTime = endEvents.length ? 1e13 : Date.now();
|
||||
let status = "passed";
|
||||
let duration = 0;
|
||||
for (const event of endEvents) {
|
||||
const shardResult = event.params.result;
|
||||
if (shardResult.status === "failed")
|
||||
status = "failed";
|
||||
else if (shardResult.status === "timedout" && status !== "failed")
|
||||
status = "timedout";
|
||||
else if (shardResult.status === "interrupted" && status !== "failed" && status !== "timedout")
|
||||
status = "interrupted";
|
||||
startTime = Math.min(startTime, shardResult.startTime);
|
||||
duration = Math.max(duration, shardResult.duration);
|
||||
}
|
||||
const result = {
|
||||
status,
|
||||
startTime,
|
||||
duration
|
||||
};
|
||||
return {
|
||||
method: "onEnd",
|
||||
params: {
|
||||
result
|
||||
}
|
||||
};
|
||||
}
|
||||
async function sortedShardFiles(dir) {
|
||||
const files = await import_fs.default.promises.readdir(dir);
|
||||
return files.filter((file) => file.endsWith(".zip")).sort();
|
||||
}
|
||||
function printStatusToStdout(message) {
|
||||
process.stdout.write(`${message}
|
||||
`);
|
||||
}
|
||||
class UniqueFileNameGenerator {
|
||||
constructor() {
|
||||
this._usedNames = /* @__PURE__ */ new Set();
|
||||
}
|
||||
makeUnique(name) {
|
||||
if (!this._usedNames.has(name)) {
|
||||
this._usedNames.add(name);
|
||||
return name;
|
||||
}
|
||||
const extension = import_path.default.extname(name);
|
||||
name = name.substring(0, name.length - extension.length);
|
||||
let index = 0;
|
||||
while (true) {
|
||||
const candidate = `${name}-${++index}${extension}`;
|
||||
if (!this._usedNames.has(candidate)) {
|
||||
this._usedNames.add(candidate);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class IdsPatcher {
|
||||
constructor(stringPool, botName, salt, globalTestIdSet) {
|
||||
this._stringPool = stringPool;
|
||||
this._botName = botName;
|
||||
this._salt = salt;
|
||||
this._testIdsMap = /* @__PURE__ */ new Map();
|
||||
this._globalTestIdSet = globalTestIdSet;
|
||||
}
|
||||
patchEvent(event) {
|
||||
const { method, params } = event;
|
||||
switch (method) {
|
||||
case "onProject":
|
||||
this._onProject(params.project);
|
||||
return;
|
||||
case "onAttach":
|
||||
case "onTestBegin":
|
||||
case "onStepBegin":
|
||||
case "onStepEnd":
|
||||
case "onStdIO":
|
||||
params.testId = params.testId ? this._mapTestId(params.testId) : void 0;
|
||||
return;
|
||||
case "onTestEnd":
|
||||
params.test.testId = this._mapTestId(params.test.testId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_onProject(project) {
|
||||
project.metadata ??= {};
|
||||
project.suites.forEach((suite) => this._updateTestIds(suite));
|
||||
}
|
||||
_updateTestIds(suite) {
|
||||
suite.entries.forEach((entry) => {
|
||||
if ("testId" in entry)
|
||||
this._updateTestId(entry);
|
||||
else
|
||||
this._updateTestIds(entry);
|
||||
});
|
||||
}
|
||||
_updateTestId(test) {
|
||||
test.testId = this._mapTestId(test.testId);
|
||||
if (this._botName) {
|
||||
test.tags = test.tags || [];
|
||||
test.tags.unshift("@" + this._botName);
|
||||
}
|
||||
}
|
||||
_mapTestId(testId) {
|
||||
const t1 = this._stringPool.internString(testId);
|
||||
if (this._testIdsMap.has(t1))
|
||||
return this._testIdsMap.get(t1);
|
||||
if (this._globalTestIdSet.has(t1)) {
|
||||
const t2 = this._stringPool.internString(testId + this._salt);
|
||||
this._globalTestIdSet.add(t2);
|
||||
this._testIdsMap.set(t1, t2);
|
||||
return t2;
|
||||
}
|
||||
this._globalTestIdSet.add(t1);
|
||||
this._testIdsMap.set(t1, t1);
|
||||
return t1;
|
||||
}
|
||||
}
|
||||
class AttachmentPathPatcher {
|
||||
constructor(_resourceDir) {
|
||||
this._resourceDir = _resourceDir;
|
||||
}
|
||||
patchEvent(event) {
|
||||
if (event.method === "onAttach")
|
||||
this._patchAttachments(event.params.attachments);
|
||||
else if (event.method === "onTestEnd")
|
||||
this._patchAttachments(event.params.result.attachments ?? []);
|
||||
}
|
||||
_patchAttachments(attachments) {
|
||||
for (const attachment of attachments) {
|
||||
if (!attachment.path)
|
||||
continue;
|
||||
attachment.path = import_path.default.join(this._resourceDir, attachment.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
class PathSeparatorPatcher {
|
||||
constructor(from) {
|
||||
this._from = from ?? (import_path.default.sep === "/" ? "\\" : "/");
|
||||
this._to = import_path.default.sep;
|
||||
}
|
||||
patchEvent(jsonEvent) {
|
||||
if (this._from === this._to)
|
||||
return;
|
||||
if (jsonEvent.method === "onProject") {
|
||||
this._updateProject(jsonEvent.params.project);
|
||||
return;
|
||||
}
|
||||
if (jsonEvent.method === "onTestEnd") {
|
||||
const test = jsonEvent.params.test;
|
||||
test.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
|
||||
const testResult = jsonEvent.params.result;
|
||||
testResult.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
|
||||
testResult.errors.forEach((error) => this._updateErrorLocations(error));
|
||||
(testResult.attachments ?? []).forEach((attachment) => {
|
||||
if (attachment.path)
|
||||
attachment.path = this._updatePath(attachment.path);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (jsonEvent.method === "onStepBegin") {
|
||||
const step = jsonEvent.params.step;
|
||||
this._updateLocation(step.location);
|
||||
return;
|
||||
}
|
||||
if (jsonEvent.method === "onStepEnd") {
|
||||
const step = jsonEvent.params.step;
|
||||
this._updateErrorLocations(step.error);
|
||||
step.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
|
||||
return;
|
||||
}
|
||||
if (jsonEvent.method === "onAttach") {
|
||||
const attach = jsonEvent.params;
|
||||
attach.attachments.forEach((attachment) => {
|
||||
if (attachment.path)
|
||||
attachment.path = this._updatePath(attachment.path);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
_updateProject(project) {
|
||||
project.outputDir = this._updatePath(project.outputDir);
|
||||
project.testDir = this._updatePath(project.testDir);
|
||||
project.snapshotDir = this._updatePath(project.snapshotDir);
|
||||
project.suites.forEach((suite) => this._updateSuite(suite, true));
|
||||
}
|
||||
_updateSuite(suite, isFileSuite = false) {
|
||||
this._updateLocation(suite.location);
|
||||
if (isFileSuite)
|
||||
suite.title = this._updatePath(suite.title);
|
||||
for (const entry of suite.entries) {
|
||||
if ("testId" in entry) {
|
||||
this._updateLocation(entry.location);
|
||||
entry.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
|
||||
} else {
|
||||
this._updateSuite(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
_updateErrorLocations(error) {
|
||||
while (error) {
|
||||
this._updateLocation(error.location);
|
||||
error = error.cause;
|
||||
}
|
||||
}
|
||||
_updateAnnotationLocation(annotation) {
|
||||
this._updateLocation(annotation.location);
|
||||
}
|
||||
_updateLocation(location) {
|
||||
if (location)
|
||||
location.file = this._updatePath(location.file);
|
||||
}
|
||||
_updatePath(text) {
|
||||
return text.split(this._from).join(this._to);
|
||||
}
|
||||
}
|
||||
class GlobalErrorPatcher {
|
||||
constructor(botName) {
|
||||
this._prefix = `(${botName}) `;
|
||||
}
|
||||
patchEvent(event) {
|
||||
if (event.method !== "onError")
|
||||
return;
|
||||
const error = event.params.error;
|
||||
if (error.message !== void 0)
|
||||
error.message = this._prefix + error.message;
|
||||
if (error.stack !== void 0)
|
||||
error.stack = this._prefix + error.stack;
|
||||
}
|
||||
}
|
||||
class JsonEventPatchers {
|
||||
constructor() {
|
||||
this.patchers = [];
|
||||
}
|
||||
patchEvents(events) {
|
||||
for (const event of events) {
|
||||
for (const patcher of this.patchers)
|
||||
patcher.patchEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
class BlobModernizer {
|
||||
modernize(fromVersion, events) {
|
||||
const result = [];
|
||||
for (const event of events)
|
||||
result.push(...this._modernize(fromVersion, event));
|
||||
return result;
|
||||
}
|
||||
_modernize(fromVersion, event) {
|
||||
let events = [event];
|
||||
for (let version = fromVersion; version < import_blob.currentBlobReportVersion; ++version)
|
||||
events = this[`_modernize_${version}_to_${version + 1}`].call(this, events);
|
||||
return events;
|
||||
}
|
||||
_modernize_1_to_2(events) {
|
||||
return events.map((event) => {
|
||||
if (event.method === "onProject") {
|
||||
const modernizeSuite = (suite) => {
|
||||
const newSuites = suite.suites.map(modernizeSuite);
|
||||
const { suites, tests, ...remainder } = suite;
|
||||
return { entries: [...newSuites, ...tests], ...remainder };
|
||||
};
|
||||
const project = event.params.project;
|
||||
project.suites = project.suites.map(modernizeSuite);
|
||||
}
|
||||
return event;
|
||||
});
|
||||
}
|
||||
}
|
||||
const modernizer = new BlobModernizer();
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createMergedReport
|
||||
});
|
104
node_modules/playwright/lib/reporters/multiplexer.js
generated
vendored
Normal file
104
node_modules/playwright/lib/reporters/multiplexer.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var multiplexer_exports = {};
|
||||
__export(multiplexer_exports, {
|
||||
Multiplexer: () => Multiplexer
|
||||
});
|
||||
module.exports = __toCommonJS(multiplexer_exports);
|
||||
class Multiplexer {
|
||||
constructor(reporters) {
|
||||
this._reporters = reporters;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onConfigure?.(config));
|
||||
}
|
||||
onBegin(suite) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onBegin?.(suite));
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onTestBegin?.(test, result));
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStdOut?.(chunk, test, result));
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStdErr?.(chunk, test, result));
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onTestEnd?.(test, result));
|
||||
}
|
||||
async onEnd(result) {
|
||||
for (const reporter of this._reporters) {
|
||||
const outResult = await wrapAsync(() => reporter.onEnd?.(result));
|
||||
if (outResult?.status)
|
||||
result.status = outResult.status;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async onExit() {
|
||||
for (const reporter of this._reporters)
|
||||
await wrapAsync(() => reporter.onExit?.());
|
||||
}
|
||||
onError(error) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onError?.(error));
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStepBegin?.(test, result, step));
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStepEnd?.(test, result, step));
|
||||
}
|
||||
printsToStdio() {
|
||||
return this._reporters.some((r) => {
|
||||
let prints = false;
|
||||
wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true);
|
||||
return prints;
|
||||
});
|
||||
}
|
||||
}
|
||||
async function wrapAsync(callback) {
|
||||
try {
|
||||
return await callback();
|
||||
} catch (e) {
|
||||
console.error("Error in reporter", e);
|
||||
}
|
||||
}
|
||||
function wrap(callback) {
|
||||
try {
|
||||
callback();
|
||||
} catch (e) {
|
||||
console.error("Error in reporter", e);
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Multiplexer
|
||||
});
|
102
node_modules/playwright/lib/reporters/reporterV2.js
generated
vendored
Normal file
102
node_modules/playwright/lib/reporters/reporterV2.js
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var reporterV2_exports = {};
|
||||
__export(reporterV2_exports, {
|
||||
wrapReporterAsV2: () => wrapReporterAsV2
|
||||
});
|
||||
module.exports = __toCommonJS(reporterV2_exports);
|
||||
function wrapReporterAsV2(reporter) {
|
||||
try {
|
||||
if ("version" in reporter && reporter.version() === "v2")
|
||||
return reporter;
|
||||
} catch (e) {
|
||||
}
|
||||
return new ReporterV2Wrapper(reporter);
|
||||
}
|
||||
class ReporterV2Wrapper {
|
||||
constructor(reporter) {
|
||||
this._deferred = [];
|
||||
this._reporter = reporter;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
this._config = config;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this._reporter.onBegin?.(this._config, suite);
|
||||
const deferred = this._deferred;
|
||||
this._deferred = null;
|
||||
for (const item of deferred) {
|
||||
if (item.error)
|
||||
this.onError(item.error);
|
||||
if (item.stdout)
|
||||
this.onStdOut(item.stdout.chunk, item.stdout.test, item.stdout.result);
|
||||
if (item.stderr)
|
||||
this.onStdErr(item.stderr.chunk, item.stderr.test, item.stderr.result);
|
||||
}
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
if (this._deferred) {
|
||||
this._deferred.push({ stdout: { chunk, test, result } });
|
||||
return;
|
||||
}
|
||||
this._reporter.onStdOut?.(chunk, test, result);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
if (this._deferred) {
|
||||
this._deferred.push({ stderr: { chunk, test, result } });
|
||||
return;
|
||||
}
|
||||
this._reporter.onStdErr?.(chunk, test, result);
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
}
|
||||
async onEnd(result) {
|
||||
return await this._reporter.onEnd?.(result);
|
||||
}
|
||||
async onExit() {
|
||||
await this._reporter.onExit?.();
|
||||
}
|
||||
onError(error) {
|
||||
if (this._deferred) {
|
||||
this._deferred.push({ error });
|
||||
return;
|
||||
}
|
||||
this._reporter.onError?.(error);
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
this._reporter.onStepBegin?.(test, result, step);
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
this._reporter.onStepEnd?.(test, result, step);
|
||||
}
|
||||
printsToStdio() {
|
||||
return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
wrapReporterAsV2
|
||||
});
|
295
node_modules/playwright/lib/reporters/teleEmitter.js
generated
vendored
Normal file
295
node_modules/playwright/lib/reporters/teleEmitter.js
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
"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 teleEmitter_exports = {};
|
||||
__export(teleEmitter_exports, {
|
||||
TeleReporterEmitter: () => TeleReporterEmitter
|
||||
});
|
||||
module.exports = __toCommonJS(teleEmitter_exports);
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_teleReceiver = require("../isomorphic/teleReceiver");
|
||||
class TeleReporterEmitter {
|
||||
constructor(messageSink, options = {}) {
|
||||
this._resultKnownAttachmentCounts = /* @__PURE__ */ new Map();
|
||||
// In case there is blob reporter and UI mode, make sure one does override
|
||||
// the id assigned by the other.
|
||||
this._idSymbol = Symbol("id");
|
||||
this._messageSink = messageSink;
|
||||
this._emitterOptions = options;
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
onConfigure(config) {
|
||||
this._rootDir = config.rootDir;
|
||||
this._messageSink({ method: "onConfigure", params: { config: this._serializeConfig(config) } });
|
||||
}
|
||||
onBegin(suite) {
|
||||
const projects = suite.suites.map((projectSuite) => this._serializeProject(projectSuite));
|
||||
for (const project of projects)
|
||||
this._messageSink({ method: "onProject", params: { project } });
|
||||
this._messageSink({ method: "onBegin", params: void 0 });
|
||||
}
|
||||
onTestBegin(test, result) {
|
||||
result[this._idSymbol] = (0, import_utils.createGuid)();
|
||||
this._messageSink({
|
||||
method: "onTestBegin",
|
||||
params: {
|
||||
testId: test.id,
|
||||
result: this._serializeResultStart(result)
|
||||
}
|
||||
});
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
const testEnd = {
|
||||
testId: test.id,
|
||||
expectedStatus: test.expectedStatus,
|
||||
timeout: test.timeout,
|
||||
annotations: []
|
||||
};
|
||||
this._sendNewAttachments(result, test.id);
|
||||
this._messageSink({
|
||||
method: "onTestEnd",
|
||||
params: {
|
||||
test: testEnd,
|
||||
result: this._serializeResultEnd(result)
|
||||
}
|
||||
});
|
||||
this._resultKnownAttachmentCounts.delete(result[this._idSymbol]);
|
||||
}
|
||||
onStepBegin(test, result, step) {
|
||||
step[this._idSymbol] = (0, import_utils.createGuid)();
|
||||
this._messageSink({
|
||||
method: "onStepBegin",
|
||||
params: {
|
||||
testId: test.id,
|
||||
resultId: result[this._idSymbol],
|
||||
step: this._serializeStepStart(step)
|
||||
}
|
||||
});
|
||||
}
|
||||
onStepEnd(test, result, step) {
|
||||
const resultId = result[this._idSymbol];
|
||||
this._sendNewAttachments(result, test.id);
|
||||
this._messageSink({
|
||||
method: "onStepEnd",
|
||||
params: {
|
||||
testId: test.id,
|
||||
resultId,
|
||||
step: this._serializeStepEnd(step, result)
|
||||
}
|
||||
});
|
||||
}
|
||||
onError(error) {
|
||||
this._messageSink({
|
||||
method: "onError",
|
||||
params: { error }
|
||||
});
|
||||
}
|
||||
onStdOut(chunk, test, result) {
|
||||
this._onStdIO("stdout", chunk, test, result);
|
||||
}
|
||||
onStdErr(chunk, test, result) {
|
||||
this._onStdIO("stderr", chunk, test, result);
|
||||
}
|
||||
_onStdIO(type, chunk, test, result) {
|
||||
if (this._emitterOptions.omitOutput)
|
||||
return;
|
||||
const isBase64 = typeof chunk !== "string";
|
||||
const data = isBase64 ? chunk.toString("base64") : chunk;
|
||||
this._messageSink({
|
||||
method: "onStdIO",
|
||||
params: { testId: test?.id, resultId: result ? result[this._idSymbol] : void 0, type, data, isBase64 }
|
||||
});
|
||||
}
|
||||
async onEnd(result) {
|
||||
const resultPayload = {
|
||||
status: result.status,
|
||||
startTime: result.startTime.getTime(),
|
||||
duration: result.duration
|
||||
};
|
||||
this._messageSink({
|
||||
method: "onEnd",
|
||||
params: {
|
||||
result: resultPayload
|
||||
}
|
||||
});
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
_serializeConfig(config) {
|
||||
return {
|
||||
configFile: this._relativePath(config.configFile),
|
||||
globalTimeout: config.globalTimeout,
|
||||
maxFailures: config.maxFailures,
|
||||
metadata: config.metadata,
|
||||
rootDir: config.rootDir,
|
||||
version: config.version,
|
||||
workers: config.workers
|
||||
};
|
||||
}
|
||||
_serializeProject(suite) {
|
||||
const project = suite.project();
|
||||
const report = {
|
||||
metadata: project.metadata,
|
||||
name: project.name,
|
||||
outputDir: this._relativePath(project.outputDir),
|
||||
repeatEach: project.repeatEach,
|
||||
retries: project.retries,
|
||||
testDir: this._relativePath(project.testDir),
|
||||
testIgnore: (0, import_teleReceiver.serializeRegexPatterns)(project.testIgnore),
|
||||
testMatch: (0, import_teleReceiver.serializeRegexPatterns)(project.testMatch),
|
||||
timeout: project.timeout,
|
||||
suites: suite.suites.map((fileSuite) => {
|
||||
return this._serializeSuite(fileSuite);
|
||||
}),
|
||||
grep: (0, import_teleReceiver.serializeRegexPatterns)(project.grep),
|
||||
grepInvert: (0, import_teleReceiver.serializeRegexPatterns)(project.grepInvert || []),
|
||||
dependencies: project.dependencies,
|
||||
snapshotDir: this._relativePath(project.snapshotDir),
|
||||
teardown: project.teardown,
|
||||
use: this._serializeProjectUseOptions(project.use)
|
||||
};
|
||||
return report;
|
||||
}
|
||||
_serializeProjectUseOptions(use) {
|
||||
return {
|
||||
testIdAttribute: use.testIdAttribute
|
||||
};
|
||||
}
|
||||
_serializeSuite(suite) {
|
||||
const result = {
|
||||
title: suite.title,
|
||||
location: this._relativeLocation(suite.location),
|
||||
entries: suite.entries().map((e) => {
|
||||
if (e.type === "test")
|
||||
return this._serializeTest(e);
|
||||
return this._serializeSuite(e);
|
||||
})
|
||||
};
|
||||
return result;
|
||||
}
|
||||
_serializeTest(test) {
|
||||
return {
|
||||
testId: test.id,
|
||||
title: test.title,
|
||||
location: this._relativeLocation(test.location),
|
||||
retries: test.retries,
|
||||
tags: test.tags,
|
||||
repeatEachIndex: test.repeatEachIndex,
|
||||
annotations: this._relativeAnnotationLocations(test.annotations)
|
||||
};
|
||||
}
|
||||
_serializeResultStart(result) {
|
||||
return {
|
||||
id: result[this._idSymbol],
|
||||
retry: result.retry,
|
||||
workerIndex: result.workerIndex,
|
||||
parallelIndex: result.parallelIndex,
|
||||
startTime: +result.startTime
|
||||
};
|
||||
}
|
||||
_serializeResultEnd(result) {
|
||||
return {
|
||||
id: result[this._idSymbol],
|
||||
duration: result.duration,
|
||||
status: result.status,
|
||||
errors: result.errors,
|
||||
annotations: result.annotations?.length ? this._relativeAnnotationLocations(result.annotations) : void 0
|
||||
};
|
||||
}
|
||||
_sendNewAttachments(result, testId) {
|
||||
const resultId = result[this._idSymbol];
|
||||
const knownAttachmentCount = this._resultKnownAttachmentCounts.get(resultId) ?? 0;
|
||||
if (result.attachments.length > knownAttachmentCount) {
|
||||
this._messageSink({
|
||||
method: "onAttach",
|
||||
params: {
|
||||
testId,
|
||||
resultId,
|
||||
attachments: this._serializeAttachments(result.attachments.slice(knownAttachmentCount))
|
||||
}
|
||||
});
|
||||
}
|
||||
this._resultKnownAttachmentCounts.set(resultId, result.attachments.length);
|
||||
}
|
||||
_serializeAttachments(attachments) {
|
||||
return attachments.map((a) => {
|
||||
const { body, ...rest } = a;
|
||||
return {
|
||||
...rest,
|
||||
// There is no Buffer in the browser, so there is no point in sending the data there.
|
||||
base64: body && !this._emitterOptions.omitBuffers ? body.toString("base64") : void 0
|
||||
};
|
||||
});
|
||||
}
|
||||
_serializeStepStart(step) {
|
||||
return {
|
||||
id: step[this._idSymbol],
|
||||
parentStepId: step.parent?.[this._idSymbol],
|
||||
title: step.title,
|
||||
category: step.category,
|
||||
startTime: +step.startTime,
|
||||
location: this._relativeLocation(step.location)
|
||||
};
|
||||
}
|
||||
_serializeStepEnd(step, result) {
|
||||
return {
|
||||
id: step[this._idSymbol],
|
||||
duration: step.duration,
|
||||
error: step.error,
|
||||
attachments: step.attachments.length ? step.attachments.map((a) => result.attachments.indexOf(a)) : void 0,
|
||||
annotations: step.annotations.length ? this._relativeAnnotationLocations(step.annotations) : void 0
|
||||
};
|
||||
}
|
||||
_relativeAnnotationLocations(annotations) {
|
||||
return annotations.map((annotation) => ({
|
||||
...annotation,
|
||||
location: annotation.location ? this._relativeLocation(annotation.location) : void 0
|
||||
}));
|
||||
}
|
||||
_relativeLocation(location) {
|
||||
if (!location)
|
||||
return location;
|
||||
return {
|
||||
...location,
|
||||
file: this._relativePath(location.file)
|
||||
};
|
||||
}
|
||||
_relativePath(absolutePath) {
|
||||
if (!absolutePath)
|
||||
return absolutePath;
|
||||
return import_path.default.relative(this._rootDir, absolutePath);
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TeleReporterEmitter
|
||||
});
|
16
node_modules/playwright/lib/reporters/versions/blobV1.js
generated
vendored
Normal file
16
node_modules/playwright/lib/reporters/versions/blobV1.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var blobV1_exports = {};
|
||||
module.exports = __toCommonJS(blobV1_exports);
|
Reference in New Issue
Block a user