@piwitests/reporter 0.54.0 → 0.55.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/dist/cli/index.js +1442 -294
- package/dist/global-setup-module.js +71 -42
- package/dist/index.d.ts +21 -9
- package/dist/index.js +5953 -5255
- package/dist/internal/capture/attachments.d.ts +2 -0
- package/dist/internal/capture/attachments.js +2 -0
- package/dist/internal/capture/capture-fixtures.d.ts +30 -9
- package/dist/internal/capture/capture-fixtures.js +767 -299
- package/package.json +1 -1
|
@@ -2037,6 +2037,8 @@ var ATTACHMENT_NAMES = {
|
|
|
2037
2037
|
pageInventory: "piwi-page-inventory",
|
|
2038
2038
|
locatorPages: "piwi-locator-pages",
|
|
2039
2039
|
codeReach: "piwi-code-reach",
|
|
2040
|
+
browserCoverage: "piwi-browser-coverage",
|
|
2041
|
+
browserFunctions: "piwi-browser-functions",
|
|
2040
2042
|
serverCoverageRequests: "piwi-server-coverage-requests",
|
|
2041
2043
|
webVitals: "piwi-web-vitals",
|
|
2042
2044
|
locatorSuggestion: "piwi-locator-suggestion",
|
|
@@ -3501,6 +3503,438 @@ function joinErrorMessages(errors) {
|
|
|
3501
3503
|
return parts.join("\n---\n") || null;
|
|
3502
3504
|
}
|
|
3503
3505
|
|
|
3506
|
+
// ../core/src/coverage.ts
|
|
3507
|
+
var MAX_COVERAGE_FILES = 2e3;
|
|
3508
|
+
var MAX_COVERAGE_RANGES = 1e4;
|
|
3509
|
+
var MAX_LINE = 1e6;
|
|
3510
|
+
var MAX_PATH_LENGTH = 500;
|
|
3511
|
+
var BLOB_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
3512
|
+
function isRecord(value) {
|
|
3513
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3514
|
+
}
|
|
3515
|
+
function isRuntime(value) {
|
|
3516
|
+
return value === "browser" || value === "server";
|
|
3517
|
+
}
|
|
3518
|
+
function isLine(value) {
|
|
3519
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= MAX_LINE;
|
|
3520
|
+
}
|
|
3521
|
+
function validRanges(raw) {
|
|
3522
|
+
if (!Array.isArray(raw)) return [];
|
|
3523
|
+
const out = [];
|
|
3524
|
+
for (const item of raw) {
|
|
3525
|
+
if (!Array.isArray(item) || item.length !== 2) continue;
|
|
3526
|
+
const [start, end] = item;
|
|
3527
|
+
if (isLine(start) && isLine(end) && start <= end) out.push([start, end]);
|
|
3528
|
+
}
|
|
3529
|
+
return out.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
3530
|
+
}
|
|
3531
|
+
function normalizeLineRanges(ranges) {
|
|
3532
|
+
const out = [];
|
|
3533
|
+
for (const range of validRanges(ranges)) {
|
|
3534
|
+
const last = out[out.length - 1];
|
|
3535
|
+
if (last && range[0] <= last[1] + 1) last[1] = Math.max(last[1], range[1]);
|
|
3536
|
+
else out.push(range);
|
|
3537
|
+
}
|
|
3538
|
+
return out;
|
|
3539
|
+
}
|
|
3540
|
+
function normalizeFunctionRanges(ranges) {
|
|
3541
|
+
const out = [];
|
|
3542
|
+
for (const range of validRanges(ranges)) {
|
|
3543
|
+
const last = out[out.length - 1];
|
|
3544
|
+
if (!last || last[0] !== range[0] || last[1] !== range[1]) out.push(range);
|
|
3545
|
+
}
|
|
3546
|
+
return out;
|
|
3547
|
+
}
|
|
3548
|
+
function normalizeCoveragePath(raw) {
|
|
3549
|
+
if (typeof raw !== "string" || raw.length > MAX_PATH_LENGTH || raw.includes("\0")) return null;
|
|
3550
|
+
const path14 = raw.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
3551
|
+
if (!path14 || path14.startsWith("../") || path14.startsWith("/") || /^[A-Za-z]:\//.test(path14)) return null;
|
|
3552
|
+
if (/(^|\/)node_modules\//.test(path14)) return null;
|
|
3553
|
+
return path14;
|
|
3554
|
+
}
|
|
3555
|
+
function fileEntry(path14, runtime, blob, functions = [], lines = []) {
|
|
3556
|
+
const file = { path: path14, runtime };
|
|
3557
|
+
if (blob && (functions.length > 0 || lines.length > 0)) file.blob = blob;
|
|
3558
|
+
if (functions.length > 0) file.functions = functions;
|
|
3559
|
+
if (lines.length > 0) file.lines = lines;
|
|
3560
|
+
return file;
|
|
3561
|
+
}
|
|
3562
|
+
function captureOf(files, incomplete) {
|
|
3563
|
+
return incomplete ? { v: 1, files, incomplete: true } : { v: 1, files };
|
|
3564
|
+
}
|
|
3565
|
+
function compareFiles(a, b) {
|
|
3566
|
+
if (a.path !== b.path) return a.path < b.path ? -1 : 1;
|
|
3567
|
+
if (a.runtime !== b.runtime) return a.runtime < b.runtime ? -1 : 1;
|
|
3568
|
+
return 0;
|
|
3569
|
+
}
|
|
3570
|
+
function sanitizeCoverage(raw) {
|
|
3571
|
+
if (!isRecord(raw) || raw.v !== 1 || !Array.isArray(raw.files)) return null;
|
|
3572
|
+
const files = [];
|
|
3573
|
+
for (const item of raw.files) {
|
|
3574
|
+
if (!isRecord(item) || !isRuntime(item.runtime)) continue;
|
|
3575
|
+
const path14 = normalizeCoveragePath(item.path);
|
|
3576
|
+
if (path14 === null) continue;
|
|
3577
|
+
const blob = typeof item.blob === "string" && BLOB_ID.test(item.blob) ? item.blob : void 0;
|
|
3578
|
+
files.push(
|
|
3579
|
+
fileEntry(path14, item.runtime, blob, normalizeFunctionRanges(item.functions), normalizeLineRanges(item.lines))
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3582
|
+
const merged = mergeCoverage(captureOf(files, raw.incomplete === true));
|
|
3583
|
+
if (!merged) return null;
|
|
3584
|
+
let incomplete = merged.incomplete === true || merged.files.length > MAX_COVERAGE_FILES;
|
|
3585
|
+
let budget = MAX_COVERAGE_RANGES;
|
|
3586
|
+
const capped = merged.files.slice(0, MAX_COVERAGE_FILES).map((file) => {
|
|
3587
|
+
const count = (file.functions?.length ?? 0) + (file.lines?.length ?? 0);
|
|
3588
|
+
if (count <= budget) {
|
|
3589
|
+
budget -= count;
|
|
3590
|
+
return file;
|
|
3591
|
+
}
|
|
3592
|
+
incomplete = true;
|
|
3593
|
+
return fileEntry(file.path, file.runtime);
|
|
3594
|
+
});
|
|
3595
|
+
return captureOf(capped, incomplete);
|
|
3596
|
+
}
|
|
3597
|
+
function mergeCoverage(...captures2) {
|
|
3598
|
+
const entries = /* @__PURE__ */ new Map();
|
|
3599
|
+
let incomplete = false;
|
|
3600
|
+
for (const capture of captures2) {
|
|
3601
|
+
if (!capture) continue;
|
|
3602
|
+
if (capture.incomplete) incomplete = true;
|
|
3603
|
+
for (const file of capture.files) {
|
|
3604
|
+
const key = `${file.runtime}:${file.path}`;
|
|
3605
|
+
let entry = entries.get(key);
|
|
3606
|
+
if (!entry) {
|
|
3607
|
+
entry = { path: file.path, runtime: file.runtime, blobs: /* @__PURE__ */ new Set(), functions: [], lines: [] };
|
|
3608
|
+
entries.set(key, entry);
|
|
3609
|
+
}
|
|
3610
|
+
if (file.blob) entry.blobs.add(file.blob);
|
|
3611
|
+
for (const range of file.functions ?? []) entry.functions.push(range);
|
|
3612
|
+
for (const range of file.lines ?? []) entry.lines.push(range);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
if (entries.size === 0) return null;
|
|
3616
|
+
const files = [...entries.values()].map((entry) => {
|
|
3617
|
+
if (entry.blobs.size > 1) incomplete = true;
|
|
3618
|
+
const blob = entry.blobs.size === 1 ? [...entry.blobs][0] : void 0;
|
|
3619
|
+
return fileEntry(
|
|
3620
|
+
entry.path,
|
|
3621
|
+
entry.runtime,
|
|
3622
|
+
blob,
|
|
3623
|
+
normalizeFunctionRanges(entry.functions),
|
|
3624
|
+
normalizeLineRanges(entry.lines)
|
|
3625
|
+
);
|
|
3626
|
+
});
|
|
3627
|
+
return captureOf(files.sort(compareFiles), incomplete);
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
// ../core/src/source-map.ts
|
|
3631
|
+
var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
3632
|
+
var BASE64_VALUE = new Int8Array(128).fill(-1);
|
|
3633
|
+
for (let i = 0; i < BASE64.length; i++) BASE64_VALUE[BASE64.charCodeAt(i)] = i;
|
|
3634
|
+
function decodeMappings(mappings, sourceBase) {
|
|
3635
|
+
const lines = [];
|
|
3636
|
+
let current = { columns: [], sources: [], originalLines: [] };
|
|
3637
|
+
let column = 0;
|
|
3638
|
+
let source = 0;
|
|
3639
|
+
let originalLine = 0;
|
|
3640
|
+
const fields = [];
|
|
3641
|
+
let value = 0;
|
|
3642
|
+
let shift = 0;
|
|
3643
|
+
const flush = () => {
|
|
3644
|
+
if (fields.length === 0) return;
|
|
3645
|
+
column += fields[0];
|
|
3646
|
+
if (fields.length >= 4) {
|
|
3647
|
+
source += fields[1];
|
|
3648
|
+
originalLine += fields[2];
|
|
3649
|
+
current.columns.push(column);
|
|
3650
|
+
current.sources.push(sourceBase + source);
|
|
3651
|
+
current.originalLines.push(originalLine);
|
|
3652
|
+
} else {
|
|
3653
|
+
current.columns.push(column);
|
|
3654
|
+
current.sources.push(-1);
|
|
3655
|
+
current.originalLines.push(-1);
|
|
3656
|
+
}
|
|
3657
|
+
fields.length = 0;
|
|
3658
|
+
};
|
|
3659
|
+
for (let i = 0; i <= mappings.length; i++) {
|
|
3660
|
+
const ch = i < mappings.length ? mappings.charCodeAt(i) : 59;
|
|
3661
|
+
if (ch === 59 || ch === 44) {
|
|
3662
|
+
flush();
|
|
3663
|
+
if (ch === 59) {
|
|
3664
|
+
lines.push(current);
|
|
3665
|
+
current = { columns: [], sources: [], originalLines: [] };
|
|
3666
|
+
column = 0;
|
|
3667
|
+
}
|
|
3668
|
+
continue;
|
|
3669
|
+
}
|
|
3670
|
+
const digit = ch < 128 ? BASE64_VALUE[ch] : -1;
|
|
3671
|
+
if (digit < 0) continue;
|
|
3672
|
+
value += (digit & 31) << shift;
|
|
3673
|
+
if (digit & 32) {
|
|
3674
|
+
shift += 5;
|
|
3675
|
+
continue;
|
|
3676
|
+
}
|
|
3677
|
+
fields.push(value & 1 ? -(value >>> 1) : value >>> 1);
|
|
3678
|
+
value = 0;
|
|
3679
|
+
shift = 0;
|
|
3680
|
+
}
|
|
3681
|
+
for (const line of lines) {
|
|
3682
|
+
if (line.columns.every((c, i) => i === 0 || c >= line.columns[i - 1])) continue;
|
|
3683
|
+
const order = line.columns.map((_, i) => i).sort((a, b) => line.columns[a] - line.columns[b]);
|
|
3684
|
+
line.columns = order.map((i) => line.columns[i]);
|
|
3685
|
+
line.sources = order.map((i) => line.sources[i]);
|
|
3686
|
+
line.originalLines = order.map((i) => line.originalLines[i]);
|
|
3687
|
+
}
|
|
3688
|
+
return lines;
|
|
3689
|
+
}
|
|
3690
|
+
function joinRoot(root, source) {
|
|
3691
|
+
if (!root || /^[a-z][\w+.-]*:/i.test(source) || source.startsWith("/")) return source;
|
|
3692
|
+
return root.endsWith("/") ? root + source : `${root}/${source}`;
|
|
3693
|
+
}
|
|
3694
|
+
function decodeLines(raw) {
|
|
3695
|
+
const sources = [];
|
|
3696
|
+
const decoded = [];
|
|
3697
|
+
const add = (map, lineOffset, columnOffset) => {
|
|
3698
|
+
if (map.sections) {
|
|
3699
|
+
for (const section of map.sections) {
|
|
3700
|
+
if (!add(section.map, section.offset.line, section.offset.column)) return false;
|
|
3701
|
+
}
|
|
3702
|
+
return true;
|
|
3703
|
+
}
|
|
3704
|
+
if (typeof map.mappings !== "string" || !Array.isArray(map.sources)) return false;
|
|
3705
|
+
const base = sources.length;
|
|
3706
|
+
for (const s of map.sources) sources.push(joinRoot(map.sourceRoot, s ?? ""));
|
|
3707
|
+
decodeMappings(map.mappings, base).forEach((segments, i) => {
|
|
3708
|
+
const at = lineOffset + i;
|
|
3709
|
+
const shifted = i === 0 && columnOffset ? segments.columns.map((c) => c + columnOffset) : segments.columns;
|
|
3710
|
+
const existing = decoded[at];
|
|
3711
|
+
if (!existing)
|
|
3712
|
+
decoded[at] = { columns: shifted, sources: segments.sources, originalLines: segments.originalLines };
|
|
3713
|
+
else {
|
|
3714
|
+
existing.columns.push(...shifted);
|
|
3715
|
+
existing.sources.push(...segments.sources);
|
|
3716
|
+
existing.originalLines.push(...segments.originalLines);
|
|
3717
|
+
}
|
|
3718
|
+
});
|
|
3719
|
+
return true;
|
|
3720
|
+
};
|
|
3721
|
+
return add(raw, 0, 0) ? { sources, lines: decoded } : null;
|
|
3722
|
+
}
|
|
3723
|
+
function compactSegments(lines) {
|
|
3724
|
+
let total = 0;
|
|
3725
|
+
for (const line of lines) total += line?.columns.length ?? 0;
|
|
3726
|
+
const segments = {
|
|
3727
|
+
lineStarts: new Int32Array(lines.length + 1),
|
|
3728
|
+
columns: new Int32Array(total),
|
|
3729
|
+
sources: new Int32Array(total),
|
|
3730
|
+
originalLines: new Int32Array(total)
|
|
3731
|
+
};
|
|
3732
|
+
let at = 0;
|
|
3733
|
+
for (let n = 0; n < lines.length; n++) {
|
|
3734
|
+
segments.lineStarts[n] = at;
|
|
3735
|
+
const line = lines[n];
|
|
3736
|
+
if (!line) continue;
|
|
3737
|
+
segments.columns.set(line.columns, at);
|
|
3738
|
+
segments.sources.set(line.sources, at);
|
|
3739
|
+
segments.originalLines.set(line.originalLines, at);
|
|
3740
|
+
at += line.columns.length;
|
|
3741
|
+
}
|
|
3742
|
+
segments.lineStarts[lines.length] = at;
|
|
3743
|
+
return segments;
|
|
3744
|
+
}
|
|
3745
|
+
function decodeSourceMap(raw) {
|
|
3746
|
+
if (raw.version !== void 0 && raw.version !== 3) return null;
|
|
3747
|
+
const decoded = decodeLines(raw);
|
|
3748
|
+
if (!decoded) return null;
|
|
3749
|
+
const { sources } = decoded;
|
|
3750
|
+
const segments = compactSegments(decoded.lines);
|
|
3751
|
+
const lineCount = segments.lineStarts.length - 1;
|
|
3752
|
+
const originalAt = (line, column) => {
|
|
3753
|
+
if (line < 0 || line >= lineCount) return null;
|
|
3754
|
+
let lo = segments.lineStarts[line];
|
|
3755
|
+
let hi = segments.lineStarts[line + 1] - 1;
|
|
3756
|
+
if (lo > hi || segments.columns[lo] > column) return null;
|
|
3757
|
+
while (lo < hi) {
|
|
3758
|
+
const mid = lo + hi + 1 >> 1;
|
|
3759
|
+
if (segments.columns[mid] <= column) lo = mid;
|
|
3760
|
+
else hi = mid - 1;
|
|
3761
|
+
}
|
|
3762
|
+
const source = segments.sources[lo];
|
|
3763
|
+
return source < 0 ? null : { source, line: segments.originalLines[lo] };
|
|
3764
|
+
};
|
|
3765
|
+
return {
|
|
3766
|
+
sources,
|
|
3767
|
+
sourceAt(line, column) {
|
|
3768
|
+
return originalAt(line, column)?.source ?? null;
|
|
3769
|
+
},
|
|
3770
|
+
originalAt,
|
|
3771
|
+
mapsBetween(source, start, end) {
|
|
3772
|
+
let found = false;
|
|
3773
|
+
eachSegmentBetween(segments, start, end, (i) => {
|
|
3774
|
+
found = segments.sources[i] === source;
|
|
3775
|
+
return found;
|
|
3776
|
+
});
|
|
3777
|
+
return found;
|
|
3778
|
+
},
|
|
3779
|
+
firstOriginalLineBetween(source, start, end) {
|
|
3780
|
+
let first = null;
|
|
3781
|
+
eachSegmentBetween(segments, start, end, (i) => {
|
|
3782
|
+
if (segments.sources[i] !== source || segments.originalLines[i] < 0) return false;
|
|
3783
|
+
first = segments.originalLines[i];
|
|
3784
|
+
return true;
|
|
3785
|
+
});
|
|
3786
|
+
return first;
|
|
3787
|
+
},
|
|
3788
|
+
originalLinesBetween(source, start, end, fromLine = 0) {
|
|
3789
|
+
let first = Number.POSITIVE_INFINITY;
|
|
3790
|
+
let last = -1;
|
|
3791
|
+
eachSegmentBetween(segments, start, end, (i) => {
|
|
3792
|
+
const line = segments.originalLines[i];
|
|
3793
|
+
if (segments.sources[i] === source && line >= fromLine) {
|
|
3794
|
+
if (line < first) first = line;
|
|
3795
|
+
if (line > last) last = line;
|
|
3796
|
+
}
|
|
3797
|
+
return false;
|
|
3798
|
+
});
|
|
3799
|
+
return last < 0 ? null : [first, last];
|
|
3800
|
+
}
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
function eachSegmentBetween(segments, start, end, visit) {
|
|
3804
|
+
const lineCount = segments.lineStarts.length - 1;
|
|
3805
|
+
for (let line = Math.max(start.line, 0); line <= end.line && line < lineCount; line++) {
|
|
3806
|
+
let i = segments.lineStarts[line];
|
|
3807
|
+
const stop = segments.lineStarts[line + 1];
|
|
3808
|
+
if (line === start.line) {
|
|
3809
|
+
let hi = stop;
|
|
3810
|
+
while (i < hi) {
|
|
3811
|
+
const mid = i + hi >> 1;
|
|
3812
|
+
if (segments.columns[mid] < start.column) i = mid + 1;
|
|
3813
|
+
else hi = mid;
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
for (; i < stop; i++) {
|
|
3817
|
+
if (line === end.line && segments.columns[i] >= end.column) return;
|
|
3818
|
+
if (visit(i)) return;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
function lineStarts(text) {
|
|
3823
|
+
const starts = [0];
|
|
3824
|
+
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) starts.push(i + 1);
|
|
3825
|
+
return starts;
|
|
3826
|
+
}
|
|
3827
|
+
function offsetToPosition(starts, offset) {
|
|
3828
|
+
let lo = 0;
|
|
3829
|
+
let hi = starts.length - 1;
|
|
3830
|
+
while (lo < hi) {
|
|
3831
|
+
const mid = lo + hi + 1 >> 1;
|
|
3832
|
+
if (starts[mid] <= offset) lo = mid;
|
|
3833
|
+
else hi = mid - 1;
|
|
3834
|
+
}
|
|
3835
|
+
return { line: lo, column: offset - starts[lo] };
|
|
3836
|
+
}
|
|
3837
|
+
function sourceMappingUrl(script) {
|
|
3838
|
+
const tail = script.slice(-4096);
|
|
3839
|
+
const matches = [...tail.matchAll(/(?:\/\/|\/\*)[#@]\s*sourceMappingURL=([^\s*'"]+)/g)];
|
|
3840
|
+
return matches.length ? matches[matches.length - 1][1] : null;
|
|
3841
|
+
}
|
|
3842
|
+
function decodeDataUrl(url) {
|
|
3843
|
+
const m = /^data:([^,]*?)(;base64)?,(.*)$/s.exec(url);
|
|
3844
|
+
if (!m) return null;
|
|
3845
|
+
try {
|
|
3846
|
+
if (!m[2]) return decodeURIComponent(m[3]);
|
|
3847
|
+
const binary = globalThis.atob(m[3]);
|
|
3848
|
+
const bytes = new Uint8Array(binary.length);
|
|
3849
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
3850
|
+
return new TextDecoder().decode(bytes);
|
|
3851
|
+
} catch {
|
|
3852
|
+
return null;
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
function normalizeSourcePath(source) {
|
|
3856
|
+
let s = source.replace(/[?#].*$/, "");
|
|
3857
|
+
s = s.replace(/^webpack:\/\/[^/]*\//, "").replace(/^webpack:\/\//, "");
|
|
3858
|
+
s = s.replace(/^(?:vite|rollup|turbopack|ng):\/*/, "");
|
|
3859
|
+
s = s.replace(/^\[project\]\//, "");
|
|
3860
|
+
s = s.replace(/^file:\/\//, "");
|
|
3861
|
+
s = s.replace(/^\/@fs\//, "/");
|
|
3862
|
+
s = s.replace(/^\/@id\//, "");
|
|
3863
|
+
try {
|
|
3864
|
+
s = decodeURIComponent(s);
|
|
3865
|
+
} catch {
|
|
3866
|
+
}
|
|
3867
|
+
s = s.replace(/\\/g, "/");
|
|
3868
|
+
if (/^\/[A-Za-z]:\//.test(s)) s = s.slice(1);
|
|
3869
|
+
s = s.replace(/(^|\/)\.\//g, "$1");
|
|
3870
|
+
return s;
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
// ../core/src/code-reach.ts
|
|
3874
|
+
var MAX_CODE_REACH_FILES = 2e3;
|
|
3875
|
+
function scriptText(source) {
|
|
3876
|
+
return { length: source.length, starts: Uint32Array.from(lineStarts(source)) };
|
|
3877
|
+
}
|
|
3878
|
+
var textOf = (entry, text) => text ?? (entry.source === void 0 ? void 0 : scriptText(entry.source));
|
|
3879
|
+
function executedFunctionRanges(entry, length, all = false) {
|
|
3880
|
+
length ??= entry.source?.length ?? Number.POSITIVE_INFINITY;
|
|
3881
|
+
const out = [];
|
|
3882
|
+
entry.functions.forEach((fn, i) => {
|
|
3883
|
+
const whole = fn.ranges[0];
|
|
3884
|
+
if (!whole || !all && whole.count <= 0) return;
|
|
3885
|
+
const topLevel = whole.startOffset === 0 && (whole.endOffset >= length || i === 0 && fn.functionName === "");
|
|
3886
|
+
if (topLevel) return;
|
|
3887
|
+
out.push({ start: whole.startOffset, end: whole.endOffset });
|
|
3888
|
+
});
|
|
3889
|
+
return out;
|
|
3890
|
+
}
|
|
3891
|
+
function scriptRan(entry, text) {
|
|
3892
|
+
return executedFunctionRanges(entry, text?.length).length > 0;
|
|
3893
|
+
}
|
|
3894
|
+
function reachedFunctionLines(entry, map, text) {
|
|
3895
|
+
return functionLines(entry, map, text, false);
|
|
3896
|
+
}
|
|
3897
|
+
function knownFunctionLines(entry, map, text) {
|
|
3898
|
+
return functionLines(entry, map, text, true);
|
|
3899
|
+
}
|
|
3900
|
+
function functionLines(entry, map, text, all) {
|
|
3901
|
+
const out = /* @__PURE__ */ new Map();
|
|
3902
|
+
const read = textOf(entry, text);
|
|
3903
|
+
const ranges = executedFunctionRanges(entry, read?.length, all);
|
|
3904
|
+
if (!ranges.length || !read) return out;
|
|
3905
|
+
const add = (source, range) => {
|
|
3906
|
+
const list = out.get(source);
|
|
3907
|
+
if (list) list.push(range);
|
|
3908
|
+
else out.set(source, [range]);
|
|
3909
|
+
};
|
|
3910
|
+
const starts = read.starts;
|
|
3911
|
+
for (const range of ranges) {
|
|
3912
|
+
const start = offsetToPosition(starts, range.start);
|
|
3913
|
+
if (!map) {
|
|
3914
|
+
const last = offsetToPosition(starts, Math.max(range.start, range.end - 1));
|
|
3915
|
+
add(-1, [start.line + 1, last.line + 1]);
|
|
3916
|
+
continue;
|
|
3917
|
+
}
|
|
3918
|
+
const at = map.originalAt(start.line, start.column);
|
|
3919
|
+
if (at === null) continue;
|
|
3920
|
+
const end = offsetToPosition(starts, range.end);
|
|
3921
|
+
const first = map.firstOriginalLineBetween(at.source, start, end);
|
|
3922
|
+
if (first === null) continue;
|
|
3923
|
+
const header = first === at.line || first === at.line + 1 ? at.line : first;
|
|
3924
|
+
const lines = map.originalLinesBetween(at.source, start, end, header);
|
|
3925
|
+
if (lines) add(at.source, [header + 1, lines[1] + 1]);
|
|
3926
|
+
}
|
|
3927
|
+
return out;
|
|
3928
|
+
}
|
|
3929
|
+
function finalizeCodeReach(files) {
|
|
3930
|
+
const out = /* @__PURE__ */ new Set();
|
|
3931
|
+
for (const raw of files) {
|
|
3932
|
+
const file = normalizeCoveragePath(raw);
|
|
3933
|
+
if (file !== null) out.add(file);
|
|
3934
|
+
}
|
|
3935
|
+
return [...out].sort().slice(0, MAX_CODE_REACH_FILES);
|
|
3936
|
+
}
|
|
3937
|
+
|
|
3504
3938
|
// src/internal/capture/inspect-on-failure.ts
|
|
3505
3939
|
function isCi(ci) {
|
|
3506
3940
|
return ci !== void 0 && ci !== "" && ci !== "false";
|
|
@@ -3909,7 +4343,45 @@ function isServerGranularity(value) {
|
|
|
3909
4343
|
return typeof value === "string" && SERVER_VALUES.has(value);
|
|
3910
4344
|
}
|
|
3911
4345
|
function browserCoverageInWorker() {
|
|
3912
|
-
|
|
4346
|
+
const browser = process.env[PIWI_ENV_KEYS.coverageBrowser];
|
|
4347
|
+
return process.env[PIWI_ENV_KEYS.captureCodeReach] === "true" || browser === "files" || browser === "functions";
|
|
4348
|
+
}
|
|
4349
|
+
function browserFunctionsInWorker() {
|
|
4350
|
+
return process.env[PIWI_ENV_KEYS.coverageBrowser] === "functions";
|
|
4351
|
+
}
|
|
4352
|
+
function browserFunctionCoverage(files) {
|
|
4353
|
+
return sanitizeCoverage({
|
|
4354
|
+
v: 1,
|
|
4355
|
+
files: [...files].map(([path14, functions]) => ({ path: path14, runtime: "browser", functions }))
|
|
4356
|
+
});
|
|
4357
|
+
}
|
|
4358
|
+
function newKnownFunctions(known, sent) {
|
|
4359
|
+
const parts = [];
|
|
4360
|
+
let files = [];
|
|
4361
|
+
let budget = MAX_COVERAGE_RANGES;
|
|
4362
|
+
const close = () => {
|
|
4363
|
+
if (files.length > 0) parts.push({ v: 1, files: files.sort((a, b) => a.path < b.path ? -1 : 1) });
|
|
4364
|
+
files = [];
|
|
4365
|
+
budget = MAX_COVERAGE_RANGES;
|
|
4366
|
+
};
|
|
4367
|
+
for (const [raw, ranges] of known) {
|
|
4368
|
+
const path14 = normalizeCoveragePath(raw);
|
|
4369
|
+
if (path14 === null) continue;
|
|
4370
|
+
let named = sent.get(path14);
|
|
4371
|
+
let fresh = normalizeFunctionRanges(ranges).filter((range) => !named?.has(`${range[0]}:${range[1]}`));
|
|
4372
|
+
if (fresh.length === 0) continue;
|
|
4373
|
+
if (!named) sent.set(path14, named = /* @__PURE__ */ new Set());
|
|
4374
|
+
for (const range of fresh) named.add(`${range[0]}:${range[1]}`);
|
|
4375
|
+
while (fresh.length > 0) {
|
|
4376
|
+
if (budget === 0 || files.length >= MAX_COVERAGE_FILES) close();
|
|
4377
|
+
const part = fresh.slice(0, budget);
|
|
4378
|
+
fresh = fresh.slice(part.length);
|
|
4379
|
+
budget -= part.length;
|
|
4380
|
+
files.push({ path: path14, allFunctions: part });
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
close();
|
|
4384
|
+
return parts;
|
|
3913
4385
|
}
|
|
3914
4386
|
function serverCoverageInWorker() {
|
|
3915
4387
|
return isServerGranularity(process.env[PIWI_ENV_KEYS.coverageServer]);
|
|
@@ -4053,241 +4525,13 @@ var crypto2 = __toESM(require("crypto"));
|
|
|
4053
4525
|
var fs6 = __toESM(require("fs"));
|
|
4054
4526
|
var path10 = __toESM(require("path"));
|
|
4055
4527
|
var import_node_child_process = require("child_process");
|
|
4056
|
-
|
|
4057
|
-
// ../core/src/coverage.ts
|
|
4058
|
-
var MAX_PATH_LENGTH = 500;
|
|
4059
|
-
function normalizeCoveragePath(raw) {
|
|
4060
|
-
if (typeof raw !== "string" || raw.length > MAX_PATH_LENGTH || raw.includes("\0")) return null;
|
|
4061
|
-
const path14 = raw.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4062
|
-
if (!path14 || path14.startsWith("../") || path14.startsWith("/") || /^[A-Za-z]:\//.test(path14)) return null;
|
|
4063
|
-
if (/(^|\/)node_modules\//.test(path14)) return null;
|
|
4064
|
-
return path14;
|
|
4065
|
-
}
|
|
4066
|
-
|
|
4067
|
-
// ../core/src/source-map.ts
|
|
4068
|
-
var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
4069
|
-
var BASE64_VALUE = new Int8Array(128).fill(-1);
|
|
4070
|
-
for (let i = 0; i < BASE64.length; i++) BASE64_VALUE[BASE64.charCodeAt(i)] = i;
|
|
4071
|
-
function decodeMappings(mappings, sourceBase) {
|
|
4072
|
-
const lines = [];
|
|
4073
|
-
let current = { columns: [], sources: [] };
|
|
4074
|
-
let column = 0;
|
|
4075
|
-
let source = 0;
|
|
4076
|
-
const fields = [];
|
|
4077
|
-
let value = 0;
|
|
4078
|
-
let shift = 0;
|
|
4079
|
-
const flush = () => {
|
|
4080
|
-
if (fields.length === 0) return;
|
|
4081
|
-
column += fields[0];
|
|
4082
|
-
if (fields.length >= 4) {
|
|
4083
|
-
source += fields[1];
|
|
4084
|
-
current.columns.push(column);
|
|
4085
|
-
current.sources.push(sourceBase + source);
|
|
4086
|
-
} else {
|
|
4087
|
-
current.columns.push(column);
|
|
4088
|
-
current.sources.push(-1);
|
|
4089
|
-
}
|
|
4090
|
-
fields.length = 0;
|
|
4091
|
-
};
|
|
4092
|
-
for (let i = 0; i <= mappings.length; i++) {
|
|
4093
|
-
const ch = i < mappings.length ? mappings.charCodeAt(i) : 59;
|
|
4094
|
-
if (ch === 59 || ch === 44) {
|
|
4095
|
-
flush();
|
|
4096
|
-
if (ch === 59) {
|
|
4097
|
-
lines.push(current);
|
|
4098
|
-
current = { columns: [], sources: [] };
|
|
4099
|
-
column = 0;
|
|
4100
|
-
}
|
|
4101
|
-
continue;
|
|
4102
|
-
}
|
|
4103
|
-
const digit = ch < 128 ? BASE64_VALUE[ch] : -1;
|
|
4104
|
-
if (digit < 0) continue;
|
|
4105
|
-
value += (digit & 31) << shift;
|
|
4106
|
-
if (digit & 32) {
|
|
4107
|
-
shift += 5;
|
|
4108
|
-
continue;
|
|
4109
|
-
}
|
|
4110
|
-
fields.push(value & 1 ? -(value >>> 1) : value >>> 1);
|
|
4111
|
-
value = 0;
|
|
4112
|
-
shift = 0;
|
|
4113
|
-
}
|
|
4114
|
-
for (const line of lines) {
|
|
4115
|
-
if (line.columns.every((c, i) => i === 0 || c >= line.columns[i - 1])) continue;
|
|
4116
|
-
const order = line.columns.map((_, i) => i).sort((a, b) => line.columns[a] - line.columns[b]);
|
|
4117
|
-
line.columns = order.map((i) => line.columns[i]);
|
|
4118
|
-
line.sources = order.map((i) => line.sources[i]);
|
|
4119
|
-
}
|
|
4120
|
-
return lines;
|
|
4121
|
-
}
|
|
4122
|
-
function joinRoot(root, source) {
|
|
4123
|
-
if (!root || /^[a-z][\w+.-]*:/i.test(source) || source.startsWith("/")) return source;
|
|
4124
|
-
return root.endsWith("/") ? root + source : `${root}/${source}`;
|
|
4125
|
-
}
|
|
4126
|
-
function decodeSourceMap(raw) {
|
|
4127
|
-
const sources = [];
|
|
4128
|
-
const lines = [];
|
|
4129
|
-
const add = (map, lineOffset, columnOffset) => {
|
|
4130
|
-
if (map.sections) {
|
|
4131
|
-
for (const section of map.sections) {
|
|
4132
|
-
if (!add(section.map, section.offset.line, section.offset.column)) return false;
|
|
4133
|
-
}
|
|
4134
|
-
return true;
|
|
4135
|
-
}
|
|
4136
|
-
if (typeof map.mappings !== "string" || !Array.isArray(map.sources)) return false;
|
|
4137
|
-
const base = sources.length;
|
|
4138
|
-
for (const s of map.sources) sources.push(joinRoot(map.sourceRoot, s ?? ""));
|
|
4139
|
-
decodeMappings(map.mappings, base).forEach((segments, i) => {
|
|
4140
|
-
const at = lineOffset + i;
|
|
4141
|
-
const shifted = i === 0 && columnOffset ? segments.columns.map((c) => c + columnOffset) : segments.columns;
|
|
4142
|
-
const existing = lines[at];
|
|
4143
|
-
if (!existing) lines[at] = { columns: shifted, sources: segments.sources };
|
|
4144
|
-
else {
|
|
4145
|
-
existing.columns.push(...shifted);
|
|
4146
|
-
existing.sources.push(...segments.sources);
|
|
4147
|
-
}
|
|
4148
|
-
});
|
|
4149
|
-
return true;
|
|
4150
|
-
};
|
|
4151
|
-
if (raw.version !== void 0 && raw.version !== 3) return null;
|
|
4152
|
-
if (!add(raw, 0, 0)) return null;
|
|
4153
|
-
return {
|
|
4154
|
-
sources,
|
|
4155
|
-
sourceAt(line, column) {
|
|
4156
|
-
const segments = lines[line];
|
|
4157
|
-
if (!segments || segments.columns.length === 0) return null;
|
|
4158
|
-
let lo = 0;
|
|
4159
|
-
let hi = segments.columns.length - 1;
|
|
4160
|
-
if (segments.columns[0] > column) return null;
|
|
4161
|
-
while (lo < hi) {
|
|
4162
|
-
const mid = lo + hi + 1 >> 1;
|
|
4163
|
-
if (segments.columns[mid] <= column) lo = mid;
|
|
4164
|
-
else hi = mid - 1;
|
|
4165
|
-
}
|
|
4166
|
-
const source = segments.sources[lo];
|
|
4167
|
-
return source < 0 ? null : source;
|
|
4168
|
-
},
|
|
4169
|
-
mapsBetween(source, start, end) {
|
|
4170
|
-
for (let line = start.line; line <= end.line && line < lines.length; line++) {
|
|
4171
|
-
const segments = lines[line];
|
|
4172
|
-
if (!segments) continue;
|
|
4173
|
-
let i = 0;
|
|
4174
|
-
if (line === start.line) {
|
|
4175
|
-
let hi = segments.columns.length;
|
|
4176
|
-
while (i < hi) {
|
|
4177
|
-
const mid = i + hi >> 1;
|
|
4178
|
-
if (segments.columns[mid] < start.column) i = mid + 1;
|
|
4179
|
-
else hi = mid;
|
|
4180
|
-
}
|
|
4181
|
-
}
|
|
4182
|
-
for (; i < segments.columns.length; i++) {
|
|
4183
|
-
if (line === end.line && segments.columns[i] >= end.column) return false;
|
|
4184
|
-
if (segments.sources[i] === source) return true;
|
|
4185
|
-
}
|
|
4186
|
-
}
|
|
4187
|
-
return false;
|
|
4188
|
-
}
|
|
4189
|
-
};
|
|
4190
|
-
}
|
|
4191
|
-
function lineStarts(text) {
|
|
4192
|
-
const starts = [0];
|
|
4193
|
-
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) starts.push(i + 1);
|
|
4194
|
-
return starts;
|
|
4195
|
-
}
|
|
4196
|
-
function offsetToPosition(starts, offset) {
|
|
4197
|
-
let lo = 0;
|
|
4198
|
-
let hi = starts.length - 1;
|
|
4199
|
-
while (lo < hi) {
|
|
4200
|
-
const mid = lo + hi + 1 >> 1;
|
|
4201
|
-
if (starts[mid] <= offset) lo = mid;
|
|
4202
|
-
else hi = mid - 1;
|
|
4203
|
-
}
|
|
4204
|
-
return { line: lo, column: offset - starts[lo] };
|
|
4205
|
-
}
|
|
4206
|
-
function sourceMappingUrl(script) {
|
|
4207
|
-
const tail = script.slice(-4096);
|
|
4208
|
-
const matches = [...tail.matchAll(/(?:\/\/|\/\*)[#@]\s*sourceMappingURL=([^\s*'"]+)/g)];
|
|
4209
|
-
return matches.length ? matches[matches.length - 1][1] : null;
|
|
4210
|
-
}
|
|
4211
|
-
function decodeDataUrl(url) {
|
|
4212
|
-
const m = /^data:([^,]*?)(;base64)?,(.*)$/s.exec(url);
|
|
4213
|
-
if (!m) return null;
|
|
4214
|
-
try {
|
|
4215
|
-
if (!m[2]) return decodeURIComponent(m[3]);
|
|
4216
|
-
const binary = globalThis.atob(m[3]);
|
|
4217
|
-
const bytes = new Uint8Array(binary.length);
|
|
4218
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
4219
|
-
return new TextDecoder().decode(bytes);
|
|
4220
|
-
} catch {
|
|
4221
|
-
return null;
|
|
4222
|
-
}
|
|
4223
|
-
}
|
|
4224
|
-
function normalizeSourcePath(source) {
|
|
4225
|
-
let s = source.replace(/[?#].*$/, "");
|
|
4226
|
-
s = s.replace(/^webpack:\/\/[^/]*\//, "").replace(/^webpack:\/\//, "");
|
|
4227
|
-
s = s.replace(/^(?:vite|rollup|turbopack|ng):\/*/, "");
|
|
4228
|
-
s = s.replace(/^\[project\]\//, "");
|
|
4229
|
-
s = s.replace(/^file:\/\//, "");
|
|
4230
|
-
s = s.replace(/^\/@fs\//, "/");
|
|
4231
|
-
s = s.replace(/^\/@id\//, "");
|
|
4232
|
-
try {
|
|
4233
|
-
s = decodeURIComponent(s);
|
|
4234
|
-
} catch {
|
|
4235
|
-
}
|
|
4236
|
-
s = s.replace(/\\/g, "/");
|
|
4237
|
-
if (/^\/[A-Za-z]:\//.test(s)) s = s.slice(1);
|
|
4238
|
-
s = s.replace(/(^|\/)\.\//g, "$1");
|
|
4239
|
-
return s;
|
|
4240
|
-
}
|
|
4241
|
-
|
|
4242
|
-
// ../core/src/code-reach.ts
|
|
4243
|
-
var MAX_CODE_REACH_FILES = 2e3;
|
|
4244
|
-
function executedFunctionRanges(entry) {
|
|
4245
|
-
const length = entry.source?.length ?? Number.POSITIVE_INFINITY;
|
|
4246
|
-
const out = [];
|
|
4247
|
-
entry.functions.forEach((fn, i) => {
|
|
4248
|
-
const whole = fn.ranges[0];
|
|
4249
|
-
if (!whole || whole.count <= 0) return;
|
|
4250
|
-
const topLevel = whole.startOffset === 0 && (whole.endOffset >= length || i === 0 && fn.functionName === "");
|
|
4251
|
-
if (topLevel) return;
|
|
4252
|
-
out.push({ start: whole.startOffset, end: whole.endOffset });
|
|
4253
|
-
});
|
|
4254
|
-
return out;
|
|
4255
|
-
}
|
|
4256
|
-
function executedFunctionOffsets(entry) {
|
|
4257
|
-
return executedFunctionRanges(entry).map((range) => range.start);
|
|
4258
|
-
}
|
|
4259
|
-
function scriptRan(entry) {
|
|
4260
|
-
return executedFunctionOffsets(entry).length > 0;
|
|
4261
|
-
}
|
|
4262
|
-
function reachedSources(entry, map) {
|
|
4263
|
-
const ranges = executedFunctionRanges(entry);
|
|
4264
|
-
const reached = /* @__PURE__ */ new Set();
|
|
4265
|
-
if (!ranges.length || entry.source === void 0) return reached;
|
|
4266
|
-
const starts = lineStarts(entry.source);
|
|
4267
|
-
for (const range of ranges) {
|
|
4268
|
-
const start = offsetToPosition(starts, range.start);
|
|
4269
|
-
const source = map.sourceAt(start.line, start.column);
|
|
4270
|
-
if (source === null || reached.has(source)) continue;
|
|
4271
|
-
if (map.mapsBetween(source, start, offsetToPosition(starts, range.end))) reached.add(source);
|
|
4272
|
-
}
|
|
4273
|
-
return reached;
|
|
4274
|
-
}
|
|
4275
|
-
function finalizeCodeReach(files) {
|
|
4276
|
-
const out = /* @__PURE__ */ new Set();
|
|
4277
|
-
for (const raw of files) {
|
|
4278
|
-
const file = normalizeCoveragePath(raw);
|
|
4279
|
-
if (file !== null) out.add(file);
|
|
4280
|
-
}
|
|
4281
|
-
return [...out].sort().slice(0, MAX_CODE_REACH_FILES);
|
|
4282
|
-
}
|
|
4283
|
-
|
|
4284
|
-
// src/internal/capture/code-reach.ts
|
|
4285
4528
|
var MAX_MAP_BYTES = 20 * 1024 * 1024;
|
|
4286
4529
|
var MAP_TIMEOUT_MS = 5e3;
|
|
4287
4530
|
var SOURCE_EXTENSIONS = /\.(?:[cm]?[jt]sx?|vue|svelte|astro|marko|html?)$/i;
|
|
4288
4531
|
var REPLAYED_SCRIPT = /^(?:about|rsc):/i;
|
|
4532
|
+
var NEVER_REACHED = /\/node_modules\/|\/@vite\//;
|
|
4289
4533
|
var BUILD_DIRS = /(?:^|\/)(?:dist|build|out|\.output|\.next|\.nuxt|\.svelte-kit|public|static|wwwroot)\//;
|
|
4290
|
-
var MAX_CACHED_SCRIPTS =
|
|
4534
|
+
var MAX_CACHED_SCRIPTS = 4e3;
|
|
4291
4535
|
var LatestByUrl = class {
|
|
4292
4536
|
constructor() {
|
|
4293
4537
|
this.entries = /* @__PURE__ */ new Map();
|
|
@@ -4327,8 +4571,32 @@ function repositoryRoot(from) {
|
|
|
4327
4571
|
}
|
|
4328
4572
|
function codeReachRoots(configDir, configured) {
|
|
4329
4573
|
const repoRoot = repositoryRoot(configDir);
|
|
4330
|
-
const
|
|
4331
|
-
|
|
4574
|
+
const resolve3 = (dirs) => (Array.isArray(dirs) ? dirs : dirs ? [dirs] : []).filter(Boolean).map((r) => path10.resolve(configDir, r));
|
|
4575
|
+
const global = Array.isArray(configured) ? resolve3(configured) : resolve3(configured?.["*"]);
|
|
4576
|
+
const byOrigin = /* @__PURE__ */ new Map();
|
|
4577
|
+
if (configured && !Array.isArray(configured)) {
|
|
4578
|
+
for (const [key, dirs] of Object.entries(configured)) {
|
|
4579
|
+
const origin = key === "*" ? null : originOf2(key);
|
|
4580
|
+
const resolved = resolve3(dirs);
|
|
4581
|
+
if (origin && resolved.length) byOrigin.set(origin, resolved);
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
const roots = global.length ? global : [configDir];
|
|
4585
|
+
return { roots: [.../* @__PURE__ */ new Set([...roots, repoRoot])], byOrigin, repoRoot };
|
|
4586
|
+
}
|
|
4587
|
+
function originOf2(url) {
|
|
4588
|
+
if (!url) return null;
|
|
4589
|
+
try {
|
|
4590
|
+
const origin = new URL(url).origin;
|
|
4591
|
+
return origin === "null" ? null : origin;
|
|
4592
|
+
} catch {
|
|
4593
|
+
return null;
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
function scriptRoots(roots, scriptUrl, pageUrl) {
|
|
4597
|
+
if (!roots.byOrigin?.size) return roots.roots;
|
|
4598
|
+
const own = roots.byOrigin.get(originOf2(scriptUrl) ?? "") ?? roots.byOrigin.get(originOf2(pageUrl) ?? "");
|
|
4599
|
+
return own ? [.../* @__PURE__ */ new Set([...own, ...roots.roots])] : roots.roots;
|
|
4332
4600
|
}
|
|
4333
4601
|
function isFile(file) {
|
|
4334
4602
|
try {
|
|
@@ -4412,50 +4680,96 @@ async function resolveScript(entry, roots, bases, fetchMap) {
|
|
|
4412
4680
|
const version = scriptVersion(entry);
|
|
4413
4681
|
const cached = scriptCache.get(entry.url, version);
|
|
4414
4682
|
if (cached) return cached;
|
|
4415
|
-
const file = fileForUrl(entry.url, roots
|
|
4683
|
+
const file = fileForUrl(entry.url, roots, bases);
|
|
4416
4684
|
const lookup = await loadMap(entry, fetchMap);
|
|
4417
4685
|
let resolution;
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4686
|
+
const text = entry.source === void 0 ? void 0 : scriptText(entry.source);
|
|
4687
|
+
if (file) resolution = { kind: "file", file, lookup, text };
|
|
4688
|
+
else resolution = lookup ? { kind: "map", lookup, files: [], text } : { kind: "none" };
|
|
4689
|
+
if (text) scriptCache.set(entry.url, version, resolution);
|
|
4421
4690
|
return resolution;
|
|
4422
4691
|
}
|
|
4423
|
-
function
|
|
4424
|
-
|
|
4425
|
-
|
|
4692
|
+
function textOf2(entry, resolution) {
|
|
4693
|
+
return resolution.text ?? (entry.source === void 0 ? void 0 : scriptText(entry.source));
|
|
4694
|
+
}
|
|
4695
|
+
async function resolveCodeReach(entries, roots, fetchMap, pageUrl) {
|
|
4696
|
+
return finalizeCodeReach((await resolveReach(entries, roots, fetchMap, pageUrl)).keys());
|
|
4426
4697
|
}
|
|
4427
|
-
async function
|
|
4428
|
-
|
|
4698
|
+
async function resolveCodeReachFunctions(entries, roots, fetchMap, pageUrl, options = {}) {
|
|
4699
|
+
return resolveFunctions(entries, roots, fetchMap, pageUrl, options.known === true);
|
|
4700
|
+
}
|
|
4701
|
+
async function resolveReach(entries, roots, fetchMap, pageUrl) {
|
|
4702
|
+
return (await resolveFunctions(entries, roots, fetchMap, pageUrl, false)).reached;
|
|
4703
|
+
}
|
|
4704
|
+
var knownCache = new LatestByUrl();
|
|
4705
|
+
async function resolveFunctions(entries, roots, fetchMap, pageUrl, withKnown) {
|
|
4706
|
+
const files = /* @__PURE__ */ new Map();
|
|
4707
|
+
const known = /* @__PURE__ */ new Map();
|
|
4708
|
+
const addTo = (into, file, functions) => {
|
|
4709
|
+
const path14 = relativeToRepo(file, roots.repoRoot);
|
|
4710
|
+
const listed = into.get(path14);
|
|
4711
|
+
if (listed) listed.push(...functions);
|
|
4712
|
+
else into.set(path14, [...functions]);
|
|
4713
|
+
};
|
|
4714
|
+
const add = (file, functions) => addTo(files, file, functions);
|
|
4429
4715
|
const bases = viteBases(entries);
|
|
4430
4716
|
const scripts = entries.filter((entry) => entry.url && entry.functions?.length && !REPLAYED_SCRIPT.test(entry.url));
|
|
4431
|
-
const
|
|
4717
|
+
const cached = scripts.map((entry) => scriptCache.get(entry.url, scriptVersion(entry)));
|
|
4432
4718
|
for (const [i, covered] of scripts.entries()) {
|
|
4433
|
-
const
|
|
4719
|
+
const dirs = scriptRoots(roots, covered.url, covered.pageUrl ?? pageUrl);
|
|
4720
|
+
const resolution = cached[i] ?? await resolveScript(covered, dirs, bases, fetchMap);
|
|
4721
|
+
const mapFile = (resolved, index) => {
|
|
4722
|
+
if (resolved.files[index] === void 0) {
|
|
4723
|
+
const source = resolved.lookup.sources[index] ?? "";
|
|
4724
|
+
let absolute = resolveSourcePath(source, dirs);
|
|
4725
|
+
if (!absolute && !/^[a-z][\w+.-]*:/i.test(source)) {
|
|
4726
|
+
try {
|
|
4727
|
+
absolute = fileForUrl(new URL(source, covered.url).href, dirs, bases);
|
|
4728
|
+
} catch {
|
|
4729
|
+
absolute = null;
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
resolved.files[index] = absolute;
|
|
4733
|
+
}
|
|
4734
|
+
return resolved.files[index] ?? null;
|
|
4735
|
+
};
|
|
4434
4736
|
if (resolution.kind === "file") {
|
|
4435
|
-
|
|
4436
|
-
const
|
|
4437
|
-
if (resolution.
|
|
4737
|
+
if (!resolution.file) continue;
|
|
4738
|
+
const text = textOf2(covered, resolution);
|
|
4739
|
+
if (resolution.lookup) {
|
|
4740
|
+
const reached = reachedFunctionLines(covered, resolution.lookup, text);
|
|
4741
|
+
if (reached.size > 0) add(resolution.file, [...reached.values()].flat());
|
|
4742
|
+
} else if (scriptRan(covered, text)) {
|
|
4743
|
+
add(resolution.file, reachedFunctionLines(covered, null, text).get(-1) ?? []);
|
|
4744
|
+
}
|
|
4438
4745
|
} else if (resolution.kind === "map") {
|
|
4439
|
-
const
|
|
4440
|
-
|
|
4441
|
-
if (
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4746
|
+
for (const [index, functions] of reachedFunctionLines(covered, resolution.lookup, textOf2(covered, resolution))) {
|
|
4747
|
+
const file = mapFile(resolution, index);
|
|
4748
|
+
if (file) add(file, functions);
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
if (!withKnown || resolution.kind === "none") continue;
|
|
4752
|
+
const version = scriptVersion(covered);
|
|
4753
|
+
let listed = knownCache.get(covered.url, version);
|
|
4754
|
+
if (!listed || listed.count < covered.functions.length) {
|
|
4755
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
4756
|
+
const text = textOf2(covered, resolution);
|
|
4757
|
+
if (resolution.kind === "file" && resolution.file) {
|
|
4758
|
+
const lines = knownFunctionLines(covered, resolution.lookup, text);
|
|
4759
|
+
const all = resolution.lookup ? [...lines.values()].flat() : lines.get(-1) ?? [];
|
|
4760
|
+
if (all.length > 0) byFile.set(resolution.file, all);
|
|
4761
|
+
} else if (resolution.kind === "map") {
|
|
4762
|
+
for (const [index, functions] of knownFunctionLines(covered, resolution.lookup, text)) {
|
|
4763
|
+
const file = mapFile(resolution, index);
|
|
4764
|
+
if (file) byFile.set(file, [...byFile.get(file) ?? [], ...functions]);
|
|
4452
4765
|
}
|
|
4453
|
-
const file = resolution.files[index];
|
|
4454
|
-
if (file) files.add(relativeToRepo(file, roots.repoRoot));
|
|
4455
4766
|
}
|
|
4767
|
+
listed = { count: covered.functions.length, files: byFile };
|
|
4768
|
+
knownCache.set(covered.url, version, listed);
|
|
4456
4769
|
}
|
|
4770
|
+
for (const [file, functions] of listed.files) addTo(known, file, functions);
|
|
4457
4771
|
}
|
|
4458
|
-
return
|
|
4772
|
+
return { reached: files, known };
|
|
4459
4773
|
}
|
|
4460
4774
|
function pageMapFetcher(page) {
|
|
4461
4775
|
return async (url) => {
|
|
@@ -4479,12 +4793,57 @@ function isChromiumPage(page) {
|
|
|
4479
4793
|
}
|
|
4480
4794
|
}
|
|
4481
4795
|
var captures = /* @__PURE__ */ new WeakMap();
|
|
4796
|
+
var MARK_WORLD = "piwi-code-reach";
|
|
4797
|
+
var MARK_FUNCTION = "piwiCodeReachMark";
|
|
4798
|
+
var MARK_SOURCE = `addEventListener('beforeunload', function ${MARK_FUNCTION}() {});`;
|
|
4799
|
+
var markedDocuments = /* @__PURE__ */ new WeakMap();
|
|
4800
|
+
function marksOf(page) {
|
|
4801
|
+
let marks = markedDocuments.get(page);
|
|
4802
|
+
if (!marks) {
|
|
4803
|
+
marks = /* @__PURE__ */ new Set();
|
|
4804
|
+
markedDocuments.set(page, marks);
|
|
4805
|
+
}
|
|
4806
|
+
return marks;
|
|
4807
|
+
}
|
|
4808
|
+
async function markCurrentDocument(page, cdp) {
|
|
4809
|
+
try {
|
|
4810
|
+
const { frameTree } = await internalCall(page, () => cdp.send("Page.getFrameTree"));
|
|
4811
|
+
const marks = marksOf(page);
|
|
4812
|
+
if (marks.has(frameTree.frame.loaderId)) return;
|
|
4813
|
+
const world = await internalCall(
|
|
4814
|
+
page,
|
|
4815
|
+
() => cdp.send("Page.createIsolatedWorld", { frameId: frameTree.frame.id, worldName: MARK_WORLD })
|
|
4816
|
+
);
|
|
4817
|
+
await internalCall(
|
|
4818
|
+
page,
|
|
4819
|
+
() => cdp.send("Runtime.evaluate", { expression: MARK_SOURCE, contextId: world.executionContextId })
|
|
4820
|
+
);
|
|
4821
|
+
marks.add(frameTree.frame.loaderId);
|
|
4822
|
+
} catch {
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
function onPaused(page, capture, event) {
|
|
4826
|
+
const leaving = event.reason === "EventListener" && event.data?.eventName === "listener:beforeunload" && (event.callFrames?.[0]?.functionName ?? MARK_FUNCTION) === MARK_FUNCTION;
|
|
4827
|
+
const read = leaving ? readCoverage(page, capture.cdp) : null;
|
|
4828
|
+
if (read) {
|
|
4829
|
+
const merging = read.then(
|
|
4830
|
+
(coverage) => mergeCoverageRead(capture.ran, capture.scripts, coverage, capture.keepIdle)
|
|
4831
|
+
);
|
|
4832
|
+
capture.reading.add(merging);
|
|
4833
|
+
void merging.finally(() => capture.reading.delete(merging));
|
|
4834
|
+
}
|
|
4835
|
+
void (read ?? Promise.resolve()).finally(() => {
|
|
4836
|
+
internalCall(page, () => capture.cdp.send("Debugger.resume")).catch(() => {
|
|
4837
|
+
});
|
|
4838
|
+
});
|
|
4839
|
+
}
|
|
4482
4840
|
function versionKey(url, hash) {
|
|
4483
4841
|
return `${hash} ${url}`;
|
|
4484
4842
|
}
|
|
4485
4843
|
function onScriptParsed(page, capture, event) {
|
|
4486
4844
|
if (!event.url || REPLAYED_SCRIPT.test(event.url)) return;
|
|
4487
|
-
capture.scripts.set(event.scriptId, { url: event.url, hash: event.hash });
|
|
4845
|
+
capture.scripts.set(event.scriptId, { url: event.url, hash: event.hash, pageUrl: capture.pageUrl });
|
|
4846
|
+
if (NEVER_REACHED.test(event.url)) return;
|
|
4488
4847
|
const key = versionKey(event.url, event.hash);
|
|
4489
4848
|
if (capture.sources.has(key) || scriptCache.get(event.url, event.hash)) return;
|
|
4490
4849
|
const source = internalCall(
|
|
@@ -4499,6 +4858,44 @@ function onScriptParsed(page, capture, event) {
|
|
|
4499
4858
|
);
|
|
4500
4859
|
capture.sources.set(key, source);
|
|
4501
4860
|
}
|
|
4861
|
+
var READ_WAIT_MS = 5e3;
|
|
4862
|
+
function readCoverage(page, cdp) {
|
|
4863
|
+
let timer;
|
|
4864
|
+
const late = new Promise((resolve3) => {
|
|
4865
|
+
timer = setTimeout(() => resolve3([]), READ_WAIT_MS);
|
|
4866
|
+
});
|
|
4867
|
+
const taken = internalCall(page, () => cdp.send("Profiler.takePreciseCoverage")).then(
|
|
4868
|
+
(answer) => answer.result,
|
|
4869
|
+
() => []
|
|
4870
|
+
);
|
|
4871
|
+
return Promise.race([taken, late]).finally(() => clearTimeout(timer));
|
|
4872
|
+
}
|
|
4873
|
+
function mergeCoverageRead(ran, scripts, read, keepIdle = true) {
|
|
4874
|
+
for (const covered of read) {
|
|
4875
|
+
const script = scripts.get(covered.scriptId);
|
|
4876
|
+
if (!script) continue;
|
|
4877
|
+
const key = versionKey(script.url, script.hash);
|
|
4878
|
+
let known = ran.get(key);
|
|
4879
|
+
if (!known) {
|
|
4880
|
+
known = { script, functions: [], byRange: /* @__PURE__ */ new Map() };
|
|
4881
|
+
ran.set(key, known);
|
|
4882
|
+
}
|
|
4883
|
+
for (const fn of covered.functions) {
|
|
4884
|
+
const whole = fn.ranges[0];
|
|
4885
|
+
if (!whole) continue;
|
|
4886
|
+
if (!keepIdle && whole.count <= 0) continue;
|
|
4887
|
+
const range = `${whole.startOffset}:${whole.endOffset}`;
|
|
4888
|
+
const seen = known.byRange.get(range);
|
|
4889
|
+
if (seen) {
|
|
4890
|
+
if (whole.count > 0 && seen.ranges[0].count <= 0) seen.ranges[0].count = whole.count;
|
|
4891
|
+
continue;
|
|
4892
|
+
}
|
|
4893
|
+
const copy = { ...fn, ranges: fn.ranges.map((r) => ({ ...r })) };
|
|
4894
|
+
known.byRange.set(range, copy);
|
|
4895
|
+
known.functions.push(copy);
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4502
4899
|
async function detach(page, cdp) {
|
|
4503
4900
|
try {
|
|
4504
4901
|
await internalCall(page, () => cdp.detach());
|
|
@@ -4510,21 +4907,35 @@ async function startCodeReach(page) {
|
|
|
4510
4907
|
let cdp = null;
|
|
4511
4908
|
try {
|
|
4512
4909
|
cdp = await internalCall(page, () => page.context().newCDPSession(page));
|
|
4513
|
-
const capture = {
|
|
4910
|
+
const capture = {
|
|
4911
|
+
cdp,
|
|
4912
|
+
scripts: /* @__PURE__ */ new Map(),
|
|
4913
|
+
sources: /* @__PURE__ */ new Map(),
|
|
4914
|
+
ran: /* @__PURE__ */ new Map(),
|
|
4915
|
+
keepIdle: browserFunctionsInWorker(),
|
|
4916
|
+
reading: /* @__PURE__ */ new Set(),
|
|
4917
|
+
pageUrl: page.url()
|
|
4918
|
+
};
|
|
4919
|
+
const marks = marksOf(page);
|
|
4514
4920
|
cdp.on("Debugger.scriptParsed", (event) => onScriptParsed(page, capture, event));
|
|
4515
|
-
cdp.on("Debugger.paused", () =>
|
|
4516
|
-
|
|
4517
|
-
|
|
4921
|
+
cdp.on("Debugger.paused", (event) => onPaused(page, capture, event));
|
|
4922
|
+
cdp.on("Page.frameNavigated", (event) => {
|
|
4923
|
+
if (event.frame.parentId) return;
|
|
4924
|
+
marks.add(event.frame.loaderId);
|
|
4925
|
+
capture.pageUrl = event.frame.url;
|
|
4518
4926
|
});
|
|
4519
4927
|
await internalCall(
|
|
4520
4928
|
page,
|
|
4521
4929
|
() => Promise.all([
|
|
4522
4930
|
capture.cdp.send("Debugger.enable"),
|
|
4523
|
-
capture.cdp.send("Debugger.setSkipAllPauses", { skip: true }),
|
|
4524
4931
|
capture.cdp.send("Profiler.enable"),
|
|
4525
|
-
capture.cdp.send("Profiler.startPreciseCoverage", { callCount: false, detailed: false })
|
|
4932
|
+
capture.cdp.send("Profiler.startPreciseCoverage", { callCount: false, detailed: false }),
|
|
4933
|
+
capture.cdp.send("Page.enable"),
|
|
4934
|
+
capture.cdp.send("Page.addScriptToEvaluateOnNewDocument", { source: MARK_SOURCE, worldName: MARK_WORLD }),
|
|
4935
|
+
capture.cdp.send("DOMDebugger.setEventListenerBreakpoint", { eventName: "beforeunload" })
|
|
4526
4936
|
])
|
|
4527
4937
|
);
|
|
4938
|
+
await markCurrentDocument(page, capture.cdp);
|
|
4528
4939
|
captures.set(page, capture);
|
|
4529
4940
|
return true;
|
|
4530
4941
|
} catch {
|
|
@@ -4538,17 +4949,17 @@ async function stopCodeReach(page) {
|
|
|
4538
4949
|
captures.delete(page);
|
|
4539
4950
|
const { cdp } = capture;
|
|
4540
4951
|
try {
|
|
4541
|
-
const
|
|
4952
|
+
const last = await internalCall(page, async () => {
|
|
4542
4953
|
const taken = await cdp.send("Profiler.takePreciseCoverage");
|
|
4543
4954
|
await cdp.send("Profiler.stopPreciseCoverage");
|
|
4544
|
-
return taken;
|
|
4955
|
+
return taken.result;
|
|
4545
4956
|
});
|
|
4957
|
+
await Promise.all(capture.reading);
|
|
4958
|
+
mergeCoverageRead(capture.ran, capture.scripts, last, capture.keepIdle);
|
|
4546
4959
|
const entries = [];
|
|
4547
|
-
for (const script of
|
|
4548
|
-
const
|
|
4549
|
-
|
|
4550
|
-
const entry = { url: parsed2.url, hash: parsed2.hash, functions: script.functions };
|
|
4551
|
-
const source = await capture.sources.get(versionKey(parsed2.url, parsed2.hash));
|
|
4960
|
+
for (const [key, { script, functions }] of capture.ran) {
|
|
4961
|
+
const entry = { url: script.url, hash: script.hash, functions, pageUrl: script.pageUrl };
|
|
4962
|
+
const source = await capture.sources.get(key);
|
|
4552
4963
|
if (source != null) entry.source = source;
|
|
4553
4964
|
entries.push(entry);
|
|
4554
4965
|
}
|
|
@@ -5721,52 +6132,89 @@ function createSink() {
|
|
|
5721
6132
|
userPick: null,
|
|
5722
6133
|
pause: null,
|
|
5723
6134
|
locatorPages: new LocatorPageLog(),
|
|
5724
|
-
codeReach:
|
|
6135
|
+
codeReach: { sessions: /* @__PURE__ */ new Map(), files: /* @__PURE__ */ new Map(), known: /* @__PURE__ */ new Map() },
|
|
5725
6136
|
serverCoverage: /* @__PURE__ */ new Map(),
|
|
5726
6137
|
baseURL: null
|
|
5727
6138
|
};
|
|
5728
6139
|
}
|
|
5729
|
-
|
|
6140
|
+
var MAX_CODE_REACH_PAGES = 16;
|
|
6141
|
+
var CODE_REACH_START_WAIT_MS = 2e3;
|
|
6142
|
+
function maybeStartCodeReach(page, alreadyOpen = false) {
|
|
5730
6143
|
const sink = currentSink;
|
|
5731
|
-
if (!sink || !browserCoverageInWorker()) return Promise.resolve(false);
|
|
5732
|
-
|
|
6144
|
+
if (!sink || !browserCoverageInWorker() || isPageClosed(page)) return Promise.resolve(false);
|
|
6145
|
+
const known = sink.codeReach.sessions.get(page);
|
|
6146
|
+
if (known) return known.started;
|
|
6147
|
+
if (alreadyOpen) {
|
|
6148
|
+
let recording = 0;
|
|
6149
|
+
for (const [other, session] of sink.codeReach.sessions) if (!session.stopped && !isPageClosed(other)) recording++;
|
|
6150
|
+
if (recording >= MAX_CODE_REACH_PAGES) return Promise.resolve(false);
|
|
6151
|
+
}
|
|
5733
6152
|
const started = startCodeReach(page);
|
|
5734
|
-
sink.codeReach
|
|
6153
|
+
sink.codeReach.sessions.set(page, { started, stopped: false });
|
|
5735
6154
|
return started;
|
|
5736
6155
|
}
|
|
6156
|
+
async function startCodeReachOnOpenPages() {
|
|
6157
|
+
if (!browserCoverageInWorker() || OPEN_PAGES.size === 0) return;
|
|
6158
|
+
const started = Promise.all([...OPEN_PAGES].map((page) => maybeStartCodeReach(page, true)));
|
|
6159
|
+
await Promise.race([started, new Promise((resolve3) => setTimeout(resolve3, CODE_REACH_START_WAIT_MS).unref())]);
|
|
6160
|
+
}
|
|
5737
6161
|
function configuredCodeReachRoots() {
|
|
5738
6162
|
const raw = process.env.PIWI_CODE_REACH_ROOTS?.trim();
|
|
5739
6163
|
if (!raw) return null;
|
|
6164
|
+
const dirs = (value) => (Array.isArray(value) ? value : [value]).filter((r) => typeof r === "string" && r !== "");
|
|
5740
6165
|
try {
|
|
5741
6166
|
const parsed2 = JSON.parse(raw);
|
|
5742
|
-
if (Array.isArray(parsed2)) return parsed2
|
|
6167
|
+
if (Array.isArray(parsed2)) return dirs(parsed2);
|
|
6168
|
+
if (parsed2 && typeof parsed2 === "object") {
|
|
6169
|
+
return Object.fromEntries(Object.entries(parsed2).map(([origin, value]) => [origin, dirs(value)]));
|
|
6170
|
+
}
|
|
5743
6171
|
} catch {
|
|
5744
6172
|
}
|
|
5745
6173
|
return raw.split(path13.delimiter).filter(Boolean);
|
|
5746
6174
|
}
|
|
5747
6175
|
async function stopSinkCodeReach(sink, closing) {
|
|
5748
|
-
const
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
6176
|
+
const stopping = [];
|
|
6177
|
+
const underway = [];
|
|
6178
|
+
for (const [page, session] of sink.codeReach.sessions) {
|
|
6179
|
+
if (session.stopped) {
|
|
6180
|
+
if (!closing && session.stopping) underway.push(session.stopping);
|
|
6181
|
+
continue;
|
|
6182
|
+
}
|
|
6183
|
+
if (closing && closing.page !== page && (!closing.context || pageContext(page) !== closing.context)) continue;
|
|
6184
|
+
session.stopped = true;
|
|
6185
|
+
stopping.push([page, session]);
|
|
5752
6186
|
}
|
|
5753
|
-
|
|
5754
|
-
try {
|
|
5755
|
-
if (!await session.started || isPageClosed(session.page)) return;
|
|
5756
|
-
const entries = await stopCodeReach(session.page);
|
|
5757
|
-
if (!entries) return;
|
|
6187
|
+
if (stopping.length > 0) {
|
|
5758
6188
|
const info = sink.testInfo;
|
|
5759
6189
|
const configFile = info?.config.configFile;
|
|
5760
6190
|
const configDir = configFile ? path13.dirname(configFile) : info?.config.rootDir ?? process.cwd();
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
6191
|
+
const roots = codeReachRoots(configDir, configuredCodeReachRoots());
|
|
6192
|
+
for (const [page, session] of stopping) {
|
|
6193
|
+
session.stopping = stopPageCodeReach(sink, page, session, roots);
|
|
6194
|
+
underway.push(session.stopping);
|
|
6195
|
+
}
|
|
6196
|
+
}
|
|
6197
|
+
await Promise.all(underway);
|
|
6198
|
+
}
|
|
6199
|
+
async function stopPageCodeReach(sink, page, session, roots) {
|
|
6200
|
+
try {
|
|
6201
|
+
if (!await session.started || isPageClosed(page)) return;
|
|
6202
|
+
const entries = await stopCodeReach(page);
|
|
6203
|
+
if (!entries) return;
|
|
6204
|
+
const { reached, known } = await resolveCodeReachFunctions(entries, roots, pageMapFetcher(page), page.url(), {
|
|
6205
|
+
known: browserFunctionsInWorker()
|
|
6206
|
+
});
|
|
6207
|
+
for (const [file, functions] of reached) {
|
|
6208
|
+
sink.codeReach.files.set(file, [...sink.codeReach.files.get(file) ?? [], ...functions]);
|
|
6209
|
+
}
|
|
6210
|
+
for (const [file, functions] of known) {
|
|
6211
|
+
sink.codeReach.known.set(file, [...sink.codeReach.known.get(file) ?? [], ...functions]);
|
|
6212
|
+
}
|
|
5766
6213
|
} catch {
|
|
5767
6214
|
}
|
|
5768
6215
|
}
|
|
5769
6216
|
var currentSink = null;
|
|
6217
|
+
var KNOWN_FUNCTIONS_SENT = /* @__PURE__ */ new Map();
|
|
5770
6218
|
var PENDING_PROBES = /* @__PURE__ */ new Set();
|
|
5771
6219
|
async function drainPendingProbes(capMs) {
|
|
5772
6220
|
if (PENDING_PROBES.size === 0) return;
|
|
@@ -6063,6 +6511,7 @@ async function maybeOpenPicker(sink, closing) {
|
|
|
6063
6511
|
applyPickToSnapshots(sink.capturedLocators, pick);
|
|
6064
6512
|
}
|
|
6065
6513
|
var INSTRUMENTED_PAGES = /* @__PURE__ */ new WeakSet();
|
|
6514
|
+
var OPEN_PAGES = /* @__PURE__ */ new Set();
|
|
6066
6515
|
var INSTRUMENTED_CONTEXTS = /* @__PURE__ */ new WeakSet();
|
|
6067
6516
|
var PATCHED_BROWSERS = /* @__PURE__ */ new WeakSet();
|
|
6068
6517
|
var CHAIN_METHOD_SET = new Set(CHAIN_METHODS);
|
|
@@ -6343,6 +6792,10 @@ var CANCELLED_REQUEST = /^net::ERR_ABORTED$|^NS_BINDING_ABORTED$|^NS_ERROR_ABORT
|
|
|
6343
6792
|
function instrumentPage(page) {
|
|
6344
6793
|
if (!page || INSTRUMENTED_PAGES.has(page)) return;
|
|
6345
6794
|
INSTRUMENTED_PAGES.add(page);
|
|
6795
|
+
if (typeof page.once === "function") {
|
|
6796
|
+
OPEN_PAGES.add(page);
|
|
6797
|
+
page.once("close", () => OPEN_PAGES.delete(page));
|
|
6798
|
+
}
|
|
6346
6799
|
void maybeStartCodeReach(page);
|
|
6347
6800
|
observeOwnApiRequests(page);
|
|
6348
6801
|
const probeSink = currentSink;
|
|
@@ -6679,10 +7132,24 @@ async function flushSink(sink, testInfo) {
|
|
|
6679
7132
|
});
|
|
6680
7133
|
}
|
|
6681
7134
|
await stopSinkCodeReach(sink);
|
|
6682
|
-
if (sink.codeReach
|
|
7135
|
+
if (sink.codeReach.files.size > 0) {
|
|
6683
7136
|
await testInfo.attach(ATTACHMENT_NAMES.codeReach, {
|
|
6684
7137
|
contentType: "application/json",
|
|
6685
|
-
body: Buffer.from(JSON.stringify(sink.codeReach.files))
|
|
7138
|
+
body: Buffer.from(JSON.stringify(finalizeCodeReach(sink.codeReach.files.keys())))
|
|
7139
|
+
});
|
|
7140
|
+
const functions = browserFunctionsInWorker() ? browserFunctionCoverage(sink.codeReach.files) : null;
|
|
7141
|
+
if (functions) {
|
|
7142
|
+
await testInfo.attach(ATTACHMENT_NAMES.browserCoverage, {
|
|
7143
|
+
contentType: "application/json",
|
|
7144
|
+
body: Buffer.from(JSON.stringify(functions))
|
|
7145
|
+
});
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7148
|
+
const known = browserFunctionsInWorker() ? newKnownFunctions(sink.codeReach.known, KNOWN_FUNCTIONS_SENT) : [];
|
|
7149
|
+
for (const part of known) {
|
|
7150
|
+
await testInfo.attach(ATTACHMENT_NAMES.browserFunctions, {
|
|
7151
|
+
contentType: "application/json",
|
|
7152
|
+
body: Buffer.from(JSON.stringify(part))
|
|
6686
7153
|
});
|
|
6687
7154
|
}
|
|
6688
7155
|
if (sink.serverCoverage.size > 0) {
|
|
@@ -6899,6 +7366,7 @@ var piwiFixtures = {
|
|
|
6899
7366
|
activeResourceLedger()?.testStarted(testInfo);
|
|
6900
7367
|
currentSink = sink;
|
|
6901
7368
|
try {
|
|
7369
|
+
await startCodeReachOnOpenPages();
|
|
6902
7370
|
await use();
|
|
6903
7371
|
} finally {
|
|
6904
7372
|
currentSink = null;
|