@flakiness/sdk 0.129.4 → 0.131.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/lib/cli/cli.js +179 -90
- package/lib/cli/cmd-convert.js +35 -24
- package/lib/cli/cmd-link.js +79 -4
- package/lib/cli/cmd-login.js +6 -3
- package/lib/cli/cmd-show-report.js +45 -21
- package/lib/junit.js +3 -3
- package/lib/localReportApi.js +207 -5
- package/lib/localReportServer.js +76 -52
- package/lib/playwright-test.js +87 -58
- package/lib/utils.js +24 -0
- package/package.json +10 -5
- package/types/tsconfig.tsbuildinfo +1 -1
package/lib/localReportServer.js
CHANGED
|
@@ -7,9 +7,14 @@ import compression from "compression";
|
|
|
7
7
|
import debug from "debug";
|
|
8
8
|
import express from "express";
|
|
9
9
|
import "express-async-errors";
|
|
10
|
-
import fs3 from "fs";
|
|
11
10
|
import http2 from "http";
|
|
12
11
|
|
|
12
|
+
// src/localReportApi.ts
|
|
13
|
+
import { TypedHTTP } from "@flakiness/shared/common/typedHttp.js";
|
|
14
|
+
import fs2 from "fs";
|
|
15
|
+
import path2 from "path";
|
|
16
|
+
import { z } from "zod/v4";
|
|
17
|
+
|
|
13
18
|
// src/localGit.ts
|
|
14
19
|
import { exec } from "child_process";
|
|
15
20
|
import { promisify } from "util";
|
|
@@ -50,46 +55,9 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
// src/localReportApi.ts
|
|
54
|
-
import { TypedHTTP } from "@flakiness/shared/common/typedHttp.js";
|
|
55
|
-
import fs from "fs";
|
|
56
|
-
import { z } from "zod/v4";
|
|
57
|
-
var t = TypedHTTP.Router.create();
|
|
58
|
-
var localReportRouter = {
|
|
59
|
-
ping: t.get({
|
|
60
|
-
handler: async () => {
|
|
61
|
-
return "pong";
|
|
62
|
-
}
|
|
63
|
-
}),
|
|
64
|
-
lastCommits: t.get({
|
|
65
|
-
handler: async ({ ctx }) => {
|
|
66
|
-
return ctx.commits;
|
|
67
|
-
}
|
|
68
|
-
}),
|
|
69
|
-
report: {
|
|
70
|
-
attachment: t.rawMethod("GET", {
|
|
71
|
-
input: z.object({
|
|
72
|
-
attachmentId: z.string().min(1).max(100).transform((id) => id)
|
|
73
|
-
}),
|
|
74
|
-
handler: async ({ ctx, input }) => {
|
|
75
|
-
const idx = ctx.attachmentIdToPath.get(input.attachmentId);
|
|
76
|
-
if (!idx)
|
|
77
|
-
throw TypedHTTP.HttpError.withCode("NOT_FOUND");
|
|
78
|
-
const buffer = await fs.promises.readFile(idx.path);
|
|
79
|
-
return TypedHTTP.ok(buffer, idx.contentType);
|
|
80
|
-
}
|
|
81
|
-
}),
|
|
82
|
-
json: t.get({
|
|
83
|
-
handler: async ({ ctx }) => {
|
|
84
|
-
return ctx.report;
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
58
|
// src/utils.ts
|
|
91
59
|
import { ReportUtils } from "@flakiness/report";
|
|
92
|
-
import
|
|
60
|
+
import fs from "fs";
|
|
93
61
|
import http from "http";
|
|
94
62
|
import https from "https";
|
|
95
63
|
import path, { posix as posixPath, win32 as win32Path } from "path";
|
|
@@ -200,7 +168,7 @@ async function resolveAttachmentPaths(report, attachmentsDir) {
|
|
|
200
168
|
return { attachmentIdToPath, missingAttachments: Array.from(missingAttachments) };
|
|
201
169
|
}
|
|
202
170
|
async function listFilesRecursively(dir, result = []) {
|
|
203
|
-
const entries = await
|
|
171
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
204
172
|
for (const entry of entries) {
|
|
205
173
|
const fullPath = path.join(dir, entry.name);
|
|
206
174
|
if (entry.isDirectory())
|
|
@@ -213,17 +181,27 @@ async function listFilesRecursively(dir, result = []) {
|
|
|
213
181
|
var IS_WIN32_PATH = new RegExp("^[a-zA-Z]:\\\\", "i");
|
|
214
182
|
var IS_ALMOST_POSIX_PATH = new RegExp("^[a-zA-Z]:/", "i");
|
|
215
183
|
|
|
216
|
-
// src/
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
this._server = _server;
|
|
221
|
-
this._port = _port;
|
|
222
|
-
this._authToken = _authToken;
|
|
184
|
+
// src/localReportApi.ts
|
|
185
|
+
var ReportInfo = class {
|
|
186
|
+
constructor(_options) {
|
|
187
|
+
this._options = _options;
|
|
223
188
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
189
|
+
report;
|
|
190
|
+
attachmentIdToPath = /* @__PURE__ */ new Map();
|
|
191
|
+
commits = [];
|
|
192
|
+
async refresh() {
|
|
193
|
+
const report = await fs2.promises.readFile(this._options.reportPath, "utf-8").then((x) => JSON.parse(x)).catch((e) => void 0);
|
|
194
|
+
if (!report) {
|
|
195
|
+
this.report = void 0;
|
|
196
|
+
this.commits = [];
|
|
197
|
+
this.attachmentIdToPath = /* @__PURE__ */ new Map();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (JSON.stringify(report) === JSON.stringify(this.report))
|
|
201
|
+
return;
|
|
202
|
+
this.report = report;
|
|
203
|
+
this.commits = await listLocalCommits(path2.dirname(this._options.reportPath), report.commitId, 100);
|
|
204
|
+
const attachmentsDir = this._options.attachmentsFolder;
|
|
227
205
|
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
228
206
|
if (missingAttachments.length) {
|
|
229
207
|
const first = missingAttachments.slice(0, 3);
|
|
@@ -232,7 +210,52 @@ var LocalReportServer = class _LocalReportServer {
|
|
|
232
210
|
if (missingAttachments.length > 3)
|
|
233
211
|
console.warn(`...and ${missingAttachments.length - 3} more missing attachments.`);
|
|
234
212
|
}
|
|
235
|
-
|
|
213
|
+
this.attachmentIdToPath = attachmentIdToPath;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
var t = TypedHTTP.Router.create();
|
|
217
|
+
var localReportRouter = {
|
|
218
|
+
ping: t.get({
|
|
219
|
+
handler: async () => {
|
|
220
|
+
return "pong";
|
|
221
|
+
}
|
|
222
|
+
}),
|
|
223
|
+
lastCommits: t.get({
|
|
224
|
+
handler: async ({ ctx }) => {
|
|
225
|
+
return ctx.reportInfo.commits;
|
|
226
|
+
}
|
|
227
|
+
}),
|
|
228
|
+
report: {
|
|
229
|
+
attachment: t.rawMethod("GET", {
|
|
230
|
+
input: z.object({
|
|
231
|
+
attachmentId: z.string().min(1).max(100).transform((id) => id)
|
|
232
|
+
}),
|
|
233
|
+
handler: async ({ ctx, input }) => {
|
|
234
|
+
const idx = ctx.reportInfo.attachmentIdToPath.get(input.attachmentId);
|
|
235
|
+
if (!idx)
|
|
236
|
+
throw TypedHTTP.HttpError.withCode("NOT_FOUND");
|
|
237
|
+
const buffer = await fs2.promises.readFile(idx.path);
|
|
238
|
+
return TypedHTTP.ok(buffer, idx.contentType);
|
|
239
|
+
}
|
|
240
|
+
}),
|
|
241
|
+
json: t.get({
|
|
242
|
+
handler: async ({ ctx }) => {
|
|
243
|
+
await ctx.reportInfo.refresh();
|
|
244
|
+
return ctx.reportInfo.report;
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/localReportServer.ts
|
|
251
|
+
var logHTTPServer = debug("fk:http");
|
|
252
|
+
var LocalReportServer = class _LocalReportServer {
|
|
253
|
+
constructor(_server, _port, _authToken) {
|
|
254
|
+
this._server = _server;
|
|
255
|
+
this._port = _port;
|
|
256
|
+
this._authToken = _authToken;
|
|
257
|
+
}
|
|
258
|
+
static async create(options) {
|
|
236
259
|
const app = express();
|
|
237
260
|
app.set("etag", false);
|
|
238
261
|
const authToken = randomUUIDBase62();
|
|
@@ -255,9 +278,10 @@ var LocalReportServer = class _LocalReportServer {
|
|
|
255
278
|
});
|
|
256
279
|
next();
|
|
257
280
|
});
|
|
281
|
+
const reportInfo = new ReportInfo(options);
|
|
258
282
|
app.use("/" + authToken, createTypedHttpExpressMiddleware({
|
|
259
283
|
router: localReportRouter,
|
|
260
|
-
createRootContext: async ({ req, res, input }) => ({
|
|
284
|
+
createRootContext: async ({ req, res, input }) => ({ reportInfo })
|
|
261
285
|
}));
|
|
262
286
|
app.use((err, req, res, next) => {
|
|
263
287
|
if (err instanceof TypedHTTP2.HttpError)
|
package/lib/playwright-test.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import { ReportUtils as ReportUtils2 } from "@flakiness/report";
|
|
3
3
|
import { Multimap } from "@flakiness/shared/common/multimap.js";
|
|
4
4
|
import chalk2 from "chalk";
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import fs7 from "fs";
|
|
6
|
+
import path6 from "path";
|
|
7
7
|
|
|
8
8
|
// src/cli/cmd-show-report.ts
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import open from "open";
|
|
11
|
-
import
|
|
11
|
+
import path5 from "path";
|
|
12
12
|
|
|
13
13
|
// src/flakinessConfig.ts
|
|
14
14
|
import fs2 from "fs";
|
|
@@ -139,6 +139,29 @@ var ansiRegex = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:
|
|
|
139
139
|
function stripAnsi(str) {
|
|
140
140
|
return str.replace(ansiRegex, "");
|
|
141
141
|
}
|
|
142
|
+
async function saveReportAndAttachments(report, attachments, outputFolder) {
|
|
143
|
+
const reportPath = path.join(outputFolder, "report.json");
|
|
144
|
+
const attachmentsFolder = path.join(outputFolder, "attachments");
|
|
145
|
+
await fs.promises.rm(outputFolder, { recursive: true, force: true });
|
|
146
|
+
await fs.promises.mkdir(outputFolder, { recursive: true });
|
|
147
|
+
await fs.promises.writeFile(reportPath, JSON.stringify(report), "utf-8");
|
|
148
|
+
if (attachments.length)
|
|
149
|
+
await fs.promises.mkdir(attachmentsFolder);
|
|
150
|
+
const movedAttachments = [];
|
|
151
|
+
for (const attachment of attachments) {
|
|
152
|
+
const attachmentPath = path.join(attachmentsFolder, attachment.id);
|
|
153
|
+
if (attachment.path)
|
|
154
|
+
await fs.promises.cp(attachment.path, attachmentPath);
|
|
155
|
+
else if (attachment.body)
|
|
156
|
+
await fs.promises.writeFile(attachmentPath, attachment.body);
|
|
157
|
+
movedAttachments.push({
|
|
158
|
+
contentType: attachment.contentType,
|
|
159
|
+
id: attachment.id,
|
|
160
|
+
path: attachmentPath
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return movedAttachments;
|
|
164
|
+
}
|
|
142
165
|
function shell(command, args, options) {
|
|
143
166
|
try {
|
|
144
167
|
const result = spawnSync(command, args, { encoding: "utf-8", ...options });
|
|
@@ -429,9 +452,14 @@ import compression from "compression";
|
|
|
429
452
|
import debug from "debug";
|
|
430
453
|
import express from "express";
|
|
431
454
|
import "express-async-errors";
|
|
432
|
-
import fs5 from "fs";
|
|
433
455
|
import http2 from "http";
|
|
434
456
|
|
|
457
|
+
// src/localReportApi.ts
|
|
458
|
+
import { TypedHTTP as TypedHTTP2 } from "@flakiness/shared/common/typedHttp.js";
|
|
459
|
+
import fs4 from "fs";
|
|
460
|
+
import path4 from "path";
|
|
461
|
+
import { z } from "zod/v4";
|
|
462
|
+
|
|
435
463
|
// src/localGit.ts
|
|
436
464
|
import { exec } from "child_process";
|
|
437
465
|
import { promisify } from "util";
|
|
@@ -473,9 +501,37 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
473
501
|
}
|
|
474
502
|
|
|
475
503
|
// src/localReportApi.ts
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
504
|
+
var ReportInfo = class {
|
|
505
|
+
constructor(_options) {
|
|
506
|
+
this._options = _options;
|
|
507
|
+
}
|
|
508
|
+
report;
|
|
509
|
+
attachmentIdToPath = /* @__PURE__ */ new Map();
|
|
510
|
+
commits = [];
|
|
511
|
+
async refresh() {
|
|
512
|
+
const report = await fs4.promises.readFile(this._options.reportPath, "utf-8").then((x) => JSON.parse(x)).catch((e) => void 0);
|
|
513
|
+
if (!report) {
|
|
514
|
+
this.report = void 0;
|
|
515
|
+
this.commits = [];
|
|
516
|
+
this.attachmentIdToPath = /* @__PURE__ */ new Map();
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (JSON.stringify(report) === JSON.stringify(this.report))
|
|
520
|
+
return;
|
|
521
|
+
this.report = report;
|
|
522
|
+
this.commits = await listLocalCommits(path4.dirname(this._options.reportPath), report.commitId, 100);
|
|
523
|
+
const attachmentsDir = this._options.attachmentsFolder;
|
|
524
|
+
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
525
|
+
if (missingAttachments.length) {
|
|
526
|
+
const first = missingAttachments.slice(0, 3);
|
|
527
|
+
for (let i = 0; i < 3 && i < missingAttachments.length; ++i)
|
|
528
|
+
console.warn(`Missing attachment with id ${missingAttachments[i]}`);
|
|
529
|
+
if (missingAttachments.length > 3)
|
|
530
|
+
console.warn(`...and ${missingAttachments.length - 3} more missing attachments.`);
|
|
531
|
+
}
|
|
532
|
+
this.attachmentIdToPath = attachmentIdToPath;
|
|
533
|
+
}
|
|
534
|
+
};
|
|
479
535
|
var t = TypedHTTP2.Router.create();
|
|
480
536
|
var localReportRouter = {
|
|
481
537
|
ping: t.get({
|
|
@@ -485,7 +541,7 @@ var localReportRouter = {
|
|
|
485
541
|
}),
|
|
486
542
|
lastCommits: t.get({
|
|
487
543
|
handler: async ({ ctx }) => {
|
|
488
|
-
return ctx.commits;
|
|
544
|
+
return ctx.reportInfo.commits;
|
|
489
545
|
}
|
|
490
546
|
}),
|
|
491
547
|
report: {
|
|
@@ -494,7 +550,7 @@ var localReportRouter = {
|
|
|
494
550
|
attachmentId: z.string().min(1).max(100).transform((id) => id)
|
|
495
551
|
}),
|
|
496
552
|
handler: async ({ ctx, input }) => {
|
|
497
|
-
const idx = ctx.attachmentIdToPath.get(input.attachmentId);
|
|
553
|
+
const idx = ctx.reportInfo.attachmentIdToPath.get(input.attachmentId);
|
|
498
554
|
if (!idx)
|
|
499
555
|
throw TypedHTTP2.HttpError.withCode("NOT_FOUND");
|
|
500
556
|
const buffer = await fs4.promises.readFile(idx.path);
|
|
@@ -503,7 +559,8 @@ var localReportRouter = {
|
|
|
503
559
|
}),
|
|
504
560
|
json: t.get({
|
|
505
561
|
handler: async ({ ctx }) => {
|
|
506
|
-
|
|
562
|
+
await ctx.reportInfo.refresh();
|
|
563
|
+
return ctx.reportInfo.report;
|
|
507
564
|
}
|
|
508
565
|
})
|
|
509
566
|
}
|
|
@@ -518,17 +575,6 @@ var LocalReportServer = class _LocalReportServer {
|
|
|
518
575
|
this._authToken = _authToken;
|
|
519
576
|
}
|
|
520
577
|
static async create(options) {
|
|
521
|
-
const report = JSON.parse(await fs5.promises.readFile(options.reportPath, "utf-8"));
|
|
522
|
-
const attachmentsDir = options.attachmentsFolder;
|
|
523
|
-
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
524
|
-
if (missingAttachments.length) {
|
|
525
|
-
const first = missingAttachments.slice(0, 3);
|
|
526
|
-
for (let i = 0; i < 3 && i < missingAttachments.length; ++i)
|
|
527
|
-
console.warn(`Missing attachment with id ${missingAttachments[i]}`);
|
|
528
|
-
if (missingAttachments.length > 3)
|
|
529
|
-
console.warn(`...and ${missingAttachments.length - 3} more missing attachments.`);
|
|
530
|
-
}
|
|
531
|
-
const commits = await listLocalCommits(process.cwd(), report.commitId, 100);
|
|
532
578
|
const app = express();
|
|
533
579
|
app.set("etag", false);
|
|
534
580
|
const authToken = randomUUIDBase62();
|
|
@@ -551,9 +597,10 @@ var LocalReportServer = class _LocalReportServer {
|
|
|
551
597
|
});
|
|
552
598
|
next();
|
|
553
599
|
});
|
|
600
|
+
const reportInfo = new ReportInfo(options);
|
|
554
601
|
app.use("/" + authToken, createTypedHttpExpressMiddleware({
|
|
555
602
|
router: localReportRouter,
|
|
556
|
-
createRootContext: async ({ req, res, input }) => ({
|
|
603
|
+
createRootContext: async ({ req, res, input }) => ({ reportInfo })
|
|
557
604
|
}));
|
|
558
605
|
app.use((err2, req, res, next) => {
|
|
559
606
|
if (err2 instanceof TypedHTTP3.HttpError)
|
|
@@ -587,7 +634,7 @@ var LocalReportServer = class _LocalReportServer {
|
|
|
587
634
|
|
|
588
635
|
// src/cli/cmd-show-report.ts
|
|
589
636
|
async function cmdShowReport(reportFolder) {
|
|
590
|
-
const reportPath =
|
|
637
|
+
const reportPath = path5.join(reportFolder, "report.json");
|
|
591
638
|
const session = await FlakinessSession.load();
|
|
592
639
|
const config = await FlakinessConfig.load();
|
|
593
640
|
const projectPublicId = config.projectPublicId();
|
|
@@ -610,12 +657,12 @@ async function cmdShowReport(reportFolder) {
|
|
|
610
657
|
|
|
611
658
|
// src/createTestStepSnippets.ts
|
|
612
659
|
import { codeFrameColumns } from "@babel/code-frame";
|
|
613
|
-
import
|
|
660
|
+
import fs5 from "fs";
|
|
614
661
|
function createTestStepSnippets(filepathToSteps) {
|
|
615
662
|
for (const [filepath, steps] of filepathToSteps) {
|
|
616
663
|
let source;
|
|
617
664
|
try {
|
|
618
|
-
source =
|
|
665
|
+
source = fs5.readFileSync(filepath, "utf-8");
|
|
619
666
|
} catch (e) {
|
|
620
667
|
continue;
|
|
621
668
|
}
|
|
@@ -640,7 +687,7 @@ function createTestStepSnippets(filepathToSteps) {
|
|
|
640
687
|
// src/reportUploader.ts
|
|
641
688
|
import { compressTextAsync, compressTextSync } from "@flakiness/shared/node/compression.js";
|
|
642
689
|
import assert2 from "assert";
|
|
643
|
-
import
|
|
690
|
+
import fs6 from "fs";
|
|
644
691
|
import { URL } from "url";
|
|
645
692
|
var ReportUploader = class _ReportUploader {
|
|
646
693
|
static optionsFromEnv(overrides) {
|
|
@@ -738,16 +785,16 @@ var ReportUpload = class {
|
|
|
738
785
|
url: uploadUrl,
|
|
739
786
|
headers: {
|
|
740
787
|
"Content-Type": attachment.contentType,
|
|
741
|
-
"Content-Length": (await
|
|
788
|
+
"Content-Length": (await fs6.promises.stat(attachmentPath)).size + ""
|
|
742
789
|
},
|
|
743
790
|
method: "put"
|
|
744
791
|
});
|
|
745
|
-
|
|
792
|
+
fs6.createReadStream(attachmentPath).pipe(request);
|
|
746
793
|
await responseDataPromise;
|
|
747
794
|
}, HTTP_BACKOFF);
|
|
748
795
|
return;
|
|
749
796
|
}
|
|
750
|
-
let buffer = attachment.body ? attachment.body : attachment.path ? await
|
|
797
|
+
let buffer = attachment.body ? attachment.body : attachment.path ? await fs6.promises.readFile(attachment.path) : void 0;
|
|
751
798
|
assert2(buffer);
|
|
752
799
|
const encoding = compressable ? "br" : void 0;
|
|
753
800
|
if (compressable)
|
|
@@ -844,7 +891,7 @@ var err = (txt) => console.error(chalk2.red(`[flakiness.io] ${txt}`));
|
|
|
844
891
|
var FlakinessReporter = class {
|
|
845
892
|
constructor(_options = {}) {
|
|
846
893
|
this._options = _options;
|
|
847
|
-
this._outputFolder =
|
|
894
|
+
this._outputFolder = path6.join(process.cwd(), this._options.outputFolder ?? process.env.FLAKINESS_OUTPUT_DIR ?? "flakiness-report");
|
|
848
895
|
}
|
|
849
896
|
_config;
|
|
850
897
|
_rootSuite;
|
|
@@ -947,7 +994,7 @@ var FlakinessReporter = class {
|
|
|
947
994
|
location: pwStep.location ? this._createLocation(context, pwStep.location) : void 0
|
|
948
995
|
};
|
|
949
996
|
if (pwStep.location) {
|
|
950
|
-
const resolvedPath =
|
|
997
|
+
const resolvedPath = path6.resolve(pwStep.location.file);
|
|
951
998
|
this._filepathToSteps.set(resolvedPath, step);
|
|
952
999
|
}
|
|
953
1000
|
if (pwStep.error)
|
|
@@ -996,10 +1043,10 @@ var FlakinessReporter = class {
|
|
|
996
1043
|
const environmentsMap = createEnvironments(this._config.projects);
|
|
997
1044
|
if (this._options.collectBrowserVersions) {
|
|
998
1045
|
try {
|
|
999
|
-
let playwrightPath =
|
|
1000
|
-
while (
|
|
1001
|
-
playwrightPath =
|
|
1002
|
-
const module = await import(
|
|
1046
|
+
let playwrightPath = fs7.realpathSync(process.argv[1]);
|
|
1047
|
+
while (path6.basename(playwrightPath) !== "test")
|
|
1048
|
+
playwrightPath = path6.dirname(playwrightPath);
|
|
1049
|
+
const module = await import(path6.join(playwrightPath, "index.js"));
|
|
1003
1050
|
for (const [project, env] of environmentsMap) {
|
|
1004
1051
|
const { browserName = "chromium", channel, headless } = project.use;
|
|
1005
1052
|
let browserType;
|
|
@@ -1048,25 +1095,7 @@ var FlakinessReporter = class {
|
|
|
1048
1095
|
for (const unaccessibleAttachment of context.unaccessibleAttachmentPaths)
|
|
1049
1096
|
warn(`cannot access attachment ${unaccessibleAttachment}`);
|
|
1050
1097
|
this._report = report;
|
|
1051
|
-
|
|
1052
|
-
const attachmentsFolder = path5.join(this._outputFolder, "attachments");
|
|
1053
|
-
await fs8.promises.rm(this._outputFolder, { recursive: true, force: true });
|
|
1054
|
-
await fs8.promises.mkdir(this._outputFolder, { recursive: true });
|
|
1055
|
-
await fs8.promises.writeFile(reportPath, JSON.stringify(report), "utf-8");
|
|
1056
|
-
if (context.attachments.size)
|
|
1057
|
-
await fs8.promises.mkdir(attachmentsFolder);
|
|
1058
|
-
for (const attachment of context.attachments.values()) {
|
|
1059
|
-
const attachmentPath = path5.join(attachmentsFolder, attachment.id);
|
|
1060
|
-
if (attachment.path)
|
|
1061
|
-
await fs8.promises.cp(attachment.path, attachmentPath);
|
|
1062
|
-
else if (attachment.body)
|
|
1063
|
-
await fs8.promises.writeFile(attachmentPath, attachment.body);
|
|
1064
|
-
this._attachments.push({
|
|
1065
|
-
contentType: attachment.contentType,
|
|
1066
|
-
id: attachment.id,
|
|
1067
|
-
path: attachmentPath
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1098
|
+
this._attachments = await saveReportAndAttachments(report, Array.from(context.attachments.values()), this._outputFolder);
|
|
1070
1099
|
this._result = result;
|
|
1071
1100
|
}
|
|
1072
1101
|
async onExit() {
|
|
@@ -1084,12 +1113,12 @@ var FlakinessReporter = class {
|
|
|
1084
1113
|
if (shouldOpen) {
|
|
1085
1114
|
await cmdShowReport(this._outputFolder);
|
|
1086
1115
|
} else {
|
|
1087
|
-
const defaultOutputFolder =
|
|
1088
|
-
const folder = defaultOutputFolder === this._outputFolder ? "" :
|
|
1116
|
+
const defaultOutputFolder = path6.join(process.cwd(), "flakiness-report");
|
|
1117
|
+
const folder = defaultOutputFolder === this._outputFolder ? "" : path6.relative(process.cwd(), this._outputFolder);
|
|
1089
1118
|
console.log(`
|
|
1090
|
-
To open last Flakiness report run:
|
|
1119
|
+
To open last Flakiness report, install Flakiness CLI tool and run:
|
|
1091
1120
|
|
|
1092
|
-
${chalk2.cyan(`
|
|
1121
|
+
${chalk2.cyan(`flakiness show ${folder}`)}
|
|
1093
1122
|
`);
|
|
1094
1123
|
}
|
|
1095
1124
|
}
|
package/lib/utils.js
CHANGED
|
@@ -123,6 +123,29 @@ var ansiRegex = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:
|
|
|
123
123
|
function stripAnsi(str) {
|
|
124
124
|
return str.replace(ansiRegex, "");
|
|
125
125
|
}
|
|
126
|
+
async function saveReportAndAttachments(report, attachments, outputFolder) {
|
|
127
|
+
const reportPath = path.join(outputFolder, "report.json");
|
|
128
|
+
const attachmentsFolder = path.join(outputFolder, "attachments");
|
|
129
|
+
await fs.promises.rm(outputFolder, { recursive: true, force: true });
|
|
130
|
+
await fs.promises.mkdir(outputFolder, { recursive: true });
|
|
131
|
+
await fs.promises.writeFile(reportPath, JSON.stringify(report), "utf-8");
|
|
132
|
+
if (attachments.length)
|
|
133
|
+
await fs.promises.mkdir(attachmentsFolder);
|
|
134
|
+
const movedAttachments = [];
|
|
135
|
+
for (const attachment of attachments) {
|
|
136
|
+
const attachmentPath = path.join(attachmentsFolder, attachment.id);
|
|
137
|
+
if (attachment.path)
|
|
138
|
+
await fs.promises.cp(attachment.path, attachmentPath);
|
|
139
|
+
else if (attachment.body)
|
|
140
|
+
await fs.promises.writeFile(attachmentPath, attachment.body);
|
|
141
|
+
movedAttachments.push({
|
|
142
|
+
contentType: attachment.contentType,
|
|
143
|
+
id: attachment.id,
|
|
144
|
+
path: attachmentPath
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return movedAttachments;
|
|
148
|
+
}
|
|
126
149
|
function shell(command, args, options) {
|
|
127
150
|
try {
|
|
128
151
|
const result = spawnSync(command, args, { encoding: "utf-8", ...options });
|
|
@@ -342,6 +365,7 @@ export {
|
|
|
342
365
|
parseStringDate,
|
|
343
366
|
resolveAttachmentPaths,
|
|
344
367
|
retryWithBackoff,
|
|
368
|
+
saveReportAndAttachments,
|
|
345
369
|
sha1Buffer,
|
|
346
370
|
sha1File,
|
|
347
371
|
shell,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flakiness/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.131.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"flakiness": "./lib/cli/cli.js"
|
|
@@ -39,13 +39,18 @@
|
|
|
39
39
|
"description": "",
|
|
40
40
|
"types": "./types/index.d.ts",
|
|
41
41
|
"scripts": {
|
|
42
|
-
"
|
|
42
|
+
"build:all": "npm run build:win && npm run build:linux && npm run build:mac && npm run build:alpine && npm run build:mac_intel",
|
|
43
|
+
"build:win": "bun build ./lib/cli/cli.js --compile --minify --target=bun-windows-x64 --outfile dist/flakiness-win-x64.exe",
|
|
44
|
+
"build:linux": "bun build ./lib/cli/cli.js --compile --minify --target=bun-linux-x64 --outfile dist/flakiness-linux-x64",
|
|
45
|
+
"build:alpine": "bun build ./lib/cli/cli.js --compile --minify --target=bun-linux-x64-musl --outfile dist/flakiness-linux-x64-alpine",
|
|
46
|
+
"build:mac": "bun build ./lib/cli/cli.js --compile --minify --target=bun-darwin-arm64 --outfile dist/flakiness-macos-arm64",
|
|
47
|
+
"build:mac_intel": "bun build ./lib/cli/cli.js --compile --minify --target=bun-darwin-x64 --outfile dist/flakiness-macos-x64"
|
|
43
48
|
},
|
|
44
49
|
"keywords": [],
|
|
45
50
|
"author": "Degu Labs, Inc",
|
|
46
51
|
"license": "Fair Source 100",
|
|
47
52
|
"devDependencies": {
|
|
48
|
-
"@flakiness/server": "0.
|
|
53
|
+
"@flakiness/server": "0.131.0",
|
|
49
54
|
"@playwright/test": "^1.54.0",
|
|
50
55
|
"@types/babel__code-frame": "^7.0.6",
|
|
51
56
|
"@types/compression": "^1.8.1",
|
|
@@ -53,8 +58,8 @@
|
|
|
53
58
|
},
|
|
54
59
|
"dependencies": {
|
|
55
60
|
"@babel/code-frame": "^7.26.2",
|
|
56
|
-
"@flakiness/report": "0.
|
|
57
|
-
"@flakiness/shared": "0.
|
|
61
|
+
"@flakiness/report": "0.131.0",
|
|
62
|
+
"@flakiness/shared": "0.131.0",
|
|
58
63
|
"@rgrove/parse-xml": "^4.2.0",
|
|
59
64
|
"body-parser": "^1.20.3",
|
|
60
65
|
"chalk": "^5.6.2",
|