supercov 0.0.9 → 0.0.12
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 +28 -23
- package/bin/native.js +87 -0
- package/bin/supercov.js +10 -4
- package/package.json +39 -25
- package/{dist → runtime/javascript}/atomic.js +0 -1
- package/{dist → runtime/javascript}/launchSupervisor.js +3 -1
- package/{dist → runtime/javascript}/nodeAssert.js +0 -1
- package/{dist → runtime/javascript}/nodeAssertAdapter.js +0 -1
- package/{dist → runtime/javascript}/nodeAssertStrict.js +0 -1
- package/{dist → runtime/javascript}/nodeTest.js +13 -5
- package/{dist → runtime/javascript}/playwright.js +177 -90
- package/{dist → runtime/javascript}/playwrightReporter.js +0 -1
- package/{dist → runtime/javascript}/provenance.js +0 -1
- package/{dist → runtime/javascript}/register.mjs +52 -1
- package/{dist → runtime/javascript}/resolve-loader.mjs +0 -36
- package/{dist → runtime/javascript}/runnerEvidence.js +6 -5
- package/{dist → runtime/javascript}/runtime.js +308 -27
- package/{dist → runtime/javascript}/transport.js +2 -3
- package/{dist → runtime/javascript}/vitest.js +38 -8
- package/{dist → runtime/javascript}/vitestReporter.js +0 -1
- package/dist/agentJson.d.ts +0 -44
- package/dist/agentJson.d.ts.map +0 -1
- package/dist/agentJson.js +0 -84
- package/dist/agentJson.js.map +0 -1
- package/dist/analyze.d.ts +0 -12
- package/dist/analyze.d.ts.map +0 -1
- package/dist/analyze.js +0 -699
- package/dist/analyze.js.map +0 -1
- package/dist/atomic.d.ts +0 -6
- package/dist/atomic.d.ts.map +0 -1
- package/dist/atomic.js.map +0 -1
- package/dist/buildCache.d.ts +0 -14
- package/dist/buildCache.d.ts.map +0 -1
- package/dist/buildCache.js +0 -84
- package/dist/buildCache.js.map +0 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -706
- package/dist/cli.js.map +0 -1
- package/dist/directInstrumenter.d.ts +0 -8
- package/dist/directInstrumenter.d.ts.map +0 -1
- package/dist/directInstrumenter.js +0 -92
- package/dist/directInstrumenter.js.map +0 -1
- package/dist/esmInterceptor.d.ts +0 -6
- package/dist/esmInterceptor.d.ts.map +0 -1
- package/dist/esmInterceptor.js +0 -63
- package/dist/esmInterceptor.js.map +0 -1
- package/dist/evidenceArchive.d.ts +0 -37
- package/dist/evidenceArchive.d.ts.map +0 -1
- package/dist/evidenceArchive.js +0 -110
- package/dist/evidenceArchive.js.map +0 -1
- package/dist/instrumenter.d.ts +0 -11
- package/dist/instrumenter.d.ts.map +0 -1
- package/dist/instrumenter.js +0 -1246
- package/dist/instrumenter.js.map +0 -1
- package/dist/integrity.d.ts +0 -10
- package/dist/integrity.d.ts.map +0 -1
- package/dist/integrity.js +0 -205
- package/dist/integrity.js.map +0 -1
- package/dist/launchSupervisor.d.ts +0 -38
- package/dist/launchSupervisor.d.ts.map +0 -1
- package/dist/launchSupervisor.js.map +0 -1
- package/dist/merge.d.ts +0 -2
- package/dist/merge.d.ts.map +0 -1
- package/dist/merge.js +0 -116
- package/dist/merge.js.map +0 -1
- package/dist/nodeAssert.d.ts +0 -31
- package/dist/nodeAssert.d.ts.map +0 -1
- package/dist/nodeAssert.js.map +0 -1
- package/dist/nodeAssertAdapter.d.ts +0 -6
- package/dist/nodeAssertAdapter.d.ts.map +0 -1
- package/dist/nodeAssertAdapter.js.map +0 -1
- package/dist/nodeAssertStrict.d.ts +0 -31
- package/dist/nodeAssertStrict.d.ts.map +0 -1
- package/dist/nodeAssertStrict.js.map +0 -1
- package/dist/nodeAssertionInstrumenter.d.ts +0 -8
- package/dist/nodeAssertionInstrumenter.d.ts.map +0 -1
- package/dist/nodeAssertionInstrumenter.js +0 -263
- package/dist/nodeAssertionInstrumenter.js.map +0 -1
- package/dist/nodeTest.d.ts +0 -15
- package/dist/nodeTest.d.ts.map +0 -1
- package/dist/nodeTest.js.map +0 -1
- package/dist/playwright.d.ts +0 -9
- package/dist/playwright.d.ts.map +0 -1
- package/dist/playwright.js.map +0 -1
- package/dist/playwrightReporter.d.ts +0 -6
- package/dist/playwrightReporter.d.ts.map +0 -1
- package/dist/playwrightReporter.js.map +0 -1
- package/dist/project.d.ts +0 -20
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js +0 -296
- package/dist/project.js.map +0 -1
- package/dist/provenance.d.ts +0 -9
- package/dist/provenance.d.ts.map +0 -1
- package/dist/provenance.js.map +0 -1
- package/dist/query.d.ts +0 -70
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js +0 -1443
- package/dist/query.js.map +0 -1
- package/dist/queryCache.d.ts +0 -15
- package/dist/queryCache.d.ts.map +0 -1
- package/dist/queryCache.js +0 -95
- package/dist/queryCache.js.map +0 -1
- package/dist/queueAdapters.d.ts +0 -15
- package/dist/queueAdapters.d.ts.map +0 -1
- package/dist/queueAdapters.js +0 -55
- package/dist/queueAdapters.js.map +0 -1
- package/dist/register.d.mts +0 -2
- package/dist/register.d.mts.map +0 -1
- package/dist/register.mjs.map +0 -1
- package/dist/reporter.d.ts +0 -13
- package/dist/reporter.d.ts.map +0 -1
- package/dist/reporter.js +0 -252
- package/dist/reporter.js.map +0 -1
- package/dist/resolve-loader.d.mts +0 -3
- package/dist/resolve-loader.d.mts.map +0 -1
- package/dist/resolve-loader.mjs.map +0 -1
- package/dist/runAnalysis.d.ts +0 -19
- package/dist/runAnalysis.d.ts.map +0 -1
- package/dist/runAnalysis.js +0 -169
- package/dist/runAnalysis.js.map +0 -1
- package/dist/runnerEvidence.d.ts +0 -19
- package/dist/runnerEvidence.d.ts.map +0 -1
- package/dist/runnerEvidence.js.map +0 -1
- package/dist/runtime.d.ts +0 -88
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/runtimeIsolation.d.ts +0 -3
- package/dist/runtimeIsolation.d.ts.map +0 -1
- package/dist/runtimeIsolation.js +0 -9
- package/dist/runtimeIsolation.js.map +0 -1
- package/dist/sourceDiscovery.d.ts +0 -9
- package/dist/sourceDiscovery.d.ts.map +0 -1
- package/dist/sourceDiscovery.js +0 -238
- package/dist/sourceDiscovery.js.map +0 -1
- package/dist/transport.d.ts +0 -17
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js.map +0 -1
- package/dist/types.d.ts +0 -378
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/vitePlugin.d.ts +0 -13
- package/dist/vitePlugin.d.ts.map +0 -1
- package/dist/vitePlugin.js +0 -125
- package/dist/vitePlugin.js.map +0 -1
- package/dist/vitest.d.ts +0 -2
- package/dist/vitest.d.ts.map +0 -1
- package/dist/vitest.js.map +0 -1
- package/dist/vitestReporter.d.ts +0 -43
- package/dist/vitestReporter.d.ts.map +0 -1
- package/dist/vitestReporter.js.map +0 -1
- package/dist/workspace.d.ts +0 -81
- package/dist/workspace.d.ts.map +0 -1
- package/dist/workspace.js +0 -504
- package/dist/workspace.js.map +0 -1
|
@@ -105,6 +105,7 @@ class CoveragePhaseController {
|
|
|
105
105
|
pendingRegistrations = new Set();
|
|
106
106
|
scriptUpdate = Promise.resolve();
|
|
107
107
|
proxyCache = new WeakMap();
|
|
108
|
+
runtimeSnapshots;
|
|
108
109
|
// Parameter properties are stateful despite the base ESLint rule treating
|
|
109
110
|
// this as an empty constructor.
|
|
110
111
|
// eslint-disable-next-line no-useless-constructor
|
|
@@ -118,6 +119,41 @@ class CoveragePhaseController {
|
|
|
118
119
|
allWorkers() {
|
|
119
120
|
return [...this.workers];
|
|
120
121
|
}
|
|
122
|
+
async collectRuntimeSnapshots() {
|
|
123
|
+
if (this.runtimeSnapshots)
|
|
124
|
+
return this.runtimeSnapshots;
|
|
125
|
+
const snapshots = [];
|
|
126
|
+
for (const page of this.allPages()) {
|
|
127
|
+
for (const frame of page.frames()) {
|
|
128
|
+
const snapshot = await frame
|
|
129
|
+
.evaluate(() => {
|
|
130
|
+
const getSnapshot = globalThis.__SUPERCOV_COVERAGE_SNAPSHOT__;
|
|
131
|
+
return getSnapshot?.() ?? { decisions: [], hits: [], events: [] };
|
|
132
|
+
})
|
|
133
|
+
.catch(() => ({
|
|
134
|
+
decisions: [],
|
|
135
|
+
hits: [],
|
|
136
|
+
events: [],
|
|
137
|
+
}));
|
|
138
|
+
snapshots.push(snapshot);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (const worker of this.allWorkers()) {
|
|
142
|
+
const snapshot = await worker
|
|
143
|
+
.evaluate(() => {
|
|
144
|
+
const getSnapshot = globalThis.__SUPERCOV_COVERAGE_SNAPSHOT__;
|
|
145
|
+
return getSnapshot?.() ?? { decisions: [], hits: [], events: [] };
|
|
146
|
+
})
|
|
147
|
+
.catch(() => ({
|
|
148
|
+
decisions: [],
|
|
149
|
+
hits: [],
|
|
150
|
+
events: [],
|
|
151
|
+
}));
|
|
152
|
+
snapshots.push(snapshot);
|
|
153
|
+
}
|
|
154
|
+
this.runtimeSnapshots = snapshots;
|
|
155
|
+
return snapshots;
|
|
156
|
+
}
|
|
121
157
|
async registerPage(page) {
|
|
122
158
|
if (this.pages.has(page))
|
|
123
159
|
return;
|
|
@@ -190,6 +226,7 @@ class CoveragePhaseController {
|
|
|
190
226
|
globalThis.__SUPERCOV_MCDC_TEST_ID__ = attemptId;
|
|
191
227
|
if (phase)
|
|
192
228
|
globalThis.__SUPERCOV_PHASE_ID__ = phase;
|
|
229
|
+
globalThis.__SUPERCOV_ACTIVATE_PROBE_CONTEXT__?.(attemptId, phase);
|
|
193
230
|
const originalFetch = globalThis.fetch?.bind(globalThis);
|
|
194
231
|
if (!originalFetch)
|
|
195
232
|
return;
|
|
@@ -217,8 +254,8 @@ class CoveragePhaseController {
|
|
|
217
254
|
await this.activateInBrowser(phase.id);
|
|
218
255
|
return phase;
|
|
219
256
|
}
|
|
220
|
-
beginAssertion(operation) {
|
|
221
|
-
const phase = this.createPhase("assertion", operation, this.lastActionId);
|
|
257
|
+
beginAssertion(operation, source = callerSource()) {
|
|
258
|
+
const phase = this.createPhase("assertion", operation, this.lastActionId, source);
|
|
222
259
|
this.activePhaseId = phase.id;
|
|
223
260
|
// Playwright queues browser protocol commands in order. Starting this
|
|
224
261
|
// evaluation before an async locator assertion is sufficient to tag its
|
|
@@ -294,8 +331,7 @@ class CoveragePhaseController {
|
|
|
294
331
|
this.proxyCache.set(target, proxy);
|
|
295
332
|
return proxy;
|
|
296
333
|
}
|
|
297
|
-
createPhase(kind, operation, causedByPhaseId) {
|
|
298
|
-
const source = callerSource();
|
|
334
|
+
createPhase(kind, operation, causedByPhaseId, source = callerSource()) {
|
|
299
335
|
const phase = {
|
|
300
336
|
id: `${this.scope.attemptId}:phase:${++this.counter}`,
|
|
301
337
|
kind,
|
|
@@ -369,6 +405,8 @@ class CoveragePhaseController {
|
|
|
369
405
|
await Promise.all([...this.pages].flatMap((page) => page.frames()).map((frame) => frame
|
|
370
406
|
.evaluate(({ id, storageKey, scopeCookie, scopeValue, phaseCookie }) => {
|
|
371
407
|
globalThis.__SUPERCOV_PHASE_ID__ = id;
|
|
408
|
+
const coverageGlobal = globalThis;
|
|
409
|
+
coverageGlobal.__SUPERCOV_ACTIVATE_PROBE_CONTEXT__?.(coverageGlobal.__SUPERCOV_MCDC_TEST_ID__ ?? "unscoped", id);
|
|
372
410
|
try {
|
|
373
411
|
localStorage.setItem(storageKey, id);
|
|
374
412
|
document.cookie = `${scopeCookie}=${encodeURIComponent(scopeValue)}; Path=/; SameSite=Lax`;
|
|
@@ -387,7 +425,9 @@ class CoveragePhaseController {
|
|
|
387
425
|
.catch(() => undefined)));
|
|
388
426
|
await Promise.all([...this.workers].map((worker) => worker
|
|
389
427
|
.evaluate((id) => {
|
|
390
|
-
|
|
428
|
+
const coverageGlobal = globalThis;
|
|
429
|
+
coverageGlobal.__SUPERCOV_PHASE_ID__ = id;
|
|
430
|
+
coverageGlobal.__SUPERCOV_ACTIVATE_PROBE_CONTEXT__?.(coverageGlobal.__SUPERCOV_MCDC_TEST_ID__ ?? "unscoped", id);
|
|
391
431
|
}, phaseId)
|
|
392
432
|
.catch(() => undefined)));
|
|
393
433
|
await Promise.all([...this.pages].map((page) => this.activatePage(page, phaseId)));
|
|
@@ -414,7 +454,7 @@ class CoveragePhaseController {
|
|
|
414
454
|
}
|
|
415
455
|
const installed = (await cdp
|
|
416
456
|
.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
417
|
-
source: `globalThis.__SUPERCOV_PHASE_ID__=${JSON.stringify(phaseId)};`,
|
|
457
|
+
source: `globalThis.__SUPERCOV_PHASE_ID__=${JSON.stringify(phaseId)};globalThis.__SUPERCOV_ACTIVATE_PROBE_CONTEXT__?.(globalThis.__SUPERCOV_MCDC_TEST_ID__??"unscoped",${JSON.stringify(phaseId)});`,
|
|
418
458
|
runImmediately: true,
|
|
419
459
|
})
|
|
420
460
|
.catch(() => undefined));
|
|
@@ -425,7 +465,40 @@ class CoveragePhaseController {
|
|
|
425
465
|
}
|
|
426
466
|
}
|
|
427
467
|
let activeController;
|
|
468
|
+
let bridgedAssertionDepth = 0;
|
|
428
469
|
const controllers = new Map();
|
|
470
|
+
const directRuntime = () => globalThis.__SUPERCOV_DIRECT_RUNTIME__;
|
|
471
|
+
globalThis.__SUPERCOV_ASSERTION_PHASE_BRIDGE__ = (operation, source, callback) => {
|
|
472
|
+
const controller = activeController;
|
|
473
|
+
const runtime = directRuntime();
|
|
474
|
+
if (!controller || !runtime)
|
|
475
|
+
return { handled: false };
|
|
476
|
+
const phase = controller.beginAssertion(operation, source);
|
|
477
|
+
bridgedAssertionDepth += 1;
|
|
478
|
+
try {
|
|
479
|
+
const value = runtime.withCoverageCarrier({ version: 1, scope: controller.scope, phaseId: phase.id }, callback);
|
|
480
|
+
bridgedAssertionDepth -= 1;
|
|
481
|
+
if (value &&
|
|
482
|
+
typeof value.then === "function")
|
|
483
|
+
return {
|
|
484
|
+
handled: true,
|
|
485
|
+
value: Promise.resolve(value).then((resolved) => {
|
|
486
|
+
controller.finish(phase);
|
|
487
|
+
return resolved;
|
|
488
|
+
}, (error) => {
|
|
489
|
+
controller.finish(phase, error);
|
|
490
|
+
throw error;
|
|
491
|
+
}),
|
|
492
|
+
};
|
|
493
|
+
controller.finish(phase);
|
|
494
|
+
return { handled: true, value };
|
|
495
|
+
}
|
|
496
|
+
catch (error) {
|
|
497
|
+
bridgedAssertionDepth -= 1;
|
|
498
|
+
controller.finish(phase, error);
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
429
502
|
function activeCoverageHeaders() {
|
|
430
503
|
const controller = activeController;
|
|
431
504
|
if (!controller)
|
|
@@ -572,7 +645,9 @@ function wrapMatchers(matchers, path = "expect") {
|
|
|
572
645
|
return value;
|
|
573
646
|
return (...args) => {
|
|
574
647
|
const controller = activeController;
|
|
575
|
-
const phase =
|
|
648
|
+
const phase = bridgedAssertionDepth === 0
|
|
649
|
+
? controller?.beginAssertion(`${path}.${name}`)
|
|
650
|
+
: undefined;
|
|
576
651
|
try {
|
|
577
652
|
const result = Reflect.apply(value, target, args);
|
|
578
653
|
if (result instanceof Promise) {
|
|
@@ -663,22 +738,51 @@ function readServerRecords(scope) {
|
|
|
663
738
|
return [];
|
|
664
739
|
}
|
|
665
740
|
}
|
|
741
|
+
function phaseSourceLine(source) {
|
|
742
|
+
return source?.replace(/:\d+$/, "");
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Playwright's redirected `expect` is the preferred assertion boundary, but
|
|
746
|
+
* its transform loader can bypass Node's resolve hook for project-owned
|
|
747
|
+
* fixture modules. The ahead-of-run frontend therefore keeps a lexical
|
|
748
|
+
* fallback. If both paths observe the same assertion, retain the richer
|
|
749
|
+
* Playwright phase (including action causality) exactly once.
|
|
750
|
+
*/
|
|
751
|
+
function mergeCollectedPhases(controllerPhases, fallbackPhases) {
|
|
752
|
+
const observed = new Map();
|
|
753
|
+
for (const phase of controllerPhases) {
|
|
754
|
+
if (phase.kind !== "assertion")
|
|
755
|
+
continue;
|
|
756
|
+
const key = `${phase.operation}\0${phaseSourceLine(phase.source) ?? ""}`;
|
|
757
|
+
observed.set(key, (observed.get(key) ?? 0) + 1);
|
|
758
|
+
}
|
|
759
|
+
const remaining = fallbackPhases.filter((phase) => {
|
|
760
|
+
if (phase.kind !== "assertion")
|
|
761
|
+
return true;
|
|
762
|
+
const key = `${phase.operation}\0${phaseSourceLine(phase.source) ?? ""}`;
|
|
763
|
+
const count = observed.get(key) ?? 0;
|
|
764
|
+
if (count === 0)
|
|
765
|
+
return true;
|
|
766
|
+
observed.set(key, count - 1);
|
|
767
|
+
return false;
|
|
768
|
+
});
|
|
769
|
+
return [...controllerPhases, ...remaining];
|
|
770
|
+
}
|
|
666
771
|
const instrumentedTest = base.extend({
|
|
667
772
|
page: async ({ page }, use, testInfo) => {
|
|
668
773
|
const scope = executionScope(testInfo);
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
activeController = controller;
|
|
774
|
+
const controller = controllers.get(scope.attemptId);
|
|
775
|
+
if (!controller)
|
|
776
|
+
throw new Error(`Supercov's automatic Playwright collector was not initialized for ${scope.attemptId}`);
|
|
673
777
|
await controller.registerPage(page);
|
|
674
778
|
try {
|
|
675
779
|
await use(controller.wrap(page));
|
|
676
780
|
}
|
|
677
781
|
finally {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
782
|
+
// This fixture still owns a live page. The automatic test fixture tears
|
|
783
|
+
// down after page dependencies and therefore cannot reliably evaluate
|
|
784
|
+
// frames on every Playwright version.
|
|
785
|
+
await controller.collectRuntimeSnapshots();
|
|
682
786
|
}
|
|
683
787
|
},
|
|
684
788
|
browser: [
|
|
@@ -705,8 +809,13 @@ const instrumentedTest = base.extend({
|
|
|
705
809
|
}));
|
|
706
810
|
},
|
|
707
811
|
mcdcAutoCollect: [
|
|
708
|
-
async ({
|
|
812
|
+
async ({}, use, testInfo) => {
|
|
709
813
|
const scope = executionScope(testInfo);
|
|
814
|
+
const configuredHeaders = Object.fromEntries(Object.entries(testInfo.project.use.extraHTTPHeaders ?? {}).map(([name, value]) => [name, String(value)]));
|
|
815
|
+
const controller = new CoveragePhaseController(scope, configuredHeaders);
|
|
816
|
+
controllers.set(scope.attemptId, controller);
|
|
817
|
+
activeController = controller;
|
|
818
|
+
directRuntime()?.activateCoverageScope(scope);
|
|
710
819
|
const serverOutput = serverEvidencePath(scope);
|
|
711
820
|
mkdirSync(serverEvidenceDirectory(scope), { recursive: true });
|
|
712
821
|
rmSync(serverOutput, { force: true });
|
|
@@ -714,81 +823,60 @@ const instrumentedTest = base.extend({
|
|
|
714
823
|
await use();
|
|
715
824
|
}
|
|
716
825
|
finally {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
826
|
+
try {
|
|
827
|
+
const browser = await controller.collectRuntimeSnapshots();
|
|
828
|
+
const server = readServerRecords(scope);
|
|
829
|
+
// Emit an artifact even when this test touched no application source.
|
|
830
|
+
// A complete test-to-coverage matrix must also identify tests that are
|
|
831
|
+
// removable without changing coverage.
|
|
832
|
+
const outputPath = testInfo.outputPath("mcdc.json");
|
|
833
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
834
|
+
const testFile = relative(process.cwd(), testInfo.file)
|
|
835
|
+
.split(sep)
|
|
836
|
+
.join("/");
|
|
837
|
+
const payload = {
|
|
838
|
+
testId: testInfo.testId,
|
|
839
|
+
scope,
|
|
840
|
+
test: testInfo.titlePath.join(" > "),
|
|
841
|
+
testFile,
|
|
842
|
+
title: testInfo.title,
|
|
843
|
+
retry: testInfo.retry,
|
|
844
|
+
status: testInfo.status ?? "unknown",
|
|
845
|
+
expectedStatus: testInfo.expectedStatus,
|
|
846
|
+
provenance: inferTestProvenance({
|
|
847
|
+
runner: "playwright",
|
|
848
|
+
file: testFile,
|
|
849
|
+
project: testInfo.project.name,
|
|
850
|
+
explicitKind: process.env["SUPERCOV_TEST_KIND"],
|
|
851
|
+
}),
|
|
852
|
+
phases: mergeCollectedPhases(controller.phases, directRuntime()?.takeNodeAssertionPhases(scope) ?? []),
|
|
853
|
+
browser,
|
|
854
|
+
server,
|
|
855
|
+
};
|
|
856
|
+
const serialized = `${JSON.stringify(payload)}\n`;
|
|
857
|
+
atomicWriteFileSync(outputPath, serialized);
|
|
858
|
+
// Pool runners may cycle-restore a VM immediately after Playwright
|
|
859
|
+
// exits, which can discard or overwrite the normal artifact copy.
|
|
860
|
+
// Write one uniquely named, one-shot evidence file to the runner's
|
|
861
|
+
// shared directory as well. No test streams into this path.
|
|
862
|
+
const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"] ??
|
|
863
|
+
(GENERATED_EVIDENCE_DIRECTORY.startsWith("__")
|
|
864
|
+
? undefined
|
|
865
|
+
: GENERATED_EVIDENCE_DIRECTORY);
|
|
866
|
+
if (evidenceDirectory) {
|
|
867
|
+
const resolvedDirectory = resolve(process.cwd(), evidenceDirectory);
|
|
868
|
+
const safeTestId = testInfo.testId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
869
|
+
const testEvidenceDirectory = resolve(resolvedDirectory, `${safeTestId}-${testInfo.retry}`);
|
|
870
|
+
mkdirSync(testEvidenceDirectory, { recursive: true });
|
|
871
|
+
atomicWriteFileSync(resolve(testEvidenceDirectory, "mcdc.json"), serialized);
|
|
733
872
|
}
|
|
734
873
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
.catch(() => ({
|
|
742
|
-
decisions: [],
|
|
743
|
-
hits: [],
|
|
744
|
-
events: [],
|
|
745
|
-
}));
|
|
746
|
-
browser.push(workerSnapshot);
|
|
747
|
-
}
|
|
748
|
-
const server = readServerRecords(scope);
|
|
749
|
-
// Emit an artifact even when this test touched no application source.
|
|
750
|
-
// A complete test-to-coverage matrix must also identify tests that are
|
|
751
|
-
// removable without changing coverage.
|
|
752
|
-
const outputPath = testInfo.outputPath("mcdc.json");
|
|
753
|
-
mkdirSync(dirname(outputPath), { recursive: true });
|
|
754
|
-
const testFile = relative(process.cwd(), testInfo.file)
|
|
755
|
-
.split(sep)
|
|
756
|
-
.join("/");
|
|
757
|
-
const payload = {
|
|
758
|
-
testId: testInfo.testId,
|
|
759
|
-
scope,
|
|
760
|
-
test: testInfo.titlePath.join(" > "),
|
|
761
|
-
testFile,
|
|
762
|
-
title: testInfo.title,
|
|
763
|
-
retry: testInfo.retry,
|
|
764
|
-
status: testInfo.status ?? "unknown",
|
|
765
|
-
expectedStatus: testInfo.expectedStatus,
|
|
766
|
-
provenance: inferTestProvenance({
|
|
767
|
-
runner: "playwright",
|
|
768
|
-
file: testFile,
|
|
769
|
-
project: testInfo.project.name,
|
|
770
|
-
explicitKind: process.env["SUPERCOV_TEST_KIND"],
|
|
771
|
-
}),
|
|
772
|
-
phases: controller?.phases ?? [],
|
|
773
|
-
browser,
|
|
774
|
-
server,
|
|
775
|
-
};
|
|
776
|
-
const serialized = `${JSON.stringify(payload)}\n`;
|
|
777
|
-
atomicWriteFileSync(outputPath, serialized);
|
|
778
|
-
// Pool runners may cycle-restore a VM immediately after Playwright
|
|
779
|
-
// exits, which can discard or overwrite the normal artifact copy.
|
|
780
|
-
// Write one uniquely named, one-shot evidence file to the runner's
|
|
781
|
-
// shared directory as well. No test streams into this path.
|
|
782
|
-
const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"] ??
|
|
783
|
-
(GENERATED_EVIDENCE_DIRECTORY.startsWith("__")
|
|
784
|
-
? undefined
|
|
785
|
-
: GENERATED_EVIDENCE_DIRECTORY);
|
|
786
|
-
if (evidenceDirectory) {
|
|
787
|
-
const resolvedDirectory = resolve(process.cwd(), evidenceDirectory);
|
|
788
|
-
const safeTestId = testInfo.testId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
789
|
-
const testEvidenceDirectory = resolve(resolvedDirectory, `${safeTestId}-${testInfo.retry}`);
|
|
790
|
-
mkdirSync(testEvidenceDirectory, { recursive: true });
|
|
791
|
-
atomicWriteFileSync(resolve(testEvidenceDirectory, "mcdc.json"), serialized);
|
|
874
|
+
finally {
|
|
875
|
+
await controller.dispose();
|
|
876
|
+
directRuntime()?.activateCoverageScope();
|
|
877
|
+
if (activeController === controller)
|
|
878
|
+
activeController = undefined;
|
|
879
|
+
controllers.delete(scope.attemptId);
|
|
792
880
|
}
|
|
793
881
|
}
|
|
794
882
|
},
|
|
@@ -797,4 +885,3 @@ const instrumentedTest = base.extend({
|
|
|
797
885
|
});
|
|
798
886
|
export const test = instrumentedTest;
|
|
799
887
|
/*__SUPERCOV_ADAPTER_EXPORTS__*/
|
|
800
|
-
//# sourceMappingURL=playwright.js.map
|
|
@@ -7,9 +7,61 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
9
|
import Module, { register, syncBuiltinESMExports } from "node:module";
|
|
10
|
+
import { closeSync, openSync, unlinkSync } from "node:fs";
|
|
10
11
|
import { resolve } from "node:path";
|
|
11
12
|
import { installLaunchSupervisor } from "./launchSupervisor.js";
|
|
12
13
|
installLaunchSupervisor();
|
|
14
|
+
// Long-running commands are diagnosed without changing their runner's exit
|
|
15
|
+
// semantics. The first preloaded Node process atomically elects itself for the
|
|
16
|
+
// run and periodically reports public active-resource types. This deliberately
|
|
17
|
+
// uses no Unix signal: a launch tree may contain uninstrumented Node children,
|
|
18
|
+
// and signalling one would terminate a healthy command by default.
|
|
19
|
+
if (!process.__SUPERCOV_DIAGNOSTIC_REPORTER__) {
|
|
20
|
+
process.__SUPERCOV_DIAGNOSTIC_REPORTER__ = true;
|
|
21
|
+
const ownerFile = process.env.SUPERCOV_DIAGNOSTIC_OWNER_FILE;
|
|
22
|
+
let ownerDescriptor;
|
|
23
|
+
try {
|
|
24
|
+
if (ownerFile)
|
|
25
|
+
ownerDescriptor = openSync(ownerFile, "wx");
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Another preloaded process owns diagnostics for this run.
|
|
29
|
+
}
|
|
30
|
+
if (ownerDescriptor !== undefined) {
|
|
31
|
+
const configuredInterval = Number(process.env.SUPERCOV_DIAGNOSTIC_INTERVAL_MS ?? 60_000);
|
|
32
|
+
const intervalMs = Number.isSafeInteger(configuredInterval) && configuredInterval > 0
|
|
33
|
+
? configuredInterval
|
|
34
|
+
: 60_000;
|
|
35
|
+
const reportResources = () => {
|
|
36
|
+
const resources = typeof process.getActiveResourcesInfo === "function"
|
|
37
|
+
? process.getActiveResourcesInfo()
|
|
38
|
+
: [];
|
|
39
|
+
const counts = Object.fromEntries([...new Set(resources)].sort().map(resource => [
|
|
40
|
+
resource,
|
|
41
|
+
resources.filter(candidate => candidate === resource).length,
|
|
42
|
+
]));
|
|
43
|
+
console.error(`[supercov:active-resources] ${JSON.stringify({
|
|
44
|
+
pid: process.pid,
|
|
45
|
+
ppid: process.ppid,
|
|
46
|
+
uptimeMs: Math.round(process.uptime() * 1000),
|
|
47
|
+
resources: counts,
|
|
48
|
+
})}`);
|
|
49
|
+
};
|
|
50
|
+
const diagnosticTimer = setInterval(reportResources, intervalMs);
|
|
51
|
+
diagnosticTimer.unref();
|
|
52
|
+
process.once("exit", () => {
|
|
53
|
+
clearInterval(diagnosticTimer);
|
|
54
|
+
try {
|
|
55
|
+
closeSync(ownerDescriptor);
|
|
56
|
+
}
|
|
57
|
+
catch { }
|
|
58
|
+
try {
|
|
59
|
+
unlinkSync(ownerFile);
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
13
65
|
// Assertion-call instrumentation also uses this runtime in test processes
|
|
14
66
|
// whose application build is handled by Vite or another compiler. Loading it
|
|
15
67
|
// for every isolated test launch keeps node:assert attribution runner-agnostic.
|
|
@@ -195,4 +247,3 @@ if (process.env.SUPERCOV_CJS_INTERCEPT === "1") {
|
|
|
195
247
|
return originalLoad.call(this, request, parent, isMain);
|
|
196
248
|
};
|
|
197
249
|
}
|
|
198
|
-
//# sourceMappingURL=register.mjs.map
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
1
|
import { resolve as resolvePath } from "node:path";
|
|
10
2
|
import { pathToFileURL } from "node:url";
|
|
11
3
|
const GENERATED_TARGET = "__SUPERCOV_PLAYWRIGHT_MODULE__";
|
|
@@ -81,31 +73,3 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
81
73
|
}
|
|
82
74
|
return nextResolve(specifier, context);
|
|
83
75
|
}
|
|
84
|
-
export async function load(url, context, nextLoad) {
|
|
85
|
-
const loaded = await nextLoad(url, context);
|
|
86
|
-
const transformer = process.env.SUPERCOV_ESM_TRANSFORMER;
|
|
87
|
-
const wrapper = process.env.SUPERCOV_ESM_CAPABILITY_WRAPPER;
|
|
88
|
-
if (!transformer ||
|
|
89
|
-
!wrapper ||
|
|
90
|
-
loaded.format !== "module" ||
|
|
91
|
-
!belongsToProject(url) ||
|
|
92
|
-
loaded.source === undefined ||
|
|
93
|
-
loaded.source === null)
|
|
94
|
-
return loaded;
|
|
95
|
-
const source = typeof loaded.source === "string"
|
|
96
|
-
? loaded.source
|
|
97
|
-
: Buffer.from(loaded.source).toString("utf8");
|
|
98
|
-
try {
|
|
99
|
-
const { transformCapabilityImports } = await import(__rewriteRelativeImportExtension(transformer));
|
|
100
|
-
const transformed = transformCapabilityImports(source, url, wrapper);
|
|
101
|
-
return transformed.transformed
|
|
102
|
-
? { ...loaded, source: transformed.code }
|
|
103
|
-
: loaded;
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
if (process.env.SUPERCOV_DEBUG === "1")
|
|
107
|
-
console.error("[supercov] ESM capability transform skipped", { url, error });
|
|
108
|
-
return loaded;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
//# sourceMappingURL=resolve-loader.mjs.map
|
|
@@ -52,9 +52,9 @@ export function callerLocation(ignored) {
|
|
|
52
52
|
}
|
|
53
53
|
return {};
|
|
54
54
|
}
|
|
55
|
-
export function readScopedServerEvidence(scope) {
|
|
55
|
+
export function readScopedServerEvidence(scope, evidencePath = serverEvidencePath(scope)) {
|
|
56
56
|
try {
|
|
57
|
-
return readFileSync(
|
|
57
|
+
return readFileSync(evidencePath, "utf8")
|
|
58
58
|
.split("\n")
|
|
59
59
|
.filter(Boolean)
|
|
60
60
|
.map((line) => JSON.parse(line))
|
|
@@ -64,7 +64,7 @@ export function readScopedServerEvidence(scope) {
|
|
|
64
64
|
return [];
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
export function writeRunnerEvidence(identity, status, scope, evidenceDirectoryOverride, phases = []) {
|
|
67
|
+
export function writeRunnerEvidence(identity, status, scope, evidenceDirectoryOverride, phases = [], serverEvidenceSource) {
|
|
68
68
|
const evidenceDirectory = evidenceDirectoryOverride ?? process.env["SUPERCOV_EVIDENCE_DIR"];
|
|
69
69
|
if (!evidenceDirectory)
|
|
70
70
|
return;
|
|
@@ -85,10 +85,11 @@ export function writeRunnerEvidence(identity, status, scope, evidenceDirectoryOv
|
|
|
85
85
|
...(phases.length > 0 ? { phases } : {}),
|
|
86
86
|
runtime: [],
|
|
87
87
|
browser: [],
|
|
88
|
-
server:
|
|
88
|
+
server: serverEvidenceSource
|
|
89
|
+
? readScopedServerEvidence(scope, serverEvidenceSource)
|
|
90
|
+
: readScopedServerEvidence(scope),
|
|
89
91
|
};
|
|
90
92
|
const directory = resolve(process.cwd(), evidenceDirectory, `${identity.runner.replace(/[^A-Za-z0-9_-]/g, "_")}-${scope.attemptId}`);
|
|
91
93
|
mkdirSync(directory, { recursive: true });
|
|
92
94
|
atomicWriteFileSync(resolve(directory, "mcdc.json"), `${JSON.stringify(payload)}\n`);
|
|
93
95
|
}
|
|
94
|
-
//# sourceMappingURL=runnerEvidence.js.map
|