ScuttleBot

Source Blame History 558 lines
f7eb47b… lmata 1 "use strict";
f7eb47b… lmata 2 var __create = Object.create;
f7eb47b… lmata 3 var __defProp = Object.defineProperty;
f7eb47b… lmata 4 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
f7eb47b… lmata 5 var __getOwnPropNames = Object.getOwnPropertyNames;
f7eb47b… lmata 6 var __getProtoOf = Object.getPrototypeOf;
f7eb47b… lmata 7 var __hasOwnProp = Object.prototype.hasOwnProperty;
f7eb47b… lmata 8 var __export = (target, all) => {
f7eb47b… lmata 9 for (var name in all)
f7eb47b… lmata 10 __defProp(target, name, { get: all[name], enumerable: true });
f7eb47b… lmata 11 };
f7eb47b… lmata 12 var __copyProps = (to, from, except, desc) => {
f7eb47b… lmata 13 if (from && typeof from === "object" || typeof from === "function") {
f7eb47b… lmata 14 for (let key of __getOwnPropNames(from))
f7eb47b… lmata 15 if (!__hasOwnProp.call(to, key) && key !== except)
f7eb47b… lmata 16 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
f7eb47b… lmata 17 }
f7eb47b… lmata 18 return to;
f7eb47b… lmata 19 };
f7eb47b… lmata 20 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
f7eb47b… lmata 21 // If the importer is in node compatibility mode or this is not an ESM
f7eb47b… lmata 22 // file that has been converted to a CommonJS file using a Babel-
f7eb47b… lmata 23 // compatible transform (i.e. "__esModule" has not been set), then set
f7eb47b… lmata 24 // "default" to the CommonJS "module.exports" for node compatibility.
f7eb47b… lmata 25 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
f7eb47b… lmata 26 mod
f7eb47b… lmata 27 ));
f7eb47b… lmata 28 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
f7eb47b… lmata 29 var merge_exports = {};
f7eb47b… lmata 30 __export(merge_exports, {
f7eb47b… lmata 31 createMergedReport: () => createMergedReport
f7eb47b… lmata 32 });
f7eb47b… lmata 33 module.exports = __toCommonJS(merge_exports);
f7eb47b… lmata 34 var import_fs = __toESM(require("fs"));
f7eb47b… lmata 35 var import_path = __toESM(require("path"));
f7eb47b… lmata 36 var import_utils = require("playwright-core/lib/utils");
f7eb47b… lmata 37 var import_blob = require("./blob");
f7eb47b… lmata 38 var import_multiplexer = require("./multiplexer");
f7eb47b… lmata 39 var import_stringInternPool = require("../isomorphic/stringInternPool");
f7eb47b… lmata 40 var import_teleReceiver = require("../isomorphic/teleReceiver");
f7eb47b… lmata 41 var import_reporters = require("../runner/reporters");
f7eb47b… lmata 42 var import_util = require("../util");
f7eb47b… lmata 43 async function createMergedReport(config, dir, reporterDescriptions, rootDirOverride) {
f7eb47b… lmata 44 const reporters = await (0, import_reporters.createReporters)(config, "merge", reporterDescriptions);
f7eb47b… lmata 45 const multiplexer = new import_multiplexer.Multiplexer(reporters);
f7eb47b… lmata 46 const stringPool = new import_stringInternPool.StringInternPool();
f7eb47b… lmata 47 let printStatus = () => {
f7eb47b… lmata 48 };
f7eb47b… lmata 49 if (!multiplexer.printsToStdio()) {
f7eb47b… lmata 50 printStatus = printStatusToStdout;
f7eb47b… lmata 51 printStatus(`merging reports from ${dir}`);
f7eb47b… lmata 52 }
f7eb47b… lmata 53 const shardFiles = await sortedShardFiles(dir);
f7eb47b… lmata 54 if (shardFiles.length === 0)
f7eb47b… lmata 55 throw new Error(`No report files found in ${dir}`);
f7eb47b… lmata 56 const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);
f7eb47b… lmata 57 const pathSeparator = rootDirOverride ? import_path.default.sep : eventData.pathSeparatorFromMetadata ?? import_path.default.sep;
f7eb47b… lmata 58 const pathPackage = pathSeparator === "/" ? import_path.default.posix : import_path.default.win32;
f7eb47b… lmata 59 const receiver = new import_teleReceiver.TeleReporterReceiver(multiplexer, {
f7eb47b… lmata 60 mergeProjects: false,
f7eb47b… lmata 61 mergeTestCases: false,
f7eb47b… lmata 62 // When merging on a different OS, an absolute path like `C:\foo\bar` from win may look like
f7eb47b… lmata 63 // a relative path on posix, and vice versa.
f7eb47b… lmata 64 // Therefore, we cannot use `path.resolve()` here - it will resolve relative-looking paths
f7eb47b… lmata 65 // against `process.cwd()`, while we just want to normalize ".." and "." segments.
f7eb47b… lmata 66 resolvePath: (rootDir, relativePath) => stringPool.internString(pathPackage.normalize(pathPackage.join(rootDir, relativePath))),
f7eb47b… lmata 67 configOverrides: config.config
f7eb47b… lmata 68 });
f7eb47b… lmata 69 printStatus(`processing test events`);
f7eb47b… lmata 70 const dispatchEvents = async (events) => {
f7eb47b… lmata 71 for (const event of events) {
f7eb47b… lmata 72 if (event.method === "onEnd")
f7eb47b… lmata 73 printStatus(`building final report`);
f7eb47b… lmata 74 await receiver.dispatch(event);
f7eb47b… lmata 75 if (event.method === "onEnd")
f7eb47b… lmata 76 printStatus(`finished building report`);
f7eb47b… lmata 77 }
f7eb47b… lmata 78 };
f7eb47b… lmata 79 await dispatchEvents(eventData.prologue);
f7eb47b… lmata 80 for (const { reportFile, eventPatchers, metadata, tags, startTime, duration } of eventData.reports) {
f7eb47b… lmata 81 const reportJsonl = await import_fs.default.promises.readFile(reportFile);
f7eb47b… lmata 82 const events = parseTestEvents(reportJsonl);
f7eb47b… lmata 83 new import_stringInternPool.JsonStringInternalizer(stringPool).traverse(events);
f7eb47b… lmata 84 eventPatchers.patchers.push(new AttachmentPathPatcher(dir));
f7eb47b… lmata 85 if (metadata.name)
f7eb47b… lmata 86 eventPatchers.patchers.push(new GlobalErrorPatcher(metadata.name));
f7eb47b… lmata 87 if (tags.length)
f7eb47b… lmata 88 eventPatchers.patchers.push(new GlobalErrorPatcher(tags.join(" ")));
f7eb47b… lmata 89 eventPatchers.patchEvents(events);
f7eb47b… lmata 90 await dispatchEvents(events);
f7eb47b… lmata 91 multiplexer.onMachineEnd({
f7eb47b… lmata 92 startTime: new Date(startTime),
f7eb47b… lmata 93 duration,
f7eb47b… lmata 94 tag: tags,
f7eb47b… lmata 95 shardIndex: metadata.shard?.current
f7eb47b… lmata 96 });
f7eb47b… lmata 97 }
f7eb47b… lmata 98 await dispatchEvents(eventData.epilogue);
f7eb47b… lmata 99 }
f7eb47b… lmata 100 const commonEventNames = ["onBlobReportMetadata", "onConfigure", "onProject", "onBegin", "onEnd"];
f7eb47b… lmata 101 const commonEvents = new Set(commonEventNames);
f7eb47b… lmata 102 const commonEventRegex = new RegExp(`${commonEventNames.join("|")}`);
f7eb47b… lmata 103 function parseCommonEvents(reportJsonl) {
f7eb47b… lmata 104 return splitBufferLines(reportJsonl).map((line) => line.toString("utf8")).filter((line) => commonEventRegex.test(line)).map((line) => JSON.parse(line)).filter((event) => commonEvents.has(event.method));
f7eb47b… lmata 105 }
f7eb47b… lmata 106 function parseTestEvents(reportJsonl) {
f7eb47b… lmata 107 return splitBufferLines(reportJsonl).map((line) => line.toString("utf8")).filter((line) => line.length).map((line) => JSON.parse(line)).filter((event) => !commonEvents.has(event.method));
f7eb47b… lmata 108 }
f7eb47b… lmata 109 function splitBufferLines(buffer) {
f7eb47b… lmata 110 const lines = [];
f7eb47b… lmata 111 let start = 0;
f7eb47b… lmata 112 while (start < buffer.length) {
f7eb47b… lmata 113 const end = buffer.indexOf(10, start);
f7eb47b… lmata 114 if (end === -1) {
f7eb47b… lmata 115 lines.push(buffer.slice(start));
f7eb47b… lmata 116 break;
f7eb47b… lmata 117 }
f7eb47b… lmata 118 lines.push(buffer.slice(start, end));
f7eb47b… lmata 119 start = end + 1;
f7eb47b… lmata 120 }
f7eb47b… lmata 121 return lines;
f7eb47b… lmata 122 }
f7eb47b… lmata 123 async function extractAndParseReports(dir, shardFiles, internalizer, printStatus) {
f7eb47b… lmata 124 const shardEvents = [];
f7eb47b… lmata 125 await import_fs.default.promises.mkdir(import_path.default.join(dir, "resources"), { recursive: true });
f7eb47b… lmata 126 const reportNames = new UniqueFileNameGenerator();
f7eb47b… lmata 127 for (const file of shardFiles) {
f7eb47b… lmata 128 const absolutePath = import_path.default.join(dir, file);
f7eb47b… lmata 129 printStatus(`extracting: ${(0, import_util.relativeFilePath)(absolutePath)}`);
f7eb47b… lmata 130 const zipFile = new import_utils.ZipFile(absolutePath);
f7eb47b… lmata 131 const entryNames = await zipFile.entries();
f7eb47b… lmata 132 for (const entryName of entryNames.sort()) {
f7eb47b… lmata 133 let fileName = import_path.default.join(dir, entryName);
f7eb47b… lmata 134 const content = await zipFile.read(entryName);
f7eb47b… lmata 135 if (entryName.endsWith(".jsonl")) {
f7eb47b… lmata 136 fileName = reportNames.makeUnique(fileName);
f7eb47b… lmata 137 let parsedEvents = parseCommonEvents(content);
f7eb47b… lmata 138 internalizer.traverse(parsedEvents);
f7eb47b… lmata 139 const metadata = findMetadata(parsedEvents, file);
f7eb47b… lmata 140 parsedEvents = modernizer.modernize(metadata.version, parsedEvents);
f7eb47b… lmata 141 shardEvents.push({
f7eb47b… lmata 142 file,
f7eb47b… lmata 143 localPath: fileName,
f7eb47b… lmata 144 metadata,
f7eb47b… lmata 145 parsedEvents
f7eb47b… lmata 146 });
f7eb47b… lmata 147 }
f7eb47b… lmata 148 await import_fs.default.promises.writeFile(fileName, content);
f7eb47b… lmata 149 }
f7eb47b… lmata 150 zipFile.close();
f7eb47b… lmata 151 }
f7eb47b… lmata 152 return shardEvents;
f7eb47b… lmata 153 }
f7eb47b… lmata 154 function findMetadata(events, file) {
f7eb47b… lmata 155 if (events[0]?.method !== "onBlobReportMetadata")
f7eb47b… lmata 156 throw new Error(`No metadata event found in ${file}`);
f7eb47b… lmata 157 const metadata = events[0].params;
f7eb47b… lmata 158 if (metadata.version > import_blob.currentBlobReportVersion)
f7eb47b… lmata 159 throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
f7eb47b… lmata 160 return metadata;
f7eb47b… lmata 161 }
f7eb47b… lmata 162 async function mergeEvents(dir, shardReportFiles, stringPool, printStatus, rootDirOverride) {
f7eb47b… lmata 163 const internalizer = new import_stringInternPool.JsonStringInternalizer(stringPool);
f7eb47b… lmata 164 const configureEvents = [];
f7eb47b… lmata 165 const projectEvents = [];
f7eb47b… lmata 166 const endEvents = [];
f7eb47b… lmata 167 const blobs = await extractAndParseReports(dir, shardReportFiles, internalizer, printStatus);
f7eb47b… lmata 168 blobs.sort((a, b) => {
f7eb47b… lmata 169 const nameA = a.metadata.name ?? "";
f7eb47b… lmata 170 const nameB = b.metadata.name ?? "";
f7eb47b… lmata 171 if (nameA !== nameB)
f7eb47b… lmata 172 return nameA.localeCompare(nameB);
f7eb47b… lmata 173 const shardA = a.metadata.shard?.current ?? 0;
f7eb47b… lmata 174 const shardB = b.metadata.shard?.current ?? 0;
f7eb47b… lmata 175 if (shardA !== shardB)
f7eb47b… lmata 176 return shardA - shardB;
f7eb47b… lmata 177 return a.file.localeCompare(b.file);
f7eb47b… lmata 178 });
f7eb47b… lmata 179 printStatus(`merging events`);
f7eb47b… lmata 180 const reports = [];
f7eb47b… lmata 181 const globalTestIdSet = /* @__PURE__ */ new Set();
f7eb47b… lmata 182 for (let i = 0; i < blobs.length; ++i) {
f7eb47b… lmata 183 const { parsedEvents, metadata, localPath } = blobs[i];
f7eb47b… lmata 184 const eventPatchers = new JsonEventPatchers();
f7eb47b… lmata 185 eventPatchers.patchers.push(new IdsPatcher(
f7eb47b… lmata 186 stringPool,
f7eb47b… lmata 187 metadata.name,
f7eb47b… lmata 188 String(i),
f7eb47b… lmata 189 globalTestIdSet
f7eb47b… lmata 190 ));
f7eb47b… lmata 191 if (rootDirOverride)
f7eb47b… lmata 192 eventPatchers.patchers.push(new PathSeparatorPatcher(metadata.pathSeparator));
f7eb47b… lmata 193 eventPatchers.patchEvents(parsedEvents);
f7eb47b… lmata 194 let tags = [];
f7eb47b… lmata 195 let startTime = 0;
f7eb47b… lmata 196 let duration = 0;
f7eb47b… lmata 197 for (const event of parsedEvents) {
f7eb47b… lmata 198 if (event.method === "onConfigure") {
f7eb47b… lmata 199 configureEvents.push(event);
f7eb47b… lmata 200 tags = event.params.config.tags || [];
f7eb47b… lmata 201 } else if (event.method === "onProject") {
f7eb47b… lmata 202 projectEvents.push(event);
f7eb47b… lmata 203 } else if (event.method === "onEnd") {
f7eb47b… lmata 204 endEvents.push({ event, metadata, tags });
f7eb47b… lmata 205 startTime = event.params.result.startTime;
f7eb47b… lmata 206 duration = event.params.result.duration;
f7eb47b… lmata 207 }
f7eb47b… lmata 208 }
f7eb47b… lmata 209 reports.push({
f7eb47b… lmata 210 eventPatchers,
f7eb47b… lmata 211 reportFile: localPath,
f7eb47b… lmata 212 metadata,
f7eb47b… lmata 213 tags,
f7eb47b… lmata 214 startTime,
f7eb47b… lmata 215 duration
f7eb47b… lmata 216 });
f7eb47b… lmata 217 }
f7eb47b… lmata 218 return {
f7eb47b… lmata 219 prologue: [
f7eb47b… lmata 220 mergeConfigureEvents(configureEvents, rootDirOverride),
f7eb47b… lmata 221 ...projectEvents,
f7eb47b… lmata 222 { method: "onBegin", params: void 0 }
f7eb47b… lmata 223 ],
f7eb47b… lmata 224 reports,
f7eb47b… lmata 225 epilogue: [
f7eb47b… lmata 226 mergeEndEvents(endEvents),
f7eb47b… lmata 227 { method: "onExit", params: void 0 }
f7eb47b… lmata 228 ],
f7eb47b… lmata 229 pathSeparatorFromMetadata: blobs[0]?.metadata.pathSeparator
f7eb47b… lmata 230 };
f7eb47b… lmata 231 }
f7eb47b… lmata 232 function mergeConfigureEvents(configureEvents, rootDirOverride) {
f7eb47b… lmata 233 if (!configureEvents.length)
f7eb47b… lmata 234 throw new Error("No configure events found");
f7eb47b… lmata 235 let config = {
f7eb47b… lmata 236 configFile: void 0,
f7eb47b… lmata 237 globalTimeout: 0,
f7eb47b… lmata 238 maxFailures: 0,
f7eb47b… lmata 239 metadata: {},
f7eb47b… lmata 240 rootDir: "",
f7eb47b… lmata 241 version: "",
f7eb47b… lmata 242 workers: 0,
f7eb47b… lmata 243 globalSetup: null,
f7eb47b… lmata 244 globalTeardown: null
f7eb47b… lmata 245 };
f7eb47b… lmata 246 for (const event of configureEvents)
f7eb47b… lmata 247 config = mergeConfigs(config, event.params.config);
f7eb47b… lmata 248 if (rootDirOverride) {
f7eb47b… lmata 249 config.rootDir = rootDirOverride;
f7eb47b… lmata 250 } else {
f7eb47b… lmata 251 const rootDirs = new Set(configureEvents.map((e) => e.params.config.rootDir));
f7eb47b… lmata 252 if (rootDirs.size > 1) {
f7eb47b… lmata 253 throw new Error([
f7eb47b… lmata 254 `Blob reports being merged were recorded with different test directories, and`,
f7eb47b… lmata 255 `merging cannot proceed. This may happen if you are merging reports from`,
f7eb47b… lmata 256 `machines with different environments, like different operating systems or`,
f7eb47b… lmata 257 `if the tests ran with different playwright configs.`,
f7eb47b… lmata 258 ``,
f7eb47b… lmata 259 `You can force merge by specifying a merge config file with "-c" option. If`,
f7eb47b… lmata 260 `you'd like all test paths to be correct, make sure 'testDir' in the merge config`,
f7eb47b… lmata 261 `file points to the actual tests location.`,
f7eb47b… lmata 262 ``,
f7eb47b… lmata 263 `Found directories:`,
f7eb47b… lmata 264 ...rootDirs
f7eb47b… lmata 265 ].join("\n"));
f7eb47b… lmata 266 }
f7eb47b… lmata 267 }
f7eb47b… lmata 268 return {
f7eb47b… lmata 269 method: "onConfigure",
f7eb47b… lmata 270 params: {
f7eb47b… lmata 271 config
f7eb47b… lmata 272 }
f7eb47b… lmata 273 };
f7eb47b… lmata 274 }
f7eb47b… lmata 275 function mergeConfigs(to, from) {
f7eb47b… lmata 276 return {
f7eb47b… lmata 277 ...to,
f7eb47b… lmata 278 ...from,
f7eb47b… lmata 279 metadata: {
f7eb47b… lmata 280 ...to.metadata,
f7eb47b… lmata 281 ...from.metadata,
f7eb47b… lmata 282 actualWorkers: (to.metadata.actualWorkers || 0) + (from.metadata.actualWorkers || 0)
f7eb47b… lmata 283 },
f7eb47b… lmata 284 workers: to.workers + from.workers
f7eb47b… lmata 285 };
f7eb47b… lmata 286 }
f7eb47b… lmata 287 function mergeEndEvents(endEvents) {
f7eb47b… lmata 288 let startTime = endEvents.length ? 1e13 : Date.now();
f7eb47b… lmata 289 let status = "passed";
f7eb47b… lmata 290 let endTime = 0;
f7eb47b… lmata 291 for (const { event } of endEvents) {
f7eb47b… lmata 292 const shardResult = event.params.result;
f7eb47b… lmata 293 if (shardResult.status === "failed")
f7eb47b… lmata 294 status = "failed";
f7eb47b… lmata 295 else if (shardResult.status === "timedout" && status !== "failed")
f7eb47b… lmata 296 status = "timedout";
f7eb47b… lmata 297 else if (shardResult.status === "interrupted" && status !== "failed" && status !== "timedout")
f7eb47b… lmata 298 status = "interrupted";
f7eb47b… lmata 299 startTime = Math.min(startTime, shardResult.startTime);
f7eb47b… lmata 300 endTime = Math.max(endTime, shardResult.startTime + shardResult.duration);
f7eb47b… lmata 301 }
f7eb47b… lmata 302 const result = {
f7eb47b… lmata 303 status,
f7eb47b… lmata 304 startTime,
f7eb47b… lmata 305 duration: endTime - startTime
f7eb47b… lmata 306 };
f7eb47b… lmata 307 return {
f7eb47b… lmata 308 method: "onEnd",
f7eb47b… lmata 309 params: {
f7eb47b… lmata 310 result
f7eb47b… lmata 311 }
f7eb47b… lmata 312 };
f7eb47b… lmata 313 }
f7eb47b… lmata 314 async function sortedShardFiles(dir) {
f7eb47b… lmata 315 const files = await import_fs.default.promises.readdir(dir);
f7eb47b… lmata 316 return files.filter((file) => file.endsWith(".zip")).sort();
f7eb47b… lmata 317 }
f7eb47b… lmata 318 function printStatusToStdout(message) {
f7eb47b… lmata 319 process.stdout.write(`${message}
f7eb47b… lmata 320 `);
f7eb47b… lmata 321 }
f7eb47b… lmata 322 class UniqueFileNameGenerator {
f7eb47b… lmata 323 constructor() {
f7eb47b… lmata 324 this._usedNames = /* @__PURE__ */ new Set();
f7eb47b… lmata 325 }
f7eb47b… lmata 326 makeUnique(name) {
f7eb47b… lmata 327 if (!this._usedNames.has(name)) {
f7eb47b… lmata 328 this._usedNames.add(name);
f7eb47b… lmata 329 return name;
f7eb47b… lmata 330 }
f7eb47b… lmata 331 const extension = import_path.default.extname(name);
f7eb47b… lmata 332 name = name.substring(0, name.length - extension.length);
f7eb47b… lmata 333 let index = 0;
f7eb47b… lmata 334 while (true) {
f7eb47b… lmata 335 const candidate = `${name}-${++index}${extension}`;
f7eb47b… lmata 336 if (!this._usedNames.has(candidate)) {
f7eb47b… lmata 337 this._usedNames.add(candidate);
f7eb47b… lmata 338 return candidate;
f7eb47b… lmata 339 }
f7eb47b… lmata 340 }
f7eb47b… lmata 341 }
f7eb47b… lmata 342 }
f7eb47b… lmata 343 class IdsPatcher {
f7eb47b… lmata 344 constructor(stringPool, botName, salt, globalTestIdSet) {
f7eb47b… lmata 345 this._stringPool = stringPool;
f7eb47b… lmata 346 this._botName = botName;
f7eb47b… lmata 347 this._salt = salt;
f7eb47b… lmata 348 this._testIdsMap = /* @__PURE__ */ new Map();
f7eb47b… lmata 349 this._globalTestIdSet = globalTestIdSet;
f7eb47b… lmata 350 }
f7eb47b… lmata 351 patchEvent(event) {
f7eb47b… lmata 352 const { method, params } = event;
f7eb47b… lmata 353 switch (method) {
f7eb47b… lmata 354 case "onProject":
f7eb47b… lmata 355 this._onProject(params.project);
f7eb47b… lmata 356 return;
f7eb47b… lmata 357 case "onAttach":
f7eb47b… lmata 358 case "onTestBegin":
f7eb47b… lmata 359 case "onStepBegin":
f7eb47b… lmata 360 case "onStepEnd":
f7eb47b… lmata 361 case "onStdIO":
f7eb47b… lmata 362 params.testId = params.testId ? this._mapTestId(params.testId) : void 0;
f7eb47b… lmata 363 return;
f7eb47b… lmata 364 case "onTestEnd":
f7eb47b… lmata 365 params.test.testId = this._mapTestId(params.test.testId);
f7eb47b… lmata 366 return;
f7eb47b… lmata 367 }
f7eb47b… lmata 368 }
f7eb47b… lmata 369 _onProject(project) {
f7eb47b… lmata 370 project.metadata ??= {};
f7eb47b… lmata 371 project.suites.forEach((suite) => this._updateTestIds(suite));
f7eb47b… lmata 372 }
f7eb47b… lmata 373 _updateTestIds(suite) {
f7eb47b… lmata 374 suite.entries.forEach((entry) => {
f7eb47b… lmata 375 if ("testId" in entry)
f7eb47b… lmata 376 this._updateTestId(entry);
f7eb47b… lmata 377 else
f7eb47b… lmata 378 this._updateTestIds(entry);
f7eb47b… lmata 379 });
f7eb47b… lmata 380 }
f7eb47b… lmata 381 _updateTestId(test) {
f7eb47b… lmata 382 test.testId = this._mapTestId(test.testId);
f7eb47b… lmata 383 if (this._botName) {
f7eb47b… lmata 384 test.tags = test.tags || [];
f7eb47b… lmata 385 test.tags.unshift("@" + this._botName);
f7eb47b… lmata 386 }
f7eb47b… lmata 387 }
f7eb47b… lmata 388 _mapTestId(testId) {
f7eb47b… lmata 389 const t1 = this._stringPool.internString(testId);
f7eb47b… lmata 390 if (this._testIdsMap.has(t1))
f7eb47b… lmata 391 return this._testIdsMap.get(t1);
f7eb47b… lmata 392 if (this._globalTestIdSet.has(t1)) {
f7eb47b… lmata 393 const t2 = this._stringPool.internString(testId + this._salt);
f7eb47b… lmata 394 this._globalTestIdSet.add(t2);
f7eb47b… lmata 395 this._testIdsMap.set(t1, t2);
f7eb47b… lmata 396 return t2;
f7eb47b… lmata 397 }
f7eb47b… lmata 398 this._globalTestIdSet.add(t1);
f7eb47b… lmata 399 this._testIdsMap.set(t1, t1);
f7eb47b… lmata 400 return t1;
f7eb47b… lmata 401 }
f7eb47b… lmata 402 }
f7eb47b… lmata 403 class AttachmentPathPatcher {
f7eb47b… lmata 404 constructor(_resourceDir) {
f7eb47b… lmata 405 this._resourceDir = _resourceDir;
f7eb47b… lmata 406 }
f7eb47b… lmata 407 patchEvent(event) {
f7eb47b… lmata 408 if (event.method === "onAttach")
f7eb47b… lmata 409 this._patchAttachments(event.params.attachments);
f7eb47b… lmata 410 else if (event.method === "onTestEnd")
f7eb47b… lmata 411 this._patchAttachments(event.params.result.attachments ?? []);
f7eb47b… lmata 412 }
f7eb47b… lmata 413 _patchAttachments(attachments) {
f7eb47b… lmata 414 for (const attachment of attachments) {
f7eb47b… lmata 415 if (!attachment.path)
f7eb47b… lmata 416 continue;
f7eb47b… lmata 417 attachment.path = import_path.default.join(this._resourceDir, attachment.path);
f7eb47b… lmata 418 }
f7eb47b… lmata 419 }
f7eb47b… lmata 420 }
f7eb47b… lmata 421 class PathSeparatorPatcher {
f7eb47b… lmata 422 constructor(from) {
f7eb47b… lmata 423 this._from = from ?? (import_path.default.sep === "/" ? "\\" : "/");
f7eb47b… lmata 424 this._to = import_path.default.sep;
f7eb47b… lmata 425 }
f7eb47b… lmata 426 patchEvent(jsonEvent) {
f7eb47b… lmata 427 if (this._from === this._to)
f7eb47b… lmata 428 return;
f7eb47b… lmata 429 if (jsonEvent.method === "onProject") {
f7eb47b… lmata 430 this._updateProject(jsonEvent.params.project);
f7eb47b… lmata 431 return;
f7eb47b… lmata 432 }
f7eb47b… lmata 433 if (jsonEvent.method === "onTestEnd") {
f7eb47b… lmata 434 const test = jsonEvent.params.test;
f7eb47b… lmata 435 test.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
f7eb47b… lmata 436 const testResult = jsonEvent.params.result;
f7eb47b… lmata 437 testResult.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
f7eb47b… lmata 438 testResult.errors.forEach((error) => this._updateErrorLocations(error));
f7eb47b… lmata 439 (testResult.attachments ?? []).forEach((attachment) => {
f7eb47b… lmata 440 if (attachment.path)
f7eb47b… lmata 441 attachment.path = this._updatePath(attachment.path);
f7eb47b… lmata 442 });
f7eb47b… lmata 443 return;
f7eb47b… lmata 444 }
f7eb47b… lmata 445 if (jsonEvent.method === "onStepBegin") {
f7eb47b… lmata 446 const step = jsonEvent.params.step;
f7eb47b… lmata 447 this._updateLocation(step.location);
f7eb47b… lmata 448 return;
f7eb47b… lmata 449 }
f7eb47b… lmata 450 if (jsonEvent.method === "onStepEnd") {
f7eb47b… lmata 451 const step = jsonEvent.params.step;
f7eb47b… lmata 452 this._updateErrorLocations(step.error);
f7eb47b… lmata 453 step.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
f7eb47b… lmata 454 return;
f7eb47b… lmata 455 }
f7eb47b… lmata 456 if (jsonEvent.method === "onAttach") {
f7eb47b… lmata 457 const attach = jsonEvent.params;
f7eb47b… lmata 458 attach.attachments.forEach((attachment) => {
f7eb47b… lmata 459 if (attachment.path)
f7eb47b… lmata 460 attachment.path = this._updatePath(attachment.path);
f7eb47b… lmata 461 });
f7eb47b… lmata 462 return;
f7eb47b… lmata 463 }
f7eb47b… lmata 464 }
f7eb47b… lmata 465 _updateProject(project) {
f7eb47b… lmata 466 project.outputDir = this._updatePath(project.outputDir);
f7eb47b… lmata 467 project.testDir = this._updatePath(project.testDir);
f7eb47b… lmata 468 project.snapshotDir = this._updatePath(project.snapshotDir);
f7eb47b… lmata 469 project.suites.forEach((suite) => this._updateSuite(suite, true));
f7eb47b… lmata 470 }
f7eb47b… lmata 471 _updateSuite(suite, isFileSuite = false) {
f7eb47b… lmata 472 this._updateLocation(suite.location);
f7eb47b… lmata 473 if (isFileSuite)
f7eb47b… lmata 474 suite.title = this._updatePath(suite.title);
f7eb47b… lmata 475 for (const entry of suite.entries) {
f7eb47b… lmata 476 if ("testId" in entry) {
f7eb47b… lmata 477 this._updateLocation(entry.location);
f7eb47b… lmata 478 entry.annotations?.forEach((annotation) => this._updateAnnotationLocation(annotation));
f7eb47b… lmata 479 } else {
f7eb47b… lmata 480 this._updateSuite(entry);
f7eb47b… lmata 481 }
f7eb47b… lmata 482 }
f7eb47b… lmata 483 }
f7eb47b… lmata 484 _updateErrorLocations(error) {
f7eb47b… lmata 485 while (error) {
f7eb47b… lmata 486 this._updateLocation(error.location);
f7eb47b… lmata 487 error = error.cause;
f7eb47b… lmata 488 }
f7eb47b… lmata 489 }
f7eb47b… lmata 490 _updateAnnotationLocation(annotation) {
f7eb47b… lmata 491 this._updateLocation(annotation.location);
f7eb47b… lmata 492 }
f7eb47b… lmata 493 _updateLocation(location) {
f7eb47b… lmata 494 if (location)
f7eb47b… lmata 495 location.file = this._updatePath(location.file);
f7eb47b… lmata 496 }
f7eb47b… lmata 497 _updatePath(text) {
f7eb47b… lmata 498 return text.split(this._from).join(this._to);
f7eb47b… lmata 499 }
f7eb47b… lmata 500 }
f7eb47b… lmata 501 class GlobalErrorPatcher {
f7eb47b… lmata 502 constructor(botName) {
f7eb47b… lmata 503 this._prefix = `(${botName}) `;
f7eb47b… lmata 504 }
f7eb47b… lmata 505 patchEvent(event) {
f7eb47b… lmata 506 if (event.method !== "onError")
f7eb47b… lmata 507 return;
f7eb47b… lmata 508 const error = event.params.error;
f7eb47b… lmata 509 if (error.message !== void 0)
f7eb47b… lmata 510 error.message = this._prefix + error.message;
f7eb47b… lmata 511 if (error.stack !== void 0)
f7eb47b… lmata 512 error.stack = this._prefix + error.stack;
f7eb47b… lmata 513 }
f7eb47b… lmata 514 }
f7eb47b… lmata 515 class JsonEventPatchers {
f7eb47b… lmata 516 constructor() {
f7eb47b… lmata 517 this.patchers = [];
f7eb47b… lmata 518 }
f7eb47b… lmata 519 patchEvents(events) {
f7eb47b… lmata 520 for (const event of events) {
f7eb47b… lmata 521 for (const patcher of this.patchers)
f7eb47b… lmata 522 patcher.patchEvent(event);
f7eb47b… lmata 523 }
f7eb47b… lmata 524 }
f7eb47b… lmata 525 }
f7eb47b… lmata 526 class BlobModernizer {
f7eb47b… lmata 527 modernize(fromVersion, events) {
f7eb47b… lmata 528 const result = [];
f7eb47b… lmata 529 for (const event of events)
f7eb47b… lmata 530 result.push(...this._modernize(fromVersion, event));
f7eb47b… lmata 531 return result;
f7eb47b… lmata 532 }
f7eb47b… lmata 533 _modernize(fromVersion, event) {
f7eb47b… lmata 534 let events = [event];
f7eb47b… lmata 535 for (let version = fromVersion; version < import_blob.currentBlobReportVersion; ++version)
f7eb47b… lmata 536 events = this[`_modernize_${version}_to_${version + 1}`].call(this, events);
f7eb47b… lmata 537 return events;
f7eb47b… lmata 538 }
f7eb47b… lmata 539 _modernize_1_to_2(events) {
f7eb47b… lmata 540 return events.map((event) => {
f7eb47b… lmata 541 if (event.method === "onProject") {
f7eb47b… lmata 542 const modernizeSuite = (suite) => {
f7eb47b… lmata 543 const newSuites = suite.suites.map(modernizeSuite);
f7eb47b… lmata 544 const { suites, tests, ...remainder } = suite;
f7eb47b… lmata 545 return { entries: [...newSuites, ...tests], ...remainder };
f7eb47b… lmata 546 };
f7eb47b… lmata 547 const project = event.params.project;
f7eb47b… lmata 548 project.suites = project.suites.map(modernizeSuite);
f7eb47b… lmata 549 }
f7eb47b… lmata 550 return event;
f7eb47b… lmata 551 });
f7eb47b… lmata 552 }
f7eb47b… lmata 553 }
f7eb47b… lmata 554 const modernizer = new BlobModernizer();
f7eb47b… lmata 555 // Annotate the CommonJS export names for ESM import in node:
f7eb47b… lmata 556 0 && (module.exports = {
f7eb47b… lmata 557 createMergedReport
f7eb47b… lmata 558 });

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button