@flakiness/sdk 0.149.1 → 0.150.1
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/README.md +9 -4
- package/lib/_internalUtils.js +2 -68
- package/lib/browser.js +2 -149
- package/lib/ciUtils.js +0 -1
- package/lib/createEnvironment.js +1 -105
- package/lib/createTestStepSnippets.js +1 -19
- package/lib/flakinessProjectConfig.js +6 -317
- package/lib/gitWorktree.js +8 -112
- package/lib/index.js +9 -1244
- package/lib/normalizeReport.js +2 -3
- package/lib/reportUtils.js +9 -384
- package/lib/reportUtilsBrowser.js +3 -132
- package/lib/showReport.js +3 -612
- package/lib/staticServer.js +7 -8
- package/lib/stripAnsi.js +1 -2
- package/lib/systemUtilizationSampler.js +2 -3
- package/lib/uploadReport.js +33 -148
- package/lib/visitTests.js +0 -1
- package/lib/writeReport.js +0 -1
- package/package.json +14 -5
- package/types/src/_internalUtils.d.ts +13 -0
- package/types/src/_internalUtils.d.ts.map +1 -0
- package/types/src/browser.d.ts +3 -0
- package/types/src/browser.d.ts.map +1 -0
- package/types/src/ciUtils.d.ts +33 -0
- package/types/src/ciUtils.d.ts.map +1 -0
- package/types/src/createEnvironment.d.ts +40 -0
- package/types/src/createEnvironment.d.ts.map +1 -0
- package/types/src/createTestStepSnippets.d.ts +30 -0
- package/types/src/createTestStepSnippets.d.ts.map +1 -0
- package/types/src/flakinessProjectConfig.d.ts +103 -0
- package/types/src/flakinessProjectConfig.d.ts.map +1 -0
- package/types/src/gitWorktree.d.ts +139 -0
- package/types/src/gitWorktree.d.ts.map +1 -0
- package/types/src/index.d.ts +10 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/normalizeReport.d.ts +26 -0
- package/types/src/normalizeReport.d.ts.map +1 -0
- package/types/src/reportUtils.d.ts +8 -0
- package/types/src/reportUtils.d.ts.map +1 -0
- package/types/src/reportUtilsBrowser.d.ts +4 -0
- package/types/src/reportUtilsBrowser.d.ts.map +1 -0
- package/types/src/showReport.d.ts +18 -0
- package/types/src/showReport.d.ts.map +1 -0
- package/types/src/staticServer.d.ts +16 -0
- package/types/src/staticServer.d.ts.map +1 -0
- package/types/src/stripAnsi.d.ts +19 -0
- package/types/src/stripAnsi.d.ts.map +1 -0
- package/types/src/systemUtilizationSampler.d.ts +43 -0
- package/types/src/systemUtilizationSampler.d.ts.map +1 -0
- package/types/src/uploadReport.d.ts +196 -0
- package/types/src/uploadReport.d.ts.map +1 -0
- package/types/src/visitTests.d.ts +28 -0
- package/types/src/visitTests.d.ts.map +1 -0
- package/types/src/writeReport.d.ts +45 -0
- package/types/src/writeReport.d.ts.map +1 -0
- package/types/tsconfig.tsbuildinfo +0 -1
package/lib/normalizeReport.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// src/normalizeReport.ts
|
|
2
1
|
import stableObjectHash from "stable-hash";
|
|
3
|
-
|
|
2
|
+
class Multimap {
|
|
4
3
|
_map = /* @__PURE__ */ new Map();
|
|
5
4
|
set(key, value) {
|
|
6
5
|
const set = this._map.get(key) ?? /* @__PURE__ */ new Set();
|
|
@@ -10,7 +9,7 @@ var Multimap = class {
|
|
|
10
9
|
getAll(key) {
|
|
11
10
|
return Array.from(this._map.get(key) ?? []);
|
|
12
11
|
}
|
|
13
|
-
}
|
|
12
|
+
}
|
|
14
13
|
function normalizeReport(report) {
|
|
15
14
|
const gEnvs = /* @__PURE__ */ new Map();
|
|
16
15
|
const gSuites = /* @__PURE__ */ new Map();
|
package/lib/reportUtils.js
CHANGED
|
@@ -1,387 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import https from "https";
|
|
11
|
-
import util from "util";
|
|
12
|
-
import zlib from "zlib";
|
|
13
|
-
var asyncBrotliCompress = util.promisify(zlib.brotliCompress);
|
|
14
|
-
var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
|
|
15
|
-
function errorText(error) {
|
|
16
|
-
return FLAKINESS_DBG ? error.stack : error.message;
|
|
17
|
-
}
|
|
18
|
-
async function retryWithBackoff(job, backoff = []) {
|
|
19
|
-
for (const timeout of backoff) {
|
|
20
|
-
try {
|
|
21
|
-
return await job();
|
|
22
|
-
} catch (e) {
|
|
23
|
-
if (e instanceof AggregateError)
|
|
24
|
-
console.error(`[flakiness.io err]`, errorText(e.errors[0]));
|
|
25
|
-
else if (e instanceof Error)
|
|
26
|
-
console.error(`[flakiness.io err]`, errorText(e));
|
|
27
|
-
else
|
|
28
|
-
console.error(`[flakiness.io err]`, e);
|
|
29
|
-
await new Promise((x) => setTimeout(x, timeout));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return await job();
|
|
33
|
-
}
|
|
34
|
-
var httpUtils;
|
|
35
|
-
((httpUtils2) => {
|
|
36
|
-
function createRequest({ url, method = "get", headers = {} }) {
|
|
37
|
-
let resolve;
|
|
38
|
-
let reject;
|
|
39
|
-
const responseDataPromise = new Promise((a, b) => {
|
|
40
|
-
resolve = a;
|
|
41
|
-
reject = b;
|
|
42
|
-
});
|
|
43
|
-
const protocol = url.startsWith("https") ? https : http;
|
|
44
|
-
headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
|
|
45
|
-
const request = protocol.request(url, { method, headers }, (res) => {
|
|
46
|
-
const chunks = [];
|
|
47
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
48
|
-
res.on("end", () => {
|
|
49
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300)
|
|
50
|
-
resolve(Buffer.concat(chunks));
|
|
51
|
-
else
|
|
52
|
-
reject(new Error(`Request to ${url} failed with ${res.statusCode}`));
|
|
53
|
-
});
|
|
54
|
-
res.on("error", (error) => reject(error));
|
|
55
|
-
});
|
|
56
|
-
request.on("error", reject);
|
|
57
|
-
return { request, responseDataPromise };
|
|
58
|
-
}
|
|
59
|
-
httpUtils2.createRequest = createRequest;
|
|
60
|
-
async function getBuffer(url, backoff) {
|
|
61
|
-
return await retryWithBackoff(async () => {
|
|
62
|
-
const { request, responseDataPromise } = createRequest({ url });
|
|
63
|
-
request.end();
|
|
64
|
-
return await responseDataPromise;
|
|
65
|
-
}, backoff);
|
|
66
|
-
}
|
|
67
|
-
httpUtils2.getBuffer = getBuffer;
|
|
68
|
-
async function getText(url, backoff) {
|
|
69
|
-
const buffer = await getBuffer(url, backoff);
|
|
70
|
-
return buffer.toString("utf-8");
|
|
71
|
-
}
|
|
72
|
-
httpUtils2.getText = getText;
|
|
73
|
-
async function getJSON(url) {
|
|
74
|
-
return JSON.parse(await getText(url));
|
|
75
|
-
}
|
|
76
|
-
httpUtils2.getJSON = getJSON;
|
|
77
|
-
async function postText(url, text, backoff) {
|
|
78
|
-
const headers = {
|
|
79
|
-
"Content-Type": "application/json",
|
|
80
|
-
"Content-Length": Buffer.byteLength(text) + ""
|
|
81
|
-
};
|
|
82
|
-
return await retryWithBackoff(async () => {
|
|
83
|
-
const { request, responseDataPromise } = createRequest({ url, headers, method: "post" });
|
|
84
|
-
request.write(text);
|
|
85
|
-
request.end();
|
|
86
|
-
return await responseDataPromise;
|
|
87
|
-
}, backoff);
|
|
88
|
-
}
|
|
89
|
-
httpUtils2.postText = postText;
|
|
90
|
-
async function postJSON(url, json, backoff) {
|
|
91
|
-
const buffer = await postText(url, JSON.stringify(json), backoff);
|
|
92
|
-
return JSON.parse(buffer.toString("utf-8"));
|
|
93
|
-
}
|
|
94
|
-
httpUtils2.postJSON = postJSON;
|
|
95
|
-
})(httpUtils || (httpUtils = {}));
|
|
96
|
-
function shell(command, args, options) {
|
|
97
|
-
try {
|
|
98
|
-
const result = spawnSync(command, args, { encoding: "utf-8", ...options });
|
|
99
|
-
if (result.status !== 0) {
|
|
100
|
-
return void 0;
|
|
101
|
-
}
|
|
102
|
-
return result.stdout.trim();
|
|
103
|
-
} catch (e) {
|
|
104
|
-
console.error(e);
|
|
105
|
-
return void 0;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function sha1Text(data) {
|
|
109
|
-
const hash = crypto.createHash("sha1");
|
|
110
|
-
hash.update(data);
|
|
111
|
-
return hash.digest("hex");
|
|
112
|
-
}
|
|
113
|
-
function sha1File(filePath) {
|
|
114
|
-
return new Promise((resolve, reject) => {
|
|
115
|
-
const hash = crypto.createHash("sha1");
|
|
116
|
-
const stream = fs.createReadStream(filePath);
|
|
117
|
-
stream.on("data", (chunk) => {
|
|
118
|
-
hash.update(chunk);
|
|
119
|
-
});
|
|
120
|
-
stream.on("end", () => {
|
|
121
|
-
resolve(hash.digest("hex"));
|
|
122
|
-
});
|
|
123
|
-
stream.on("error", (err) => {
|
|
124
|
-
reject(err);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// src/createEnvironment.ts
|
|
130
|
-
function readLinuxOSRelease() {
|
|
131
|
-
const osReleaseText = fs2.readFileSync("/etc/os-release", "utf-8");
|
|
132
|
-
return new Map(osReleaseText.toLowerCase().split("\n").filter((line) => line.includes("=")).map((line) => {
|
|
133
|
-
line = line.trim();
|
|
134
|
-
let [key, value] = line.split("=");
|
|
135
|
-
if (value.startsWith('"') && value.endsWith('"'))
|
|
136
|
-
value = value.substring(1, value.length - 1);
|
|
137
|
-
return [key, value];
|
|
138
|
-
}));
|
|
139
|
-
}
|
|
140
|
-
function osLinuxInfo() {
|
|
141
|
-
const arch = shell(`uname`, [`-m`]);
|
|
142
|
-
const osReleaseMap = readLinuxOSRelease();
|
|
143
|
-
const name = osReleaseMap.get("name") ?? shell(`uname`);
|
|
144
|
-
const version = osReleaseMap.get("version_id");
|
|
145
|
-
return { name, arch, version };
|
|
146
|
-
}
|
|
147
|
-
function osDarwinInfo() {
|
|
148
|
-
const name = "macos";
|
|
149
|
-
const arch = shell(`uname`, [`-m`]);
|
|
150
|
-
const version = shell(`sw_vers`, [`-productVersion`]);
|
|
151
|
-
return { name, arch, version };
|
|
152
|
-
}
|
|
153
|
-
function osWinInfo() {
|
|
154
|
-
const name = "win";
|
|
155
|
-
const arch = process.arch;
|
|
156
|
-
const version = os.release();
|
|
157
|
-
return { name, arch, version };
|
|
158
|
-
}
|
|
159
|
-
function getOSInfo() {
|
|
160
|
-
if (process.platform === "darwin")
|
|
161
|
-
return osDarwinInfo();
|
|
162
|
-
if (process.platform === "win32")
|
|
163
|
-
return osWinInfo();
|
|
164
|
-
return osLinuxInfo();
|
|
165
|
-
}
|
|
166
|
-
function extractEnvConfiguration() {
|
|
167
|
-
const ENV_PREFIX = "FK_ENV_";
|
|
168
|
-
return Object.fromEntries(
|
|
169
|
-
Object.entries(process.env).filter(([key]) => key.toUpperCase().startsWith(ENV_PREFIX.toUpperCase())).map(([key, value]) => [key.substring(ENV_PREFIX.length).toLowerCase(), (value ?? "").trim().toLowerCase()])
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
function createEnvironment(options) {
|
|
173
|
-
const osInfo = getOSInfo();
|
|
174
|
-
return {
|
|
175
|
-
name: options.name,
|
|
176
|
-
systemData: {
|
|
177
|
-
osArch: osInfo.arch,
|
|
178
|
-
osName: osInfo.name,
|
|
179
|
-
osVersion: osInfo.version
|
|
180
|
-
},
|
|
181
|
-
userSuppliedData: {
|
|
182
|
-
...extractEnvConfiguration(),
|
|
183
|
-
...options.userSuppliedData ?? {}
|
|
184
|
-
},
|
|
185
|
-
opaqueData: options.opaqueData
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// src/createTestStepSnippets.ts
|
|
190
|
-
import { codeFrameColumns } from "@babel/code-frame";
|
|
191
|
-
import fs3 from "fs";
|
|
192
|
-
|
|
193
|
-
// src/visitTests.ts
|
|
194
|
-
function visitTests(report, testVisitor) {
|
|
195
|
-
function visitSuite(suite, parents) {
|
|
196
|
-
parents.push(suite);
|
|
197
|
-
for (const test of suite.tests ?? [])
|
|
198
|
-
testVisitor(test, parents);
|
|
199
|
-
for (const childSuite of suite.suites ?? [])
|
|
200
|
-
visitSuite(childSuite, parents);
|
|
201
|
-
parents.pop();
|
|
202
|
-
}
|
|
203
|
-
for (const test of report.tests ?? [])
|
|
204
|
-
testVisitor(test, []);
|
|
205
|
-
for (const suite of report.suites)
|
|
206
|
-
visitSuite(suite, []);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// src/createTestStepSnippets.ts
|
|
210
|
-
function createTestStepSnippetsInplace(worktree, report) {
|
|
211
|
-
const allSteps = /* @__PURE__ */ new Map();
|
|
212
|
-
visitTests(report, (test) => {
|
|
213
|
-
for (const attempt of test.attempts) {
|
|
214
|
-
for (const step of attempt.steps ?? []) {
|
|
215
|
-
if (!step.location)
|
|
216
|
-
continue;
|
|
217
|
-
let fileSteps = allSteps.get(step.location.file);
|
|
218
|
-
if (!fileSteps) {
|
|
219
|
-
fileSteps = /* @__PURE__ */ new Set();
|
|
220
|
-
allSteps.set(step.location.file, fileSteps);
|
|
221
|
-
}
|
|
222
|
-
fileSteps.add(step);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
for (const [gitFilePath, steps] of allSteps) {
|
|
227
|
-
let source;
|
|
228
|
-
try {
|
|
229
|
-
source = fs3.readFileSync(worktree.absolutePath(gitFilePath), "utf-8");
|
|
230
|
-
} catch (e) {
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const lines = source.split("\n").length;
|
|
234
|
-
const highlighted = codeFrameColumns(source, { start: { line: lines, column: 1 } }, { highlightCode: true, linesAbove: lines, linesBelow: 0 });
|
|
235
|
-
const highlightedLines = highlighted.split("\n");
|
|
236
|
-
const lineWithArrow = highlightedLines[highlightedLines.length - 1];
|
|
237
|
-
for (const step of steps) {
|
|
238
|
-
if (!step.location)
|
|
239
|
-
continue;
|
|
240
|
-
if (step.location.line < 2 || step.location.line >= lines)
|
|
241
|
-
continue;
|
|
242
|
-
const snippetLines = highlightedLines.slice(step.location.line - 2, step.location.line + 1);
|
|
243
|
-
const index = lineWithArrow.indexOf("^");
|
|
244
|
-
const shiftedArrow = lineWithArrow.slice(0, index) + " ".repeat(step.location.column - 1) + lineWithArrow.slice(index);
|
|
245
|
-
snippetLines.splice(2, 0, shiftedArrow);
|
|
246
|
-
step.snippet = snippetLines.join("\n");
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// src/normalizeReport.ts
|
|
252
|
-
import stableObjectHash from "stable-hash";
|
|
253
|
-
var Multimap = class {
|
|
254
|
-
_map = /* @__PURE__ */ new Map();
|
|
255
|
-
set(key, value) {
|
|
256
|
-
const set = this._map.get(key) ?? /* @__PURE__ */ new Set();
|
|
257
|
-
this._map.set(key, set);
|
|
258
|
-
set.add(value);
|
|
259
|
-
}
|
|
260
|
-
getAll(key) {
|
|
261
|
-
return Array.from(this._map.get(key) ?? []);
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
function normalizeReport(report) {
|
|
265
|
-
const gEnvs = /* @__PURE__ */ new Map();
|
|
266
|
-
const gSuites = /* @__PURE__ */ new Map();
|
|
267
|
-
const gTests = new Multimap();
|
|
268
|
-
const gSuiteIds = /* @__PURE__ */ new Map();
|
|
269
|
-
const gTestIds = /* @__PURE__ */ new Map();
|
|
270
|
-
const gEnvIds = /* @__PURE__ */ new Map();
|
|
271
|
-
const gSuiteChildren = new Multimap();
|
|
272
|
-
const gSuiteTests = new Multimap();
|
|
273
|
-
for (const env of report.environments) {
|
|
274
|
-
const envId = computeEnvId(env);
|
|
275
|
-
gEnvs.set(envId, env);
|
|
276
|
-
gEnvIds.set(env, envId);
|
|
277
|
-
}
|
|
278
|
-
const usedEnvIds = /* @__PURE__ */ new Set();
|
|
279
|
-
function visitTests2(tests, suiteId) {
|
|
280
|
-
for (const test of tests ?? []) {
|
|
281
|
-
const testId = computeTestId(test, suiteId);
|
|
282
|
-
gTests.set(testId, test);
|
|
283
|
-
gTestIds.set(test, testId);
|
|
284
|
-
gSuiteTests.set(suiteId, test);
|
|
285
|
-
for (const attempt of test.attempts) {
|
|
286
|
-
const env = report.environments[attempt.environmentIdx];
|
|
287
|
-
const envId = gEnvIds.get(env);
|
|
288
|
-
usedEnvIds.add(envId);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
function visitSuite(suite, parentSuiteId) {
|
|
293
|
-
const suiteId = computeSuiteId(suite, parentSuiteId);
|
|
294
|
-
gSuites.set(suiteId, suite);
|
|
295
|
-
gSuiteIds.set(suite, suiteId);
|
|
296
|
-
for (const childSuite of suite.suites ?? []) {
|
|
297
|
-
visitSuite(childSuite, suiteId);
|
|
298
|
-
gSuiteChildren.set(suiteId, childSuite);
|
|
299
|
-
}
|
|
300
|
-
visitTests2(suite.tests ?? [], suiteId);
|
|
301
|
-
}
|
|
302
|
-
function transformTests(tests) {
|
|
303
|
-
const testIds = new Set(tests.map((test) => gTestIds.get(test)));
|
|
304
|
-
return [...testIds].map((testId) => {
|
|
305
|
-
const tests2 = gTests.getAll(testId);
|
|
306
|
-
const tags = tests2.map((test) => test.tags ?? []).flat();
|
|
307
|
-
return {
|
|
308
|
-
location: tests2[0].location,
|
|
309
|
-
title: tests2[0].title,
|
|
310
|
-
tags: tags.length ? tags : void 0,
|
|
311
|
-
attempts: tests2.map((t) => t.attempts).flat().map((attempt) => ({
|
|
312
|
-
...attempt,
|
|
313
|
-
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx]))
|
|
314
|
-
}))
|
|
315
|
-
};
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
function transformSuites(suites) {
|
|
319
|
-
const suiteIds = new Set(suites.map((suite) => gSuiteIds.get(suite)));
|
|
320
|
-
return [...suiteIds].map((suiteId) => {
|
|
321
|
-
const suite = gSuites.get(suiteId);
|
|
322
|
-
return {
|
|
323
|
-
location: suite.location,
|
|
324
|
-
title: suite.title,
|
|
325
|
-
type: suite.type,
|
|
326
|
-
suites: transformSuites(gSuiteChildren.getAll(suiteId)),
|
|
327
|
-
tests: transformTests(gSuiteTests.getAll(suiteId))
|
|
328
|
-
};
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
visitTests2(report.tests ?? [], "suiteless");
|
|
332
|
-
for (const suite of report.suites)
|
|
333
|
-
visitSuite(suite);
|
|
334
|
-
const newEnvironments = [...usedEnvIds];
|
|
335
|
-
const envIdToIndex = new Map(newEnvironments.map((envId, index) => [envId, index]));
|
|
336
|
-
return {
|
|
337
|
-
...report,
|
|
338
|
-
environments: newEnvironments.map((envId) => gEnvs.get(envId)),
|
|
339
|
-
suites: transformSuites(report.suites),
|
|
340
|
-
tests: transformTests(report.tests ?? [])
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
function computeEnvId(env) {
|
|
344
|
-
return stableObjectHash(env);
|
|
345
|
-
}
|
|
346
|
-
function computeSuiteId(suite, parentSuiteId) {
|
|
347
|
-
return stableObjectHash({
|
|
348
|
-
parentSuiteId: parentSuiteId ?? "",
|
|
349
|
-
type: suite.type,
|
|
350
|
-
file: suite.location?.file ?? "",
|
|
351
|
-
title: suite.title
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
function computeTestId(test, suiteId) {
|
|
355
|
-
return stableObjectHash({
|
|
356
|
-
suiteId,
|
|
357
|
-
file: test.location?.file ?? "",
|
|
358
|
-
title: test.title
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/stripAnsi.ts
|
|
363
|
-
var ansiRegex = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))", "g");
|
|
364
|
-
function stripAnsi(str) {
|
|
365
|
-
return str.replace(ansiRegex, "");
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// src/uploadReport.ts
|
|
369
|
-
async function createFileAttachment(contentType, filePath) {
|
|
370
|
-
return {
|
|
371
|
-
type: "file",
|
|
372
|
-
contentType,
|
|
373
|
-
id: await sha1File(filePath),
|
|
374
|
-
path: filePath
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
async function createDataAttachment(contentType, data) {
|
|
378
|
-
return {
|
|
379
|
-
type: "buffer",
|
|
380
|
-
contentType,
|
|
381
|
-
id: sha1Text(data),
|
|
382
|
-
body: data
|
|
383
|
-
};
|
|
384
|
-
}
|
|
1
|
+
import { createEnvironment } from "./createEnvironment.js";
|
|
2
|
+
import { createTestStepSnippetsInplace } from "./createTestStepSnippets.js";
|
|
3
|
+
import { normalizeReport } from "./normalizeReport.js";
|
|
4
|
+
import { stripAnsi } from "./stripAnsi.js";
|
|
5
|
+
import {
|
|
6
|
+
createDataAttachment,
|
|
7
|
+
createFileAttachment
|
|
8
|
+
} from "./uploadReport.js";
|
|
9
|
+
import { visitTests } from "./visitTests.js";
|
|
385
10
|
export {
|
|
386
11
|
createDataAttachment,
|
|
387
12
|
createEnvironment,
|
|
@@ -1,135 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
_map = /* @__PURE__ */ new Map();
|
|
5
|
-
set(key, value) {
|
|
6
|
-
const set = this._map.get(key) ?? /* @__PURE__ */ new Set();
|
|
7
|
-
this._map.set(key, set);
|
|
8
|
-
set.add(value);
|
|
9
|
-
}
|
|
10
|
-
getAll(key) {
|
|
11
|
-
return Array.from(this._map.get(key) ?? []);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
function normalizeReport(report) {
|
|
15
|
-
const gEnvs = /* @__PURE__ */ new Map();
|
|
16
|
-
const gSuites = /* @__PURE__ */ new Map();
|
|
17
|
-
const gTests = new Multimap();
|
|
18
|
-
const gSuiteIds = /* @__PURE__ */ new Map();
|
|
19
|
-
const gTestIds = /* @__PURE__ */ new Map();
|
|
20
|
-
const gEnvIds = /* @__PURE__ */ new Map();
|
|
21
|
-
const gSuiteChildren = new Multimap();
|
|
22
|
-
const gSuiteTests = new Multimap();
|
|
23
|
-
for (const env of report.environments) {
|
|
24
|
-
const envId = computeEnvId(env);
|
|
25
|
-
gEnvs.set(envId, env);
|
|
26
|
-
gEnvIds.set(env, envId);
|
|
27
|
-
}
|
|
28
|
-
const usedEnvIds = /* @__PURE__ */ new Set();
|
|
29
|
-
function visitTests2(tests, suiteId) {
|
|
30
|
-
for (const test of tests ?? []) {
|
|
31
|
-
const testId = computeTestId(test, suiteId);
|
|
32
|
-
gTests.set(testId, test);
|
|
33
|
-
gTestIds.set(test, testId);
|
|
34
|
-
gSuiteTests.set(suiteId, test);
|
|
35
|
-
for (const attempt of test.attempts) {
|
|
36
|
-
const env = report.environments[attempt.environmentIdx];
|
|
37
|
-
const envId = gEnvIds.get(env);
|
|
38
|
-
usedEnvIds.add(envId);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function visitSuite(suite, parentSuiteId) {
|
|
43
|
-
const suiteId = computeSuiteId(suite, parentSuiteId);
|
|
44
|
-
gSuites.set(suiteId, suite);
|
|
45
|
-
gSuiteIds.set(suite, suiteId);
|
|
46
|
-
for (const childSuite of suite.suites ?? []) {
|
|
47
|
-
visitSuite(childSuite, suiteId);
|
|
48
|
-
gSuiteChildren.set(suiteId, childSuite);
|
|
49
|
-
}
|
|
50
|
-
visitTests2(suite.tests ?? [], suiteId);
|
|
51
|
-
}
|
|
52
|
-
function transformTests(tests) {
|
|
53
|
-
const testIds = new Set(tests.map((test) => gTestIds.get(test)));
|
|
54
|
-
return [...testIds].map((testId) => {
|
|
55
|
-
const tests2 = gTests.getAll(testId);
|
|
56
|
-
const tags = tests2.map((test) => test.tags ?? []).flat();
|
|
57
|
-
return {
|
|
58
|
-
location: tests2[0].location,
|
|
59
|
-
title: tests2[0].title,
|
|
60
|
-
tags: tags.length ? tags : void 0,
|
|
61
|
-
attempts: tests2.map((t) => t.attempts).flat().map((attempt) => ({
|
|
62
|
-
...attempt,
|
|
63
|
-
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx]))
|
|
64
|
-
}))
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
function transformSuites(suites) {
|
|
69
|
-
const suiteIds = new Set(suites.map((suite) => gSuiteIds.get(suite)));
|
|
70
|
-
return [...suiteIds].map((suiteId) => {
|
|
71
|
-
const suite = gSuites.get(suiteId);
|
|
72
|
-
return {
|
|
73
|
-
location: suite.location,
|
|
74
|
-
title: suite.title,
|
|
75
|
-
type: suite.type,
|
|
76
|
-
suites: transformSuites(gSuiteChildren.getAll(suiteId)),
|
|
77
|
-
tests: transformTests(gSuiteTests.getAll(suiteId))
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
visitTests2(report.tests ?? [], "suiteless");
|
|
82
|
-
for (const suite of report.suites)
|
|
83
|
-
visitSuite(suite);
|
|
84
|
-
const newEnvironments = [...usedEnvIds];
|
|
85
|
-
const envIdToIndex = new Map(newEnvironments.map((envId, index) => [envId, index]));
|
|
86
|
-
return {
|
|
87
|
-
...report,
|
|
88
|
-
environments: newEnvironments.map((envId) => gEnvs.get(envId)),
|
|
89
|
-
suites: transformSuites(report.suites),
|
|
90
|
-
tests: transformTests(report.tests ?? [])
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function computeEnvId(env) {
|
|
94
|
-
return stableObjectHash(env);
|
|
95
|
-
}
|
|
96
|
-
function computeSuiteId(suite, parentSuiteId) {
|
|
97
|
-
return stableObjectHash({
|
|
98
|
-
parentSuiteId: parentSuiteId ?? "",
|
|
99
|
-
type: suite.type,
|
|
100
|
-
file: suite.location?.file ?? "",
|
|
101
|
-
title: suite.title
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
function computeTestId(test, suiteId) {
|
|
105
|
-
return stableObjectHash({
|
|
106
|
-
suiteId,
|
|
107
|
-
file: test.location?.file ?? "",
|
|
108
|
-
title: test.title
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// src/stripAnsi.ts
|
|
113
|
-
var ansiRegex = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))", "g");
|
|
114
|
-
function stripAnsi(str) {
|
|
115
|
-
return str.replace(ansiRegex, "");
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// src/visitTests.ts
|
|
119
|
-
function visitTests(report, testVisitor) {
|
|
120
|
-
function visitSuite(suite, parents) {
|
|
121
|
-
parents.push(suite);
|
|
122
|
-
for (const test of suite.tests ?? [])
|
|
123
|
-
testVisitor(test, parents);
|
|
124
|
-
for (const childSuite of suite.suites ?? [])
|
|
125
|
-
visitSuite(childSuite, parents);
|
|
126
|
-
parents.pop();
|
|
127
|
-
}
|
|
128
|
-
for (const test of report.tests ?? [])
|
|
129
|
-
testVisitor(test, []);
|
|
130
|
-
for (const suite of report.suites)
|
|
131
|
-
visitSuite(suite, []);
|
|
132
|
-
}
|
|
1
|
+
import { normalizeReport } from "./normalizeReport.js";
|
|
2
|
+
import { stripAnsi } from "./stripAnsi.js";
|
|
3
|
+
import { visitTests } from "./visitTests.js";
|
|
133
4
|
export {
|
|
134
5
|
normalizeReport,
|
|
135
6
|
stripAnsi,
|