@stablyai/internal-playwright 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +168 -0
- package/ThirdPartyNotices.txt +6277 -0
- package/cli.js +19 -0
- package/index.d.ts +17 -0
- package/index.js +17 -0
- package/index.mjs +18 -0
- package/jsx-runtime.js +42 -0
- package/jsx-runtime.mjs +21 -0
- package/lib/agents/generateAgents.js +265 -0
- package/lib/agents/generator.md +102 -0
- package/lib/agents/healer.md +78 -0
- package/lib/agents/planner.md +135 -0
- package/lib/cli.js +274 -0
- package/lib/common/config.js +274 -0
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js +377 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +102 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +52 -0
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +389 -0
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js +302 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js +58 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js +60 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js +85 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +104 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js +140 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js +321 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js +100 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js +310 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/fsWatcher.js +67 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +696 -0
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js +42 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js +77 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js +30 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js +69 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +507 -0
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +137 -0
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js +211 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js +16 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +334 -0
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js +16 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js +59 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +325 -0
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +87 -0
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +366 -0
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +73 -0
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +99 -0
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +102 -0
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +159 -0
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +359 -0
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +99 -0
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js +16 -0
- package/lib/mcp/browser/backend.js +93 -0
- package/lib/mcp/browser/backend.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +296 -0
- package/lib/mcp/browser/browserServerBackend.js +76 -0
- package/lib/mcp/browser/codegen.js +66 -0
- package/lib/mcp/browser/config.js +385 -0
- package/lib/mcp/browser/context.js +287 -0
- package/lib/mcp/browser/response.js +228 -0
- package/lib/mcp/browser/sessionLog.js +160 -0
- package/lib/mcp/browser/tab.js +277 -0
- package/lib/mcp/browser/tool.js +30 -0
- package/lib/mcp/browser/tool.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +63 -0
- package/lib/mcp/browser/tools/console.js +44 -0
- package/lib/mcp/browser/tools/dialogs.js +60 -0
- package/lib/mcp/browser/tools/evaluate.js +70 -0
- package/lib/mcp/browser/tools/files.js +58 -0
- package/lib/mcp/browser/tools/form.js +74 -0
- package/lib/mcp/browser/tools/install.js +69 -0
- package/lib/mcp/browser/tools/keyboard.js +85 -0
- package/lib/mcp/browser/tools/mouse.js +107 -0
- package/lib/mcp/browser/tools/navigate.js +62 -0
- package/lib/mcp/browser/tools/network.js +54 -0
- package/lib/mcp/browser/tools/pdf.js +59 -0
- package/lib/mcp/browser/tools/screenshot.js +88 -0
- package/lib/mcp/browser/tools/snapshot.js +182 -0
- package/lib/mcp/browser/tools/tabs.js +67 -0
- package/lib/mcp/browser/tools/tool.js +49 -0
- package/lib/mcp/browser/tools/tracing.js +74 -0
- package/lib/mcp/browser/tools/utils.js +100 -0
- package/lib/mcp/browser/tools/verify.js +154 -0
- package/lib/mcp/browser/tools/wait.js +63 -0
- package/lib/mcp/browser/tools.js +80 -0
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js +44 -0
- package/lib/mcp/config.d.js +16 -0
- package/lib/mcp/extension/cdpRelay.js +351 -0
- package/lib/mcp/extension/extensionContextFactory.js +75 -0
- package/lib/mcp/extension/protocol.js +28 -0
- package/lib/mcp/index.js +61 -0
- package/lib/mcp/log.js +35 -0
- package/lib/mcp/program.js +96 -0
- package/lib/mcp/sdk/bundle.js +81 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/call.js +49 -0
- package/lib/mcp/sdk/call.js.map +7 -0
- package/lib/mcp/sdk/exports.js +32 -0
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +187 -0
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js +71 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/mdb.js +206 -0
- package/lib/mcp/sdk/mdb.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js +128 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +189 -0
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +51 -0
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/test/backend.js +67 -0
- package/lib/mcp/test/backend.js.map +7 -0
- package/lib/mcp/test/browserBackend.js +98 -0
- package/lib/mcp/test/context.js +48 -0
- package/lib/mcp/test/context.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +122 -0
- package/lib/mcp/test/plannerTools.js +46 -0
- package/lib/mcp/test/seed.js +72 -0
- package/lib/mcp/test/streams.js +39 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +97 -0
- package/lib/mcp/test/testContext.js +176 -0
- package/lib/mcp/test/testTool.js +30 -0
- package/lib/mcp/test/testTools.js +115 -0
- package/lib/mcp/test/tool.js +30 -0
- package/lib/mcp/test/tool.js.map +7 -0
- package/lib/mcp/test/tools.js +150 -0
- package/lib/mcp/test/tools.js.map +7 -0
- package/lib/mcp/vscode/host.js +187 -0
- package/lib/mcp/vscode/main.js +77 -0
- package/lib/mcpBundleImpl.js +41 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js +198 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js +28 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js +209 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +412 -0
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +609 -0
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +135 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +82 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js +32 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js +128 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +644 -0
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +130 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js +254 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js +230 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +113 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +235 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js +69 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js +144 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +535 -0
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +104 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js +102 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/teleEmitter.js +297 -0
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js +16 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +491 -0
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js +72 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js +77 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +333 -0
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js +89 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +161 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +241 -0
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js +189 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +137 -0
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/runner.js +173 -0
- package/lib/runner/sigIntWatcher.js +96 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/taskRunner.js +127 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js +410 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +117 -0
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +390 -0
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +264 -0
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiMode.js +271 -0
- package/lib/runner/uiModeReporter.js +30 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js +72 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +395 -0
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +95 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/store.js +98 -0
- package/lib/third_party/pirates.js +62 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js +103 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +43 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +461 -0
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +272 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +104 -0
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/esmUtils.js +32 -0
- package/lib/transform/portTransport.js +67 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +293 -0
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +403 -0
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +43 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +100 -0
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +258 -0
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/stepContext.js +34 -0
- package/lib/worker/testInfo.js +508 -0
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js +344 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js +174 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js +31 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +520 -0
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +74 -0
- package/test.d.ts +18 -0
- package/test.js +24 -0
- package/test.mjs +33 -0
- package/types/test.d.ts +10217 -0
- package/types/testReporter.d.ts +816 -0
@@ -0,0 +1,644 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __create = Object.create;
|
3
|
+
var __defProp = Object.defineProperty;
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
8
|
+
var __export = (target, all) => {
|
9
|
+
for (var name in all)
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
11
|
+
};
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
14
|
+
for (let key of __getOwnPropNames(from))
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
17
|
+
}
|
18
|
+
return to;
|
19
|
+
};
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
26
|
+
mod
|
27
|
+
));
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
29
|
+
var html_exports = {};
|
30
|
+
__export(html_exports, {
|
31
|
+
default: () => html_default,
|
32
|
+
showHTMLReport: () => showHTMLReport,
|
33
|
+
startHtmlReportServer: () => startHtmlReportServer
|
34
|
+
});
|
35
|
+
module.exports = __toCommonJS(html_exports);
|
36
|
+
var import_fs = __toESM(require("fs"));
|
37
|
+
var import_path = __toESM(require("path"));
|
38
|
+
var import_stream = require("stream");
|
39
|
+
var import_utils = require("playwright-core/lib/utils");
|
40
|
+
var import_utils2 = require("playwright-core/lib/utils");
|
41
|
+
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
42
|
+
var import_utilsBundle2 = require("playwright-core/lib/utilsBundle");
|
43
|
+
var import_zipBundle = require("playwright-core/lib/zipBundle");
|
44
|
+
var import_base = require("./base");
|
45
|
+
var import_babelBundle = require("../transform/babelBundle");
|
46
|
+
var import_util = require("../util");
|
47
|
+
const htmlReportOptions = ["always", "never", "on-failure"];
|
48
|
+
const isHtmlReportOption = (type) => {
|
49
|
+
return htmlReportOptions.includes(type);
|
50
|
+
};
|
51
|
+
class HtmlReporter {
|
52
|
+
constructor(options) {
|
53
|
+
this._topLevelErrors = [];
|
54
|
+
this._options = options;
|
55
|
+
}
|
56
|
+
version() {
|
57
|
+
return "v2";
|
58
|
+
}
|
59
|
+
printsToStdio() {
|
60
|
+
return false;
|
61
|
+
}
|
62
|
+
onConfigure(config) {
|
63
|
+
this.config = config;
|
64
|
+
}
|
65
|
+
onBegin(suite) {
|
66
|
+
const { outputFolder, open: open2, attachmentsBaseURL, host, port } = this._resolveOptions();
|
67
|
+
this._outputFolder = outputFolder;
|
68
|
+
this._open = open2;
|
69
|
+
this._host = host;
|
70
|
+
this._port = port;
|
71
|
+
this._attachmentsBaseURL = attachmentsBaseURL;
|
72
|
+
const reportedWarnings = /* @__PURE__ */ new Set();
|
73
|
+
for (const project of this.config.projects) {
|
74
|
+
if (this._isSubdirectory(outputFolder, project.outputDir) || this._isSubdirectory(project.outputDir, outputFolder)) {
|
75
|
+
const key = outputFolder + "|" + project.outputDir;
|
76
|
+
if (reportedWarnings.has(key))
|
77
|
+
continue;
|
78
|
+
reportedWarnings.add(key);
|
79
|
+
writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
|
80
|
+
writeLine(`
|
81
|
+
html reporter folder: ${import_utils2.colors.bold(outputFolder)}
|
82
|
+
test results folder: ${import_utils2.colors.bold(project.outputDir)}`);
|
83
|
+
writeLine("");
|
84
|
+
writeLine(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
|
85
|
+
`);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
this.suite = suite;
|
89
|
+
}
|
90
|
+
_resolveOptions() {
|
91
|
+
const outputFolder = reportFolderFromEnv() ?? (0, import_util.resolveReporterOutputPath)("playwright-report", this._options.configDir, this._options.outputFolder);
|
92
|
+
return {
|
93
|
+
outputFolder,
|
94
|
+
open: getHtmlReportOptionProcessEnv() || this._options.open || "on-failure",
|
95
|
+
attachmentsBaseURL: process.env.PLAYWRIGHT_HTML_ATTACHMENTS_BASE_URL || this._options.attachmentsBaseURL || "data/",
|
96
|
+
host: process.env.PLAYWRIGHT_HTML_HOST || this._options.host,
|
97
|
+
port: process.env.PLAYWRIGHT_HTML_PORT ? +process.env.PLAYWRIGHT_HTML_PORT : this._options.port
|
98
|
+
};
|
99
|
+
}
|
100
|
+
_isSubdirectory(parentDir, dir) {
|
101
|
+
const relativePath = import_path.default.relative(parentDir, dir);
|
102
|
+
return !!relativePath && !relativePath.startsWith("..") && !import_path.default.isAbsolute(relativePath);
|
103
|
+
}
|
104
|
+
onError(error) {
|
105
|
+
this._topLevelErrors.push(error);
|
106
|
+
}
|
107
|
+
async onEnd(result) {
|
108
|
+
const projectSuites = this.suite.suites;
|
109
|
+
await (0, import_utils.removeFolders)([this._outputFolder]);
|
110
|
+
let noSnippets;
|
111
|
+
if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === "false" || process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === "0")
|
112
|
+
noSnippets = false;
|
113
|
+
else if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS)
|
114
|
+
noSnippets = true;
|
115
|
+
noSnippets = noSnippets || this._options.noSnippets;
|
116
|
+
let noCopyPrompt;
|
117
|
+
if (process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT === "false" || process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT === "0")
|
118
|
+
noCopyPrompt = false;
|
119
|
+
else if (process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT)
|
120
|
+
noCopyPrompt = true;
|
121
|
+
noCopyPrompt = noCopyPrompt || this._options.noCopyPrompt;
|
122
|
+
const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL, {
|
123
|
+
title: process.env.PLAYWRIGHT_HTML_TITLE || this._options.title,
|
124
|
+
noSnippets,
|
125
|
+
noCopyPrompt
|
126
|
+
});
|
127
|
+
this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);
|
128
|
+
}
|
129
|
+
async onExit() {
|
130
|
+
if (process.env.CI || !this._buildResult)
|
131
|
+
return;
|
132
|
+
const { ok, singleTestId } = this._buildResult;
|
133
|
+
const shouldOpen = !this._options._isTestServer && (this._open === "always" || !ok && this._open === "on-failure");
|
134
|
+
if (shouldOpen) {
|
135
|
+
await showHTMLReport(this._outputFolder, this._host, this._port, singleTestId);
|
136
|
+
} else if (this._options._mode === "test" && !this._options._isTestServer) {
|
137
|
+
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
|
138
|
+
const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? "" : " " + import_path.default.relative(process.cwd(), this._outputFolder);
|
139
|
+
const hostArg = this._host ? ` --host ${this._host}` : "";
|
140
|
+
const portArg = this._port ? ` --port ${this._port}` : "";
|
141
|
+
writeLine("");
|
142
|
+
writeLine("To open last HTML report run:");
|
143
|
+
writeLine(import_utils2.colors.cyan(`
|
144
|
+
${packageManagerCommand} playwright show-report${relativeReportPath}${hostArg}${portArg}
|
145
|
+
`));
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
function reportFolderFromEnv() {
|
150
|
+
const envValue = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT;
|
151
|
+
return envValue ? import_path.default.resolve(envValue) : void 0;
|
152
|
+
}
|
153
|
+
function getHtmlReportOptionProcessEnv() {
|
154
|
+
const htmlOpenEnv = process.env.PLAYWRIGHT_HTML_OPEN || process.env.PW_TEST_HTML_REPORT_OPEN;
|
155
|
+
if (!htmlOpenEnv)
|
156
|
+
return void 0;
|
157
|
+
if (!isHtmlReportOption(htmlOpenEnv)) {
|
158
|
+
writeLine(import_utils2.colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(", ")}`));
|
159
|
+
return void 0;
|
160
|
+
}
|
161
|
+
return htmlOpenEnv;
|
162
|
+
}
|
163
|
+
function standaloneDefaultFolder() {
|
164
|
+
return reportFolderFromEnv() ?? (0, import_util.resolveReporterOutputPath)("playwright-report", process.cwd(), void 0);
|
165
|
+
}
|
166
|
+
async function showHTMLReport(reportFolder, host = "localhost", port, testId) {
|
167
|
+
const folder = reportFolder ?? standaloneDefaultFolder();
|
168
|
+
try {
|
169
|
+
(0, import_utils.assert)(import_fs.default.statSync(folder).isDirectory());
|
170
|
+
} catch (e) {
|
171
|
+
writeLine(import_utils2.colors.red(`No report found at "${folder}"`));
|
172
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(1);
|
173
|
+
return;
|
174
|
+
}
|
175
|
+
const server = startHtmlReportServer(folder);
|
176
|
+
await server.start({ port, host, preferredPort: port ? void 0 : 9323 });
|
177
|
+
let url = server.urlPrefix("human-readable");
|
178
|
+
writeLine("");
|
179
|
+
writeLine(import_utils2.colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));
|
180
|
+
if (testId)
|
181
|
+
url += `#?testId=${testId}`;
|
182
|
+
url = url.replace("0.0.0.0", "localhost");
|
183
|
+
await (0, import_utilsBundle.open)(url, { wait: true }).catch(() => {
|
184
|
+
});
|
185
|
+
await new Promise(() => {
|
186
|
+
});
|
187
|
+
}
|
188
|
+
function startHtmlReportServer(folder) {
|
189
|
+
const server = new import_utils.HttpServer();
|
190
|
+
server.routePrefix("/", (request, response) => {
|
191
|
+
let relativePath = new URL("http://localhost" + request.url).pathname;
|
192
|
+
if (relativePath.startsWith("/trace/file")) {
|
193
|
+
const url = new URL("http://localhost" + request.url);
|
194
|
+
try {
|
195
|
+
return server.serveFile(request, response, url.searchParams.get("path"));
|
196
|
+
} catch (e) {
|
197
|
+
return false;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
if (relativePath.endsWith("/stall.js"))
|
201
|
+
return true;
|
202
|
+
if (relativePath === "/")
|
203
|
+
relativePath = "/index.html";
|
204
|
+
const absolutePath = import_path.default.join(folder, ...relativePath.split("/"));
|
205
|
+
return server.serveFile(request, response, absolutePath);
|
206
|
+
});
|
207
|
+
return server;
|
208
|
+
}
|
209
|
+
class HtmlBuilder {
|
210
|
+
constructor(config, outputDir, attachmentsBaseURL, options) {
|
211
|
+
this._stepsInFile = new import_utils.MultiMap();
|
212
|
+
this._hasTraces = false;
|
213
|
+
this._config = config;
|
214
|
+
this._reportFolder = outputDir;
|
215
|
+
this._options = options;
|
216
|
+
import_fs.default.mkdirSync(this._reportFolder, { recursive: true });
|
217
|
+
this._dataZipFile = new import_zipBundle.yazl.ZipFile();
|
218
|
+
this._attachmentsBaseURL = attachmentsBaseURL;
|
219
|
+
}
|
220
|
+
async build(metadata, projectSuites, result, topLevelErrors) {
|
221
|
+
const data = /* @__PURE__ */ new Map();
|
222
|
+
for (const projectSuite of projectSuites) {
|
223
|
+
const projectName = projectSuite.project().name;
|
224
|
+
for (const fileSuite of projectSuite.suites) {
|
225
|
+
const fileName = this._relativeLocation(fileSuite.location).file;
|
226
|
+
this._createEntryForSuite(data, projectName, fileSuite, fileName, true);
|
227
|
+
}
|
228
|
+
}
|
229
|
+
if (!this._options.noSnippets)
|
230
|
+
createSnippets(this._stepsInFile);
|
231
|
+
let ok = true;
|
232
|
+
for (const [fileId, { testFile, testFileSummary }] of data) {
|
233
|
+
const stats = testFileSummary.stats;
|
234
|
+
for (const test of testFileSummary.tests) {
|
235
|
+
if (test.outcome === "expected")
|
236
|
+
++stats.expected;
|
237
|
+
if (test.outcome === "skipped")
|
238
|
+
++stats.skipped;
|
239
|
+
if (test.outcome === "unexpected")
|
240
|
+
++stats.unexpected;
|
241
|
+
if (test.outcome === "flaky")
|
242
|
+
++stats.flaky;
|
243
|
+
++stats.total;
|
244
|
+
}
|
245
|
+
stats.ok = stats.unexpected + stats.flaky === 0;
|
246
|
+
if (!stats.ok)
|
247
|
+
ok = false;
|
248
|
+
const testCaseSummaryComparator = (t1, t2) => {
|
249
|
+
const w1 = (t1.outcome === "unexpected" ? 1e3 : 0) + (t1.outcome === "flaky" ? 1 : 0);
|
250
|
+
const w2 = (t2.outcome === "unexpected" ? 1e3 : 0) + (t2.outcome === "flaky" ? 1 : 0);
|
251
|
+
return w2 - w1;
|
252
|
+
};
|
253
|
+
testFileSummary.tests.sort(testCaseSummaryComparator);
|
254
|
+
this._addDataFile(fileId + ".json", testFile);
|
255
|
+
}
|
256
|
+
const htmlReport = {
|
257
|
+
metadata,
|
258
|
+
startTime: result.startTime.getTime(),
|
259
|
+
duration: result.duration,
|
260
|
+
files: [...data.values()].map((e) => e.testFileSummary),
|
261
|
+
projectNames: projectSuites.map((r) => r.project().name),
|
262
|
+
stats: { ...[...data.values()].reduce((a, e) => addStats(a, e.testFileSummary.stats), emptyStats()) },
|
263
|
+
errors: topLevelErrors.map((error) => (0, import_base.formatError)(import_base.internalScreen, error).message),
|
264
|
+
options: this._options
|
265
|
+
};
|
266
|
+
htmlReport.files.sort((f1, f2) => {
|
267
|
+
const w1 = f1.stats.unexpected * 1e3 + f1.stats.flaky;
|
268
|
+
const w2 = f2.stats.unexpected * 1e3 + f2.stats.flaky;
|
269
|
+
return w2 - w1;
|
270
|
+
});
|
271
|
+
this._addDataFile("report.json", htmlReport);
|
272
|
+
let singleTestId;
|
273
|
+
if (htmlReport.stats.total === 1) {
|
274
|
+
const testFile = data.values().next().value.testFile;
|
275
|
+
singleTestId = testFile.tests[0].testId;
|
276
|
+
}
|
277
|
+
if (process.env.PW_HMR === "1") {
|
278
|
+
const redirectFile = import_path.default.join(this._reportFolder, "index.html");
|
279
|
+
await this._writeReportData(redirectFile);
|
280
|
+
async function redirect() {
|
281
|
+
const hmrURL = new URL("http://localhost:44224");
|
282
|
+
const popup = window.open(hmrURL);
|
283
|
+
const listener = (evt) => {
|
284
|
+
if (evt.source === popup && evt.data === "ready") {
|
285
|
+
const element = document.getElementById("playwrightReportBase64");
|
286
|
+
popup.postMessage(element?.textContent ?? "", hmrURL.origin);
|
287
|
+
window.removeEventListener("message", listener);
|
288
|
+
window.close();
|
289
|
+
}
|
290
|
+
};
|
291
|
+
window.addEventListener("message", listener);
|
292
|
+
}
|
293
|
+
import_fs.default.appendFileSync(redirectFile, `<script>(${redirect.toString()})()</script>`);
|
294
|
+
return { ok, singleTestId };
|
295
|
+
}
|
296
|
+
const appFolder = import_path.default.join(require.resolve("playwright-core"), "..", "lib", "vite", "htmlReport");
|
297
|
+
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(appFolder, "index.html"), import_path.default.join(this._reportFolder, "index.html"));
|
298
|
+
if (this._hasTraces) {
|
299
|
+
const traceViewerFolder = import_path.default.join(require.resolve("playwright-core"), "..", "lib", "vite", "traceViewer");
|
300
|
+
const traceViewerTargetFolder = import_path.default.join(this._reportFolder, "trace");
|
301
|
+
const traceViewerAssetsTargetFolder = import_path.default.join(traceViewerTargetFolder, "assets");
|
302
|
+
import_fs.default.mkdirSync(traceViewerAssetsTargetFolder, { recursive: true });
|
303
|
+
for (const file of import_fs.default.readdirSync(traceViewerFolder)) {
|
304
|
+
if (file.endsWith(".map") || file.includes("watch") || file.includes("assets"))
|
305
|
+
continue;
|
306
|
+
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(traceViewerFolder, file), import_path.default.join(traceViewerTargetFolder, file));
|
307
|
+
}
|
308
|
+
for (const file of import_fs.default.readdirSync(import_path.default.join(traceViewerFolder, "assets"))) {
|
309
|
+
if (file.endsWith(".map") || file.includes("xtermModule"))
|
310
|
+
continue;
|
311
|
+
await (0, import_utils.copyFileAndMakeWritable)(import_path.default.join(traceViewerFolder, "assets", file), import_path.default.join(traceViewerAssetsTargetFolder, file));
|
312
|
+
}
|
313
|
+
}
|
314
|
+
await this._writeReportData(import_path.default.join(this._reportFolder, "index.html"));
|
315
|
+
return { ok, singleTestId };
|
316
|
+
}
|
317
|
+
async _writeReportData(filePath) {
|
318
|
+
import_fs.default.appendFileSync(filePath, '<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,');
|
319
|
+
await new Promise((f) => {
|
320
|
+
this._dataZipFile.end(void 0, () => {
|
321
|
+
this._dataZipFile.outputStream.pipe(new Base64Encoder()).pipe(import_fs.default.createWriteStream(filePath, { flags: "a" })).on("close", f);
|
322
|
+
});
|
323
|
+
});
|
324
|
+
import_fs.default.appendFileSync(filePath, "</script>");
|
325
|
+
}
|
326
|
+
_addDataFile(fileName, data) {
|
327
|
+
this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);
|
328
|
+
}
|
329
|
+
_createEntryForSuite(data, projectName, suite, fileName, deep) {
|
330
|
+
const fileId = (0, import_utils.calculateSha1)(fileName).slice(0, 20);
|
331
|
+
let fileEntry = data.get(fileId);
|
332
|
+
if (!fileEntry) {
|
333
|
+
fileEntry = {
|
334
|
+
testFile: { fileId, fileName, tests: [] },
|
335
|
+
testFileSummary: { fileId, fileName, tests: [], stats: emptyStats() }
|
336
|
+
};
|
337
|
+
data.set(fileId, fileEntry);
|
338
|
+
}
|
339
|
+
const { testFile, testFileSummary } = fileEntry;
|
340
|
+
const testEntries = [];
|
341
|
+
this._processSuite(suite, projectName, [], deep, testEntries);
|
342
|
+
for (const test of testEntries) {
|
343
|
+
testFile.tests.push(test.testCase);
|
344
|
+
testFileSummary.tests.push(test.testCaseSummary);
|
345
|
+
}
|
346
|
+
}
|
347
|
+
_processSuite(suite, projectName, path2, deep, outTests) {
|
348
|
+
const newPath = [...path2, suite.title];
|
349
|
+
suite.entries().forEach((e) => {
|
350
|
+
if (e.type === "test")
|
351
|
+
outTests.push(this._createTestEntry(e, projectName, newPath));
|
352
|
+
else if (deep)
|
353
|
+
this._processSuite(e, projectName, newPath, deep, outTests);
|
354
|
+
});
|
355
|
+
}
|
356
|
+
_createTestEntry(test, projectName, path2) {
|
357
|
+
const duration = test.results.reduce((a, r) => a + r.duration, 0);
|
358
|
+
const location = this._relativeLocation(test.location);
|
359
|
+
path2 = path2.slice(1).filter((path3) => path3.length > 0);
|
360
|
+
const results = test.results.map((r) => this._createTestResult(test, r));
|
361
|
+
return {
|
362
|
+
testCase: {
|
363
|
+
testId: test.id,
|
364
|
+
title: test.title,
|
365
|
+
projectName,
|
366
|
+
location,
|
367
|
+
duration,
|
368
|
+
annotations: this._serializeAnnotations(test.annotations),
|
369
|
+
tags: test.tags,
|
370
|
+
outcome: test.outcome(),
|
371
|
+
path: path2,
|
372
|
+
results,
|
373
|
+
ok: test.outcome() === "expected" || test.outcome() === "flaky"
|
374
|
+
},
|
375
|
+
testCaseSummary: {
|
376
|
+
testId: test.id,
|
377
|
+
title: test.title,
|
378
|
+
projectName,
|
379
|
+
location,
|
380
|
+
duration,
|
381
|
+
annotations: this._serializeAnnotations(test.annotations),
|
382
|
+
tags: test.tags,
|
383
|
+
outcome: test.outcome(),
|
384
|
+
path: path2,
|
385
|
+
ok: test.outcome() === "expected" || test.outcome() === "flaky",
|
386
|
+
results: results.map((result) => {
|
387
|
+
return { attachments: result.attachments.map((a) => ({ name: a.name, contentType: a.contentType, path: a.path })) };
|
388
|
+
})
|
389
|
+
}
|
390
|
+
};
|
391
|
+
}
|
392
|
+
_serializeAttachments(attachments) {
|
393
|
+
let lastAttachment;
|
394
|
+
return attachments.map((a) => {
|
395
|
+
if (a.name === "trace")
|
396
|
+
this._hasTraces = true;
|
397
|
+
if ((a.name === "stdout" || a.name === "stderr") && a.contentType === "text/plain") {
|
398
|
+
if (lastAttachment && lastAttachment.name === a.name && lastAttachment.contentType === a.contentType) {
|
399
|
+
lastAttachment.body += (0, import_util.stripAnsiEscapes)(a.body);
|
400
|
+
return null;
|
401
|
+
}
|
402
|
+
a.body = (0, import_util.stripAnsiEscapes)(a.body);
|
403
|
+
lastAttachment = a;
|
404
|
+
return a;
|
405
|
+
}
|
406
|
+
if (a.path) {
|
407
|
+
let fileName = a.path;
|
408
|
+
try {
|
409
|
+
const buffer = import_fs.default.readFileSync(a.path);
|
410
|
+
const sha1 = (0, import_utils.calculateSha1)(buffer) + import_path.default.extname(a.path);
|
411
|
+
fileName = this._attachmentsBaseURL + sha1;
|
412
|
+
import_fs.default.mkdirSync(import_path.default.join(this._reportFolder, "data"), { recursive: true });
|
413
|
+
import_fs.default.writeFileSync(import_path.default.join(this._reportFolder, "data", sha1), buffer);
|
414
|
+
} catch (e) {
|
415
|
+
}
|
416
|
+
return {
|
417
|
+
name: a.name,
|
418
|
+
contentType: a.contentType,
|
419
|
+
path: fileName,
|
420
|
+
body: a.body
|
421
|
+
};
|
422
|
+
}
|
423
|
+
if (a.body instanceof Buffer) {
|
424
|
+
if (isTextContentType(a.contentType)) {
|
425
|
+
const charset = a.contentType.match(/charset=(.*)/)?.[1];
|
426
|
+
try {
|
427
|
+
const body = a.body.toString(charset || "utf-8");
|
428
|
+
return {
|
429
|
+
name: a.name,
|
430
|
+
contentType: a.contentType,
|
431
|
+
body
|
432
|
+
};
|
433
|
+
} catch (e) {
|
434
|
+
}
|
435
|
+
}
|
436
|
+
import_fs.default.mkdirSync(import_path.default.join(this._reportFolder, "data"), { recursive: true });
|
437
|
+
const extension = (0, import_utils.sanitizeForFilePath)(import_path.default.extname(a.name).replace(/^\./, "")) || import_utilsBundle2.mime.getExtension(a.contentType) || "dat";
|
438
|
+
const sha1 = (0, import_utils.calculateSha1)(a.body) + "." + extension;
|
439
|
+
import_fs.default.writeFileSync(import_path.default.join(this._reportFolder, "data", sha1), a.body);
|
440
|
+
return {
|
441
|
+
name: a.name,
|
442
|
+
contentType: a.contentType,
|
443
|
+
path: this._attachmentsBaseURL + sha1
|
444
|
+
};
|
445
|
+
}
|
446
|
+
return {
|
447
|
+
name: a.name,
|
448
|
+
contentType: a.contentType,
|
449
|
+
body: a.body
|
450
|
+
};
|
451
|
+
}).filter(Boolean);
|
452
|
+
}
|
453
|
+
_serializeAnnotations(annotations) {
|
454
|
+
return annotations.map((a) => ({
|
455
|
+
type: a.type,
|
456
|
+
description: a.description === void 0 ? void 0 : String(a.description),
|
457
|
+
location: a.location ? {
|
458
|
+
file: a.location.file,
|
459
|
+
line: a.location.line,
|
460
|
+
column: a.location.column
|
461
|
+
} : void 0
|
462
|
+
}));
|
463
|
+
}
|
464
|
+
_createTestResult(test, result) {
|
465
|
+
return {
|
466
|
+
duration: result.duration,
|
467
|
+
startTime: result.startTime.toISOString(),
|
468
|
+
retry: result.retry,
|
469
|
+
steps: dedupeSteps(result.steps).map((s) => this._createTestStep(s, result)),
|
470
|
+
errors: (0, import_base.formatResultFailure)(import_base.internalScreen, test, result, "").map((error) => {
|
471
|
+
return {
|
472
|
+
message: error.message,
|
473
|
+
codeframe: error.location ? createErrorCodeframe(error.message, error.location) : void 0
|
474
|
+
};
|
475
|
+
}),
|
476
|
+
status: result.status,
|
477
|
+
annotations: this._serializeAnnotations(result.annotations),
|
478
|
+
attachments: this._serializeAttachments([
|
479
|
+
...result.attachments,
|
480
|
+
...result.stdout.map((m) => stdioAttachment(m, "stdout")),
|
481
|
+
...result.stderr.map((m) => stdioAttachment(m, "stderr"))
|
482
|
+
])
|
483
|
+
};
|
484
|
+
}
|
485
|
+
_createTestStep(dedupedStep, result) {
|
486
|
+
const { step, duration, count } = dedupedStep;
|
487
|
+
const skipped = dedupedStep.step.annotations?.find((a) => a.type === "skip");
|
488
|
+
let title = step.title;
|
489
|
+
if (skipped)
|
490
|
+
title = `${title} (skipped${skipped.description ? ": " + skipped.description : ""})`;
|
491
|
+
const testStep = {
|
492
|
+
title,
|
493
|
+
startTime: step.startTime.toISOString(),
|
494
|
+
duration,
|
495
|
+
steps: dedupeSteps(step.steps).map((s) => this._createTestStep(s, result)),
|
496
|
+
attachments: step.attachments.map((s) => {
|
497
|
+
const index = result.attachments.indexOf(s);
|
498
|
+
if (index === -1)
|
499
|
+
throw new Error("Unexpected, attachment not found");
|
500
|
+
return index;
|
501
|
+
}),
|
502
|
+
location: this._relativeLocation(step.location),
|
503
|
+
error: step.error?.message,
|
504
|
+
count,
|
505
|
+
skipped: !!skipped
|
506
|
+
};
|
507
|
+
if (step.location)
|
508
|
+
this._stepsInFile.set(step.location.file, testStep);
|
509
|
+
return testStep;
|
510
|
+
}
|
511
|
+
_relativeLocation(location) {
|
512
|
+
if (!location)
|
513
|
+
return void 0;
|
514
|
+
const file = (0, import_utils.toPosixPath)(import_path.default.relative(this._config.rootDir, location.file));
|
515
|
+
return {
|
516
|
+
file,
|
517
|
+
line: location.line,
|
518
|
+
column: location.column
|
519
|
+
};
|
520
|
+
}
|
521
|
+
}
|
522
|
+
const emptyStats = () => {
|
523
|
+
return {
|
524
|
+
total: 0,
|
525
|
+
expected: 0,
|
526
|
+
unexpected: 0,
|
527
|
+
flaky: 0,
|
528
|
+
skipped: 0,
|
529
|
+
ok: true
|
530
|
+
};
|
531
|
+
};
|
532
|
+
const addStats = (stats, delta) => {
|
533
|
+
stats.total += delta.total;
|
534
|
+
stats.skipped += delta.skipped;
|
535
|
+
stats.expected += delta.expected;
|
536
|
+
stats.unexpected += delta.unexpected;
|
537
|
+
stats.flaky += delta.flaky;
|
538
|
+
stats.ok = stats.ok && delta.ok;
|
539
|
+
return stats;
|
540
|
+
};
|
541
|
+
class Base64Encoder extends import_stream.Transform {
|
542
|
+
_transform(chunk, encoding, callback) {
|
543
|
+
if (this._remainder) {
|
544
|
+
chunk = Buffer.concat([this._remainder, chunk]);
|
545
|
+
this._remainder = void 0;
|
546
|
+
}
|
547
|
+
const remaining = chunk.length % 3;
|
548
|
+
if (remaining) {
|
549
|
+
this._remainder = chunk.slice(chunk.length - remaining);
|
550
|
+
chunk = chunk.slice(0, chunk.length - remaining);
|
551
|
+
}
|
552
|
+
chunk = chunk.toString("base64");
|
553
|
+
this.push(Buffer.from(chunk));
|
554
|
+
callback();
|
555
|
+
}
|
556
|
+
_flush(callback) {
|
557
|
+
if (this._remainder)
|
558
|
+
this.push(Buffer.from(this._remainder.toString("base64")));
|
559
|
+
callback();
|
560
|
+
}
|
561
|
+
}
|
562
|
+
function isTextContentType(contentType) {
|
563
|
+
return contentType.startsWith("text/") || contentType.startsWith("application/json");
|
564
|
+
}
|
565
|
+
function stdioAttachment(chunk, type) {
|
566
|
+
return {
|
567
|
+
name: type,
|
568
|
+
contentType: "text/plain",
|
569
|
+
body: typeof chunk === "string" ? chunk : chunk.toString("utf-8")
|
570
|
+
};
|
571
|
+
}
|
572
|
+
function dedupeSteps(steps) {
|
573
|
+
const result = [];
|
574
|
+
let lastResult = void 0;
|
575
|
+
for (const step of steps) {
|
576
|
+
const canDedupe = !step.error && step.duration >= 0 && step.location?.file && !step.steps.length;
|
577
|
+
const lastStep = lastResult?.step;
|
578
|
+
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) {
|
579
|
+
++lastResult.count;
|
580
|
+
lastResult.duration += step.duration;
|
581
|
+
continue;
|
582
|
+
}
|
583
|
+
lastResult = { step, count: 1, duration: step.duration };
|
584
|
+
result.push(lastResult);
|
585
|
+
if (!canDedupe)
|
586
|
+
lastResult = void 0;
|
587
|
+
}
|
588
|
+
return result;
|
589
|
+
}
|
590
|
+
function createSnippets(stepsInFile) {
|
591
|
+
for (const file of stepsInFile.keys()) {
|
592
|
+
let source;
|
593
|
+
try {
|
594
|
+
source = import_fs.default.readFileSync(file, "utf-8") + "\n//";
|
595
|
+
} catch (e) {
|
596
|
+
continue;
|
597
|
+
}
|
598
|
+
const lines = source.split("\n").length;
|
599
|
+
const highlighted = (0, import_babelBundle.codeFrameColumns)(source, { start: { line: lines, column: 1 } }, { highlightCode: true, linesAbove: lines, linesBelow: 0 });
|
600
|
+
const highlightedLines = highlighted.split("\n");
|
601
|
+
const lineWithArrow = highlightedLines[highlightedLines.length - 1];
|
602
|
+
for (const step of stepsInFile.get(file)) {
|
603
|
+
if (step.location.line < 2 || step.location.line >= lines)
|
604
|
+
continue;
|
605
|
+
const snippetLines = highlightedLines.slice(step.location.line - 2, step.location.line + 1);
|
606
|
+
const index = lineWithArrow.indexOf("^");
|
607
|
+
const shiftedArrow = lineWithArrow.slice(0, index) + " ".repeat(step.location.column - 1) + lineWithArrow.slice(index);
|
608
|
+
snippetLines.splice(2, 0, shiftedArrow);
|
609
|
+
step.snippet = snippetLines.join("\n");
|
610
|
+
}
|
611
|
+
}
|
612
|
+
}
|
613
|
+
function createErrorCodeframe(message, location) {
|
614
|
+
let source;
|
615
|
+
try {
|
616
|
+
source = import_fs.default.readFileSync(location.file, "utf-8") + "\n//";
|
617
|
+
} catch (e) {
|
618
|
+
return;
|
619
|
+
}
|
620
|
+
return (0, import_babelBundle.codeFrameColumns)(
|
621
|
+
source,
|
622
|
+
{
|
623
|
+
start: {
|
624
|
+
line: location.line,
|
625
|
+
column: location.column
|
626
|
+
}
|
627
|
+
},
|
628
|
+
{
|
629
|
+
highlightCode: false,
|
630
|
+
linesAbove: 100,
|
631
|
+
linesBelow: 100,
|
632
|
+
message: (0, import_util.stripAnsiEscapes)(message).split("\n")[0] || void 0
|
633
|
+
}
|
634
|
+
);
|
635
|
+
}
|
636
|
+
function writeLine(line) {
|
637
|
+
process.stdout.write(line + "\n");
|
638
|
+
}
|
639
|
+
var html_default = HtmlReporter;
|
640
|
+
// Annotate the CommonJS export names for ESM import in node:
|
641
|
+
0 && (module.exports = {
|
642
|
+
showHTMLReport,
|
643
|
+
startHtmlReportServer
|
644
|
+
});
|