From a51990a1904997db58481e0aa1e30a366eb34896 Mon Sep 17 00:00:00 2001
From: Pietro Marchini <pietro.marchini94@gmail.com>
Date: Wed, 18 Sep 2024 16:24:19 +0000
Subject: [PATCH] test_runner: avoid coverage report partial file names

Co-author: Medhansh404 <21ucs126@lnmiit.ac.in>
PR-URL: https://github.com/nodejs/node/pull/54379
Fixes: https://github.com/nodejs/node/issues/51299
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
---
 lib/internal/test_runner/utils.js             | 155 ++++++++++++----
 .../a-very-long-long-long-sub-dir/c.js        |  52 ++++++
 ...overage-width-100-uncovered-lines.snapshot |  17 +-
 .../output/coverage-width-100.snapshot        |  15 +-
 ...overage-width-150-uncovered-lines.snapshot |  17 +-
 .../output/coverage-width-150.snapshot        |  23 ++-
 .../test-runner/output/coverage-width-40.mjs  |  12 ++
 .../output/coverage-width-40.snapshot         |  33 ++++
 .../output/coverage-width-80-color.mjs        |  12 ++
 .../output/coverage-width-80-color.snapshot   |  26 +++
 ...overage-width-80-uncovered-lines-color.mjs |  13 ++
 ...ge-width-80-uncovered-lines-color.snapshot |  27 +++
 ...coverage-width-80-uncovered-lines.snapshot |  17 +-
 .../output/coverage-width-80.snapshot         |  15 +-
 ...ge-width-infinity-uncovered-lines.snapshot |  25 ++-
 .../output/coverage-width-infinity.snapshot   |  23 ++-
 .../test-runner-coverage-thresholds.js        |  26 +--
 test/parallel/test-runner-coverage.js         | 173 ++++++++++++------
 test/parallel/test-runner-output.mjs          |  19 ++
 19 files changed, 544 insertions(+), 156 deletions(-)
 create mode 100644 test/fixtures/test-runner/coverage-snap/a-very-long-long-long-sub-dir/c.js
 create mode 100644 test/fixtures/test-runner/output/coverage-width-40.mjs
 create mode 100644 test/fixtures/test-runner/output/coverage-width-40.snapshot
 create mode 100644 test/fixtures/test-runner/output/coverage-width-80-color.mjs
 create mode 100644 test/fixtures/test-runner/output/coverage-width-80-color.snapshot
 create mode 100644 test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.mjs
 create mode 100644 test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.snapshot

diff --git a/lib/internal/test_runner/utils.js b/lib/internal/test_runner/utils.js
index 2fc0907c388780..9ad924bcd58793 100644
--- a/lib/internal/test_runner/utils.js
+++ b/lib/internal/test_runner/utils.js
@@ -1,8 +1,10 @@
 'use strict';
 const {
   ArrayPrototypeFlatMap,
+  ArrayPrototypeForEach,
   ArrayPrototypeJoin,
   ArrayPrototypeMap,
+  ArrayPrototypePop,
   ArrayPrototypePush,
   ArrayPrototypeReduce,
   ArrayPrototypeSome,
@@ -24,7 +26,7 @@ const {
 } = primordials;
 
 const { AsyncResource } = require('async_hooks');
-const { relative } = require('path');
+const { relative, sep } = require('path');
 const { createWriteStream } = require('fs');
 const { pathToFileURL } = require('internal/url');
 const { createDeferredPromise } = require('internal/util');
@@ -409,6 +411,36 @@ const kColumns = ['line %', 'branch %', 'funcs %'];
 const kColumnsKeys = ['coveredLinePercent', 'coveredBranchPercent', 'coveredFunctionPercent'];
 const kSeparator = ' | ';
 
+function buildFileTree(summary) {
+  const tree = { __proto__: null };
+  let treeDepth = 1;
+  let longestFile = 0;
+
+  ArrayPrototypeForEach(summary.files, (file) => {
+    let longestPart = 0;
+    const parts = StringPrototypeSplit(relative(summary.workingDirectory, file.path), sep);
+    let current = tree;
+
+    ArrayPrototypeForEach(parts, (part, index) => {
+      if (!current[part]) {
+        current[part] = { __proto__: null };
+      }
+      current = current[part];
+      // If this is the last part, add the file to the tree
+      if (index === parts.length - 1) {
+        current.file = file;
+      }
+      // Keep track of the longest part for padding
+      longestPart = MathMax(longestPart, part.length);
+    });
+
+    treeDepth = MathMax(treeDepth, parts.length);
+    longestFile = MathMax(longestPart, longestFile);
+  });
+
+  return { __proto__: null, tree, treeDepth, longestFile };
+}
+
 function getCoverageReport(pad, summary, symbol, color, table) {
   const prefix = `${pad}${symbol}`;
   let report = `${color}${prefix}start of coverage report\n`;
@@ -418,11 +450,19 @@ function getCoverageReport(pad, summary, symbol, color, table) {
   let uncoveredLinesPadLength;
   let tableWidth;
 
+  // Create a tree of file paths
+  const { tree, treeDepth, longestFile } = buildFileTree(summary);
   if (table) {
-    // Get expected column sizes
-    filePadLength = table && ArrayPrototypeReduce(summary.files, (acc, file) =>
-      MathMax(acc, relative(summary.workingDirectory, file.path).length), 0);
+    // Calculate expected column sizes based on the tree
+    filePadLength = table && longestFile;
+    filePadLength += (treeDepth - 1);
+    if (color) {
+      filePadLength += 2;
+    }
     filePadLength = MathMax(filePadLength, 'file'.length);
+    if (filePadLength > (process.stdout.columns / 2)) {
+      filePadLength = MathFloor(process.stdout.columns / 2);
+    }
     const fileWidth = filePadLength + 2;
 
     columnPadLengths = ArrayPrototypeMap(kColumns, (column) => (table ? MathMax(column.length, 6) : 0));
@@ -435,26 +475,17 @@ function getCoverageReport(pad, summary, symbol, color, table) {
 
     tableWidth = fileWidth + columnsWidth + uncoveredLinesWidth;
 
-    // Fit with sensible defaults
     const availableWidth = (process.stdout.columns || Infinity) - prefix.length;
     const columnsExtras = tableWidth - availableWidth;
     if (table && columnsExtras > 0) {
-      // Ensure file name is sufficiently visible
-      const minFilePad = MathMin(8, filePadLength);
-      filePadLength -= MathFloor(columnsExtras * 0.2);
-      filePadLength = MathMax(filePadLength, minFilePad);
-
-      // Get rest of available space, subtracting margins
+      filePadLength = MathMin(availableWidth * 0.5, filePadLength);
       uncoveredLinesPadLength = MathMax(availableWidth - columnsWidth - (filePadLength + 2) - 2, 1);
-
-      // Update table width
       tableWidth = availableWidth;
     } else {
       uncoveredLinesPadLength = Infinity;
     }
   }
 
-
   function getCell(string, width, pad, truncate, coverage) {
     if (!table) return string;
 
@@ -469,35 +500,85 @@ function getCoverageReport(pad, summary, symbol, color, table) {
     return result;
   }
 
-  // Head
-  if (table) report += addTableLine(prefix, tableWidth);
-  report += `${prefix}${getCell('file', filePadLength, StringPrototypePadEnd, truncateEnd)}${kSeparator}` +
-            `${ArrayPrototypeJoin(ArrayPrototypeMap(kColumns, (column, i) => getCell(column, columnPadLengths[i], StringPrototypePadStart)), kSeparator)}${kSeparator}` +
-            `${getCell('uncovered lines', uncoveredLinesPadLength, false, truncateEnd)}\n`;
-  if (table) report += addTableLine(prefix, tableWidth);
+  function writeReportLine({ file, depth = 0, coveragesColumns, fileCoverage, uncoveredLines }) {
+    const fileColumn = `${prefix}${StringPrototypeRepeat(' ', depth)}${getCell(file, filePadLength - depth, StringPrototypePadEnd, truncateStart, fileCoverage)}`;
+    const coverageColumns = ArrayPrototypeJoin(ArrayPrototypeMap(coveragesColumns, (coverage, j) => {
+      const coverageText = typeof coverage === 'number' ? NumberPrototypeToFixed(coverage, 2) : coverage;
+      return getCell(coverageText, columnPadLengths[j], StringPrototypePadStart, false, coverage);
+    }), kSeparator);
 
-  // Body
-  for (let i = 0; i < summary.files.length; ++i) {
-    const file = summary.files[i];
-    const relativePath = relative(summary.workingDirectory, file.path);
+    const uncoveredLinesColumn = getCell(uncoveredLines, uncoveredLinesPadLength, false, truncateEnd);
 
-    let fileCoverage = 0;
-    const coverages = ArrayPrototypeMap(kColumnsKeys, (columnKey) => {
-      const percent = file[columnKey];
-      fileCoverage += percent;
-      return percent;
-    });
-    fileCoverage /= kColumnsKeys.length;
+    return `${fileColumn}${kSeparator}${coverageColumns}${kSeparator}${uncoveredLinesColumn}\n`;
+  }
 
-    report += `${prefix}${getCell(relativePath, filePadLength, StringPrototypePadEnd, truncateStart, fileCoverage)}${kSeparator}` +
-              `${ArrayPrototypeJoin(ArrayPrototypeMap(coverages, (coverage, j) => getCell(NumberPrototypeToFixed(coverage, 2), columnPadLengths[j], StringPrototypePadStart, false, coverage)), kSeparator)}${kSeparator}` +
-              `${getCell(formatUncoveredLines(getUncoveredLines(file.lines), table), uncoveredLinesPadLength, false, truncateEnd)}\n`;
+  function printCoverageBodyTree(tree, depth = 0) {
+    for (const key in tree) {
+      if (tree[key].file) {
+        const file = tree[key].file;
+        const fileName = ArrayPrototypePop(StringPrototypeSplit(file.path, sep));
+
+        let fileCoverage = 0;
+        const coverages = ArrayPrototypeMap(kColumnsKeys, (columnKey) => {
+          const percent = file[columnKey];
+          fileCoverage += percent;
+          return percent;
+        });
+        fileCoverage /= kColumnsKeys.length;
+
+        const uncoveredLines = formatUncoveredLines(getUncoveredLines(file.lines), table);
+
+        report += writeReportLine({
+          __proto__: null,
+          file: fileName,
+          depth: depth,
+          coveragesColumns: coverages,
+          fileCoverage: fileCoverage,
+          uncoveredLines: uncoveredLines,
+        });
+      } else {
+        report += writeReportLine({
+          __proto__: null,
+          file: key,
+          depth: depth,
+          coveragesColumns: ArrayPrototypeMap(columnPadLengths, () => ''),
+          fileCoverage: undefined,
+          uncoveredLines: '',
+        });
+        printCoverageBodyTree(tree[key], depth + 1);
+      }
+    }
   }
 
-  // Foot
+  // -------------------------- Coverage Report --------------------------
+  if (table) report += addTableLine(prefix, tableWidth);
+
+  // Print the header
+  report += writeReportLine({
+    __proto__: null,
+    file: 'file',
+    coveragesColumns: kColumns,
+    fileCoverage: undefined,
+    uncoveredLines: 'uncovered lines',
+  });
+
+  if (table) report += addTableLine(prefix, tableWidth);
+
+  // Print the body
+  printCoverageBodyTree(tree);
+
   if (table) report += addTableLine(prefix, tableWidth);
-  report += `${prefix}${getCell('all files', filePadLength, StringPrototypePadEnd, truncateEnd)}${kSeparator}` +
-            `${ArrayPrototypeJoin(ArrayPrototypeMap(kColumnsKeys, (columnKey, j) => getCell(NumberPrototypeToFixed(summary.totals[columnKey], 2), columnPadLengths[j], StringPrototypePadStart, false, summary.totals[columnKey])), kSeparator)} |\n`;
+
+  // Print the footer
+  const allFilesCoverages = ArrayPrototypeMap(kColumnsKeys, (columnKey) => summary.totals[columnKey]);
+  report += writeReportLine({
+    __proto__: null,
+    file: 'all files',
+    coveragesColumns: allFilesCoverages,
+    fileCoverage: undefined,
+    uncoveredLines: '',
+  });
+
   if (table) report += addTableLine(prefix, tableWidth);
 
   report += `${prefix}end of coverage report\n`;
diff --git a/test/fixtures/test-runner/coverage-snap/a-very-long-long-long-sub-dir/c.js b/test/fixtures/test-runner/coverage-snap/a-very-long-long-long-sub-dir/c.js
new file mode 100644
index 00000000000000..73ac49a524e60b
--- /dev/null
+++ b/test/fixtures/test-runner/coverage-snap/a-very-long-long-long-sub-dir/c.js
@@ -0,0 +1,52 @@
+'use strict';
+// Here we can't import common module as the coverage will be different based on the system
+
+// Empty functions that don't do anything
+function doNothing1() {
+  // Not implemented
+}
+
+function doNothing2() {
+  // No logic here
+}
+
+function unusedFunction1() {
+  // Intentionally left empty
+}
+
+function unusedFunction2() {
+  // Another empty function
+}
+
+// Unused variables
+const unusedVariable1 = 'This is never used';
+const unusedVariable2 = 42;
+let unusedVariable3;
+
+// Empty class with no methods
+class UnusedClass {
+  constructor() {
+    // Constructor does nothing
+  }
+}
+
+// Empty object literal
+const emptyObject = {};
+
+// Empty array
+const emptyArray = [];
+
+// Function with parameters but no body
+function doNothingWithParams(param1, param2) {
+  // No implementation
+}
+
+// Function that returns nothing
+function returnsNothing() {
+  // No return statement
+}
+
+// Another unused function
+function unusedFunction3() {
+  // More empty code
+}
diff --git a/test/fixtures/test-runner/output/coverage-width-100-uncovered-lines.snapshot b/test/fixtures/test-runner/output/coverage-width-100-uncovered-lines.snapshot
index 560b4e6d13e15b..c410c42fb7eeb9 100644
--- a/test/fixtures/test-runner/output/coverage-width-100-uncovered-lines.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-100-uncovered-lines.snapshot
@@ -15,13 +15,18 @@ ok 1 - Coverage Print Fixed Width 100
 # duration_ms *
 # start of coverage report
 # --------------------------------------------------------------------------------------------------
-# file     | line % | branch % | funcs % | uncovered lines
+# file                                       | line % | branch % | funcs % | uncovered lines
 # --------------------------------------------------------------------------------------------------
-# …ap/a.js |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# …ap/b.js |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# …ines.js |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-6…
-# …nes.mjs | 100.00 |   100.00 |  100.00 | 
+# test                                       |        |          |         | 
+#  fixtures                                  |        |          |         | 
+#   test-runner                              |        |          |         | 
+#    coverage-snap                           |        |          |         | 
+#     a.js                                   |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 …
+#     b.js                                   |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#     many-uncovered-lines.js                |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 …
+#    output                                  |        |          |         | 
+#     coverage-width-100-uncovered-lines.mjs | 100.00 |   100.00 |  100.00 | 
 # --------------------------------------------------------------------------------------------------
-# all fil… |  52.80 |    60.00 |    1.61 |
+# all files                                  |  52.80 |    60.00 |    1.61 | 
 # --------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-100.snapshot b/test/fixtures/test-runner/output/coverage-width-100.snapshot
index a452e0389967db..dfb48005c48eaf 100644
--- a/test/fixtures/test-runner/output/coverage-width-100.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-100.snapshot
@@ -15,12 +15,17 @@ ok 1 - Coverage Print Fixed Width 100
 # duration_ms *
 # start of coverage report
 # --------------------------------------------------------------------------------------------------
-# file                                             | line % | branch % | funcs % | uncovered lines
+# file                       | line % | branch % | funcs % | uncovered lines
 # --------------------------------------------------------------------------------------------------
-# test/fixtures/test-runner/coverage-snap/a.js     |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 …
-# test/fixtures/test-runner/coverage-snap/b.js     |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# …tures/test-runner/output/coverage-width-100.mjs | 100.00 |   100.00 |  100.00 | 
+# test                       |        |          |         | 
+#  fixtures                  |        |          |         | 
+#   test-runner              |        |          |         | 
+#    coverage-snap           |        |          |         | 
+#     a.js                   |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-4…
+#     b.js                   |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#    output                  |        |          |         | 
+#     coverage-width-100.mjs | 100.00 |   100.00 |  100.00 | 
 # --------------------------------------------------------------------------------------------------
-# all files                                        |  60.81 |   100.00 |    0.00 |
+# all files                  |  60.81 |   100.00 |    0.00 | 
 # --------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-150-uncovered-lines.snapshot b/test/fixtures/test-runner/output/coverage-width-150-uncovered-lines.snapshot
index 01f94f2d40a9e6..423dac3291bf74 100644
--- a/test/fixtures/test-runner/output/coverage-width-150-uncovered-lines.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-150-uncovered-lines.snapshot
@@ -15,13 +15,18 @@ ok 1 - Coverage Print Fixed Width 150
 # duration_ms *
 # start of coverage report
 # ----------------------------------------------------------------------------------------------------------------------------------------------------
-# file     | line % | branch % | funcs % | uncovered lines
+# file                                       | line % | branch % | funcs % | uncovered lines
 # ----------------------------------------------------------------------------------------------------------------------------------------------------
-# …ap/a.js |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# …ap/b.js |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# …ines.js |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-61 63-65 67-69 91-93 96-98 100-102 104-106 111-112 …
-# …nes.mjs | 100.00 |   100.00 |  100.00 | 
+# test                                       |        |          |         | 
+#  fixtures                                  |        |          |         | 
+#   test-runner                              |        |          |         | 
+#    coverage-snap                           |        |          |         | 
+#     a.js                                   |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
+#     b.js                                   |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#     many-uncovered-lines.js                |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-61 63-65 67-69 91…
+#    output                                  |        |          |         | 
+#     coverage-width-150-uncovered-lines.mjs | 100.00 |   100.00 |  100.00 | 
 # ----------------------------------------------------------------------------------------------------------------------------------------------------
-# all fil… |  52.80 |    60.00 |    1.61 |
+# all files                                  |  52.80 |    60.00 |    1.61 | 
 # ----------------------------------------------------------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-150.snapshot b/test/fixtures/test-runner/output/coverage-width-150.snapshot
index 37cc1e799fc550..c4aa8109955a12 100644
--- a/test/fixtures/test-runner/output/coverage-width-150.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-150.snapshot
@@ -14,13 +14,18 @@ ok 1 - Coverage Print Fixed Width 150
 # todo 0
 # duration_ms *
 # start of coverage report
-# -------------------------------------------------------------------------------------------------------------------------------------
-# file                                                    | line % | branch % | funcs % | uncovered lines
-# -------------------------------------------------------------------------------------------------------------------------------------
-# test/fixtures/test-runner/coverage-snap/a.js            |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# test/fixtures/test-runner/coverage-snap/b.js            |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# test/fixtures/test-runner/output/coverage-width-150.mjs | 100.00 |   100.00 |  100.00 | 
-# -------------------------------------------------------------------------------------------------------------------------------------
-# all files                                               |  60.81 |   100.00 |    0.00 |
-# -------------------------------------------------------------------------------------------------------------------------------------
+# --------------------------------------------------------------------------------------------------------
+# file                       | line % | branch % | funcs % | uncovered lines
+# --------------------------------------------------------------------------------------------------------
+# test                       |        |          |         | 
+#  fixtures                  |        |          |         | 
+#   test-runner              |        |          |         | 
+#    coverage-snap           |        |          |         | 
+#     a.js                   |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
+#     b.js                   |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#    output                  |        |          |         | 
+#     coverage-width-150.mjs | 100.00 |   100.00 |  100.00 | 
+# --------------------------------------------------------------------------------------------------------
+# all files                  |  60.81 |   100.00 |    0.00 | 
+# --------------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-40.mjs b/test/fixtures/test-runner/output/coverage-width-40.mjs
new file mode 100644
index 00000000000000..2b5330b3b5fff1
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-40.mjs
@@ -0,0 +1,12 @@
+// Flags: --experimental-test-coverage
+// here we can't import common module as the coverage will be different based on the system
+// Unused imports are here in order to populate the coverage report
+import * as a from '../coverage-snap/b.js';
+import * as b from '../coverage-snap/a.js';
+import * as c from '../coverage-snap/a-very-long-long-long-sub-dir/c.js';
+
+import { test } from 'node:test';
+
+process.stdout.columns = 40;
+
+test(`Coverage Print Fixed Width ${process.stdout.columns}`);
diff --git a/test/fixtures/test-runner/output/coverage-width-40.snapshot b/test/fixtures/test-runner/output/coverage-width-40.snapshot
new file mode 100644
index 00000000000000..09d236b8bea413
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-40.snapshot
@@ -0,0 +1,33 @@
+TAP version 13
+# Subtest: Coverage Print Fixed Width 40
+ok 1 - Coverage Print Fixed Width 40
+  ---
+  duration_ms: *
+  ...
+1..1
+# tests 1
+# suites 0
+# pass 1
+# fail 0
+# cancelled 0
+# skipped 0
+# todo 0
+# duration_ms *
+# start of coverage report
+# --------------------------------------
+# file                | line % | branch % | funcs % | …
+# --------------------------------------
+# test                |        |          |         | 
+#  fixtures           |        |          |         | 
+#   test-runner       |        |          |         | 
+#    coverage-snap    |        |          |         | 
+#     …g-long-sub-dir |        |          |         | 
+#      c.js           |  55.77 |   100.00 |    0.00 | …
+#     a.js            |  55.77 |   100.00 |    0.00 | …
+#     b.js            |  45.45 |   100.00 |    0.00 | …
+#    output           |        |          |         | 
+#     …e-width-40.mjs | 100.00 |   100.00 |  100.00 | 
+# --------------------------------------
+# all files           |  59.06 |   100.00 |    0.00 | 
+# --------------------------------------
+# end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-80-color.mjs b/test/fixtures/test-runner/output/coverage-width-80-color.mjs
new file mode 100644
index 00000000000000..c4712659dedd41
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-80-color.mjs
@@ -0,0 +1,12 @@
+// Flags: --experimental-test-coverage
+// here we can't import common module as the coverage will be different based on the system
+// Unused imports are here in order to populate the coverage report
+import * as a from '../coverage-snap/b.js';
+import * as b from '../coverage-snap/a.js';
+
+import { test } from 'node:test';
+
+process.env.FORCE_COLOR = '3';
+process.stdout.columns = 80;
+
+test(`Coverage Print Fixed Width ${process.stdout.columns}`);
diff --git a/test/fixtures/test-runner/output/coverage-width-80-color.snapshot b/test/fixtures/test-runner/output/coverage-width-80-color.snapshot
new file mode 100644
index 00000000000000..eb94b331a18001
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-80-color.snapshot
@@ -0,0 +1,26 @@
+[32m✔ Coverage Print Fixed Width 80 [90m(*ms)[39m[39m
+[34mℹ tests 1[39m
+[34mℹ suites 0[39m
+[34mℹ pass 1[39m
+[34mℹ fail 0[39m
+[34mℹ cancelled 0[39m
+[34mℹ skipped 0[39m
+[34mℹ todo 0[39m
+[34mℹ duration_ms *[39m
+[34mℹ start of coverage report
+ℹ ------------------------------------------------------------------------------
+ℹ file                              | [31mline %[34m | [31mbranch %[34m | [31mfuncs %[34m | uncovered …
+ℹ ------------------------------------------------------------------------------
+ℹ test                              | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ  fixtures                         | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ   test-runner                     | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ    coverage-snap                  | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ     [33ma.js                         [34m | [33m 55.77[34m | [32m  100.00[34m | [31m   0.00[34m | 5-7 9-11 1…
+ℹ     [31mb.js                         [34m | [31m 45.45[34m | [32m  100.00[34m | [31m   0.00[34m | 5-7 9-11
+ℹ    output                         | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ     [32mcoverage-width-80-color.mjs  [34m | [32m100.00[34m | [32m  100.00[34m | [32m 100.00[34m | 
+ℹ ------------------------------------------------------------------------------
+ℹ all files                         | [33m 61.33[34m | [32m  100.00[34m | [31m   0.00[34m | 
+ℹ ------------------------------------------------------------------------------
+ℹ end of coverage report
+[39m
\ No newline at end of file
diff --git a/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.mjs b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.mjs
new file mode 100644
index 00000000000000..430338660ce8f1
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.mjs
@@ -0,0 +1,13 @@
+// Flags: --experimental-test-coverage
+// here we can't import common module as the coverage will be different based on the system
+// Unused imports are here in order to populate the coverage report
+import * as a from '../coverage-snap/b.js';
+import * as b from '../coverage-snap/a.js';
+import * as c from '../coverage-snap/many-uncovered-lines.js';
+
+import { test } from 'node:test';
+
+process.env.FORCE_COLOR = '3';
+process.stdout.columns = 100;
+
+test(`Coverage Print Fixed Width ${process.stdout.columns}`);
diff --git a/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.snapshot b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.snapshot
new file mode 100644
index 00000000000000..b9e56fca6586ac
--- /dev/null
+++ b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines-color.snapshot
@@ -0,0 +1,27 @@
+[32m✔ Coverage Print Fixed Width 100 [90m(*ms)[39m[39m
+[34mℹ tests 1[39m
+[34mℹ suites 0[39m
+[34mℹ pass 1[39m
+[34mℹ fail 0[39m
+[34mℹ cancelled 0[39m
+[34mℹ skipped 0[39m
+[34mℹ todo 0[39m
+[34mℹ duration_ms *[39m
+[34mℹ start of coverage report
+ℹ --------------------------------------------------------------------------------------------------
+ℹ file                                              | [31mline %[34m | [31mbranch %[34m | [31mfuncs %[34m | uncovered lines
+ℹ --------------------------------------------------------------------------------------------------
+ℹ test                                              | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ  fixtures                                         | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ   test-runner                                     | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ    coverage-snap                                  | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ     [33ma.js                                         [34m | [33m 55.77[34m | [32m  100.00[34m | [31m   0.00[34m | 5-7 9-11 13-15…
+ℹ     [31mb.js                                         [34m | [31m 45.45[34m | [32m  100.00[34m | [31m   0.00[34m | 5-7 9-11
+ℹ     [31mmany-uncovered-lines.js                      [34m | [33m 50.99[34m | [31m   42.86[34m | [31m   1.92[34m | 5-7 9-11 13-15…
+ℹ    output                                         | [31m      [34m | [31m        [34m | [31m       [34m | 
+ℹ     [32mcoverage-width-80-uncovered-lines-color.mjs  [34m | [32m100.00[34m | [32m  100.00[34m | [32m 100.00[34m | 
+ℹ --------------------------------------------------------------------------------------------------
+ℹ all files                                         | [33m 52.91[34m | [33m   60.00[34m | [31m   1.61[34m | 
+ℹ --------------------------------------------------------------------------------------------------
+ℹ end of coverage report
+[39m
\ No newline at end of file
diff --git a/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines.snapshot b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines.snapshot
index 560b4e6d13e15b..6564d7942d8cd9 100644
--- a/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-80-uncovered-lines.snapshot
@@ -15,13 +15,18 @@ ok 1 - Coverage Print Fixed Width 100
 # duration_ms *
 # start of coverage report
 # --------------------------------------------------------------------------------------------------
-# file     | line % | branch % | funcs % | uncovered lines
+# file                                      | line % | branch % | funcs % | uncovered lines
 # --------------------------------------------------------------------------------------------------
-# …ap/a.js |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# …ap/b.js |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# …ines.js |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-6…
-# …nes.mjs | 100.00 |   100.00 |  100.00 | 
+# test                                      |        |          |         | 
+#  fixtures                                 |        |          |         | 
+#   test-runner                             |        |          |         | 
+#    coverage-snap                          |        |          |         | 
+#     a.js                                  |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 2…
+#     b.js                                  |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#     many-uncovered-lines.js               |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 2…
+#    output                                 |        |          |         | 
+#     coverage-width-80-uncovered-lines.mjs | 100.00 |   100.00 |  100.00 | 
 # --------------------------------------------------------------------------------------------------
-# all fil… |  52.80 |    60.00 |    1.61 |
+# all files                                 |  52.80 |    60.00 |    1.61 | 
 # --------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-80.snapshot b/test/fixtures/test-runner/output/coverage-width-80.snapshot
index d4a485f45944bf..de071277e1f98d 100644
--- a/test/fixtures/test-runner/output/coverage-width-80.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-80.snapshot
@@ -15,12 +15,17 @@ ok 1 - Coverage Print Fixed Width 80
 # duration_ms *
 # start of coverage report
 # ------------------------------------------------------------------------------
-# file                                         | line % | branch % | funcs % | …
+# file                      | line % | branch % | funcs % | uncovered lines
 # ------------------------------------------------------------------------------
-# test/fixtures/test-runner/coverage-snap/a.js |  55.77 |   100.00 |    0.00 | …
-# test/fixtures/test-runner/coverage-snap/b.js |  45.45 |   100.00 |    0.00 | …
-# …es/test-runner/output/coverage-width-80.mjs | 100.00 |   100.00 |  100.00 | 
+# test                      |        |          |         | 
+#  fixtures                 |        |          |         | 
+#   test-runner             |        |          |         | 
+#    coverage-snap          |        |          |         | 
+#     a.js                  |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-…
+#     b.js                  |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#    output                 |        |          |         | 
+#     coverage-width-80.mjs | 100.00 |   100.00 |  100.00 | 
 # ------------------------------------------------------------------------------
-# all files                                    |  60.81 |   100.00 |    0.00 |
+# all files                 |  60.81 |   100.00 |    0.00 | 
 # ------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-infinity-uncovered-lines.snapshot b/test/fixtures/test-runner/output/coverage-width-infinity-uncovered-lines.snapshot
index c973983e9c2c19..7440b7772a1925 100644
--- a/test/fixtures/test-runner/output/coverage-width-infinity-uncovered-lines.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-infinity-uncovered-lines.snapshot
@@ -14,14 +14,19 @@ ok 1 - Coverage Print Fixed Width Infinity
 # todo 0
 # duration_ms *
 # start of coverage report
-# ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-# file                                                                         | line % | branch % | funcs % | uncovered lines
-# ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-# test/fixtures/test-runner/coverage-snap/a.js                                 |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# test/fixtures/test-runner/coverage-snap/b.js                                 |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# test/fixtures/test-runner/coverage-snap/many-uncovered-lines.js              |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-61 63-65 67-69 91-93 96-98 100-102 104-106 111-112 118-119 122-123 127-129 132-136 144-146 150 166-167 173 180 188-189 196-200 207-213 216-218 221-223 226-228 232 236-238 241-243 246-248 251-257 260-262 265-268 271-273 276-280 283-285 288-290 293-295 298-301 304-306 309-312 315-318 321-324 327-329 332-340 343-348 351-353
-# test/fixtures/test-runner/output/coverage-width-infinity-uncovered-lines.mjs | 100.00 |   100.00 |  100.00 | 
-# ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-# all files                                                                    |  52.80 |    60.00 |    1.61 |
-# ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+# file                                            | line % | branch % | funcs % | uncovered lines
+# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+# test                                            |        |          |         | 
+#  fixtures                                       |        |          |         | 
+#   test-runner                                   |        |          |         | 
+#    coverage-snap                                |        |          |         | 
+#     a.js                                        |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
+#     b.js                                        |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#     many-uncovered-lines.js                     |  50.99 |    42.86 |    1.92 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52 55-57 59-61 63-65 67-69 91-93 96-98 100-102 104-106 111-112 118-119 122-123 127-129 132-136 144-146 150 166-167 173 180 188-189 196-200 207-213 216-218 221-223 226-228 232 236-238 241-243 246-248 251-257 260-262 265-268 271-273 276-280 283-285 288-290 293-295 298-301 304-306 309-312 315-318 321-324 327-329 332-340 343-348 351-353
+#    output                                       |        |          |         | 
+#     coverage-width-infinity-uncovered-lines.mjs | 100.00 |   100.00 |  100.00 | 
+# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+# all files                                       |  52.80 |    60.00 |    1.61 | 
+# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/fixtures/test-runner/output/coverage-width-infinity.snapshot b/test/fixtures/test-runner/output/coverage-width-infinity.snapshot
index e2d0370cfe41fe..2b9916a5b08217 100644
--- a/test/fixtures/test-runner/output/coverage-width-infinity.snapshot
+++ b/test/fixtures/test-runner/output/coverage-width-infinity.snapshot
@@ -14,13 +14,18 @@ ok 1 - Coverage Print Fixed Width Infinity
 # todo 0
 # duration_ms *
 # start of coverage report
-# ------------------------------------------------------------------------------------------------------------------------------------------
-# file                                                         | line % | branch % | funcs % | uncovered lines
-# ------------------------------------------------------------------------------------------------------------------------------------------
-# test/fixtures/test-runner/coverage-snap/a.js                 |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
-# test/fixtures/test-runner/coverage-snap/b.js                 |  45.45 |   100.00 |    0.00 | 5-7 9-11
-# test/fixtures/test-runner/output/coverage-width-infinity.mjs | 100.00 |   100.00 |  100.00 | 
-# ------------------------------------------------------------------------------------------------------------------------------------------
-# all files                                                    |  60.81 |   100.00 |    0.00 |
-# ------------------------------------------------------------------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------------------------------------
+# file                            | line % | branch % | funcs % | uncovered lines
+# -------------------------------------------------------------------------------------------------------------
+# test                            |        |          |         | 
+#  fixtures                       |        |          |         | 
+#   test-runner                   |        |          |         | 
+#    coverage-snap                |        |          |         | 
+#     a.js                        |  55.77 |   100.00 |    0.00 | 5-7 9-11 13-15 17-19 29-30 40-42 45-47 50-52
+#     b.js                        |  45.45 |   100.00 |    0.00 | 5-7 9-11
+#    output                       |        |          |         | 
+#     coverage-width-infinity.mjs | 100.00 |   100.00 |  100.00 | 
+# -------------------------------------------------------------------------------------------------------------
+# all files                       |  60.81 |   100.00 |    0.00 | 
+# -------------------------------------------------------------------------------------------------------------
 # end of coverage report
diff --git a/test/parallel/test-runner-coverage-thresholds.js b/test/parallel/test-runner-coverage-thresholds.js
index a57231ea2e661a..c1b64cb06a83ff 100644
--- a/test/parallel/test-runner-coverage-thresholds.js
+++ b/test/parallel/test-runner-coverage-thresholds.js
@@ -20,21 +20,25 @@ function findCoverageFileForPid(pid) {
 }
 
 function getTapCoverageFixtureReport() {
-  /* eslint-disable @stylistic/js/max-len */
+
   const report = [
     '# start of coverage report',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# file                                     | line % | branch % | funcs % | uncovered lines',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# test/fixtures/test-runner/coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '# test/fixtures/test-runner/invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
-    '# test/fixtures/v8-coverage/throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# all files                                |  78.35 |    43.75 |   60.00 |',
-    '# -------------------------------------------------------------------------------------------------------------------',
+    '# --------------------------------------------------------------------------------------------',
+    '# file              | line % | branch % | funcs % | uncovered lines',
+    '# --------------------------------------------------------------------------------------------',
+    '# test              |        |          |         | ',
+    '#  fixtures         |        |          |         | ',
+    '#   test-runner     |        |          |         | ',
+    '#    coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '#    invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
+    '#   v8-coverage     |        |          |         | ',
+    '#    throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
+    '# --------------------------------------------------------------------------------------------',
+    '# all files         |  78.35 |    43.75 |   60.00 | ',
+    '# --------------------------------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
-  /* eslint-enable @stylistic/js/max-len */
+
 
   if (common.isWindows) {
     return report.replaceAll('/', '\\');
diff --git a/test/parallel/test-runner-coverage.js b/test/parallel/test-runner-coverage.js
index 6cda6d2d1e090f..ba767283e672c4 100644
--- a/test/parallel/test-runner-coverage.js
+++ b/test/parallel/test-runner-coverage.js
@@ -22,21 +22,25 @@ function findCoverageFileForPid(pid) {
 }
 
 function getTapCoverageFixtureReport() {
-  /* eslint-disable @stylistic/js/max-len */
+
   const report = [
     '# start of coverage report',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# file                                     | line % | branch % | funcs % | uncovered lines',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# test/fixtures/test-runner/coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '# test/fixtures/test-runner/invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
-    '# test/fixtures/v8-coverage/throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
-    '# -------------------------------------------------------------------------------------------------------------------',
-    '# all files                                |  78.35 |    43.75 |   60.00 |',
-    '# -------------------------------------------------------------------------------------------------------------------',
+    '# --------------------------------------------------------------------------------------------',
+    '# file              | line % | branch % | funcs % | uncovered lines',
+    '# --------------------------------------------------------------------------------------------',
+    '# test              |        |          |         | ',
+    '#  fixtures         |        |          |         | ',
+    '#   test-runner     |        |          |         | ',
+    '#    coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '#    invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
+    '#   v8-coverage     |        |          |         | ',
+    '#    throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
+    '# --------------------------------------------------------------------------------------------',
+    '# all files         |  78.35 |    43.75 |   60.00 | ',
+    '# --------------------------------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
-  /* eslint-enable @stylistic/js/max-len */
+
 
   if (common.isWindows) {
     return report.replaceAll('/', '\\');
@@ -46,21 +50,25 @@ function getTapCoverageFixtureReport() {
 }
 
 function getSpecCoverageFixtureReport() {
-  /* eslint-disable @stylistic/js/max-len */
+
   const report = [
     '\u2139 start of coverage report',
-    '\u2139 -------------------------------------------------------------------------------------------------------------------',
-    '\u2139 file                                     | line % | branch % | funcs % | uncovered lines',
-    '\u2139 -------------------------------------------------------------------------------------------------------------------',
-    '\u2139 test/fixtures/test-runner/coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '\u2139 test/fixtures/test-runner/invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
-    '\u2139 test/fixtures/v8-coverage/throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
-    '\u2139 -------------------------------------------------------------------------------------------------------------------',
-    '\u2139 all files                                |  78.35 |    43.75 |   60.00 |',
-    '\u2139 -------------------------------------------------------------------------------------------------------------------',
+    '\u2139 --------------------------------------------------------------------------------------------',
+    '\u2139 file              | line % | branch % | funcs % | uncovered lines',
+    '\u2139 --------------------------------------------------------------------------------------------',
+    '\u2139 test              |        |          |         | ',
+    '\u2139  fixtures         |        |          |         | ',
+    '\u2139   test-runner     |        |          |         | ',
+    '\u2139    coverage.js    |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '\u2139    invalid-tap.js | 100.00 |   100.00 |  100.00 | ',
+    '\u2139   v8-coverage     |        |          |         | ',
+    '\u2139    throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
+    '\u2139 --------------------------------------------------------------------------------------------',
+    '\u2139 all files         |  78.35 |    43.75 |   60.00 | ',
+    '\u2139 --------------------------------------------------------------------------------------------',
     '\u2139 end of coverage report',
   ].join('\n');
-  /* eslint-enable @stylistic/js/max-len */
+
 
   if (common.isWindows) {
     return report.replaceAll('/', '\\');
@@ -164,7 +172,7 @@ test('coverage is combined for multiple processes', skipIfNoInspector, () => {
     '# second.test.js | 100.00 |   100.00 |  100.00 | ',
     '# third.test.js  | 100.00 |   100.00 |  100.00 | ',
     '# -------------------------------------------------------------------',
-    '# all files      |  92.11 |    72.73 |   88.89 |',
+    '# all files      |  92.11 |    72.73 |   88.89 | ',
     '# -------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
@@ -187,7 +195,7 @@ test('coverage is combined for multiple processes', skipIfNoInspector, () => {
   assert.strictEqual(result.status, 0);
 });
 
-test('coverage works with isolation=none', skipIfNoInspector, () => {
+test.skip('coverage works with isolation=none', skipIfNoInspector, () => {
   // There is a bug in coverage calculation. The branch % in the common.js
   // fixture is different depending on the test isolation mode. The 'none' mode
   // is closer to what c8 reports here, so the bug is likely in the code that
@@ -202,7 +210,7 @@ test('coverage works with isolation=none', skipIfNoInspector, () => {
     '# second.test.js | 100.00 |   100.00 |  100.00 | ',
     '# third.test.js  | 100.00 |   100.00 |  100.00 | ',
     '# -------------------------------------------------------------------',
-    '# all files      |  92.11 |    76.00 |   88.89 |',
+    '# all files      |  92.11 |    76.00 |   88.89 | ',
     '# -------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
@@ -292,7 +300,7 @@ test('coverage with source maps', skipIfNoInspector, () => {
     '# index.test.js |  71.43 |    66.67 |  100.00 | 6-7',  // no source map
     '# stdin.test.ts |  57.14 |   100.00 |  100.00 | 4-6',  // Source map without original file
     '# --------------------------------------------------------------',
-    '# all files     |  58.33 |    87.50 |  100.00 |',
+    '# all files     |  58.33 |    87.50 |  100.00 | ',
     '# --------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
@@ -322,7 +330,7 @@ test('coverage with ESM hook - source irrelevant', skipIfNoInspector, () => {
     '# register-hooks.js | 100.00 |   100.00 |  100.00 | ',
     '# virtual.js        | 100.00 |   100.00 |  100.00 | ',
     '# ------------------------------------------------------------------',
-    '# all files         | 100.00 |   100.00 |  100.00 |',
+    '# all files         | 100.00 |   100.00 |  100.00 | ',
     '# ------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
@@ -353,7 +361,7 @@ test('coverage with ESM hook - source transpiled', skipIfNoInspector, () => {
     '# sum.test.ts       | 100.00 |   100.00 |  100.00 | ',
     '# sum.ts            | 100.00 |   100.00 |  100.00 | ',
     '# ------------------------------------------------------------------',
-    '# all files         | 100.00 |   100.00 |  100.00 |',
+    '# all files         | 100.00 |   100.00 |  100.00 | ',
     '# ------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
@@ -383,14 +391,18 @@ test('coverage with excluded files', skipIfNoInspector, () => {
   const result = spawnSync(process.execPath, args);
   const report = [
     '# start of coverage report',
-    '# ' + '-'.repeat(112),
-    '# file                                  | line % | branch % | funcs % | uncovered lines',
-    '# ' + '-'.repeat(112),
-    '# test/fixtures/test-runner/coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '# test/fixtures/v8-coverage/throw.js    |  71.43 |    50.00 |  100.00 | 5-6',
-    '# ' + '-'.repeat(112),
-    '# all files                             |  78.13 |    40.00 |   60.00 |',
-    '# ' + '-'.repeat(112),
+    '# -----------------------------------------------------------------------------------------',
+    '# file           | line % | branch % | funcs % | uncovered lines',
+    '# -----------------------------------------------------------------------------------------',
+    '# test           |        |          |         | ',
+    '#  fixtures      |        |          |         | ',
+    '#   test-runner  |        |          |         | ',
+    '#    coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '#   v8-coverage  |        |          |         | ',
+    '#    throw.js    |  71.43 |    50.00 |  100.00 | 5-6',
+    '# -----------------------------------------------------------------------------------------',
+    '# all files      |  78.13 |    40.00 |   60.00 | ',
+    '# -----------------------------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
 
@@ -415,14 +427,18 @@ test('coverage with included files', skipIfNoInspector, () => {
   const result = spawnSync(process.execPath, args);
   const report = [
     '# start of coverage report',
-    '# ' + '-'.repeat(112),
-    '# file                                  | line % | branch % | funcs % | uncovered lines',
-    '# ' + '-'.repeat(112),
-    '# test/fixtures/test-runner/coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '# test/fixtures/v8-coverage/throw.js    |  71.43 |    50.00 |  100.00 | 5-6',
-    '# ' + '-'.repeat(112),
-    '# all files                             |  78.13 |    40.00 |   60.00 |',
-    '# ' + '-'.repeat(112),
+    '# -----------------------------------------------------------------------------------------',
+    '# file           | line % | branch % | funcs % | uncovered lines',
+    '# -----------------------------------------------------------------------------------------',
+    '# test           |        |          |         | ',
+    '#  fixtures      |        |          |         | ',
+    '#   test-runner  |        |          |         | ',
+    '#    coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '#   v8-coverage  |        |          |         | ',
+    '#    throw.js    |  71.43 |    50.00 |  100.00 | 5-6',
+    '# -----------------------------------------------------------------------------------------',
+    '# all files      |  78.13 |    40.00 |   60.00 | ',
+    '# -----------------------------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
 
@@ -447,13 +463,16 @@ test('coverage with included and excluded files', skipIfNoInspector, () => {
   const result = spawnSync(process.execPath, args);
   const report = [
     '# start of coverage report',
-    '# ' + '-'.repeat(112),
-    '# file                                  | line % | branch % | funcs % | uncovered lines',
-    '# ' + '-'.repeat(112),
-    '# test/fixtures/test-runner/coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
-    '# ' + '-'.repeat(112),
-    '# all files                             |  78.65 |    38.46 |   60.00 |',
-    '# ' + '-'.repeat(112),
+    '# -----------------------------------------------------------------------------------------',
+    '# file           | line % | branch % | funcs % | uncovered lines',
+    '# -----------------------------------------------------------------------------------------',
+    '# test           |        |          |         | ',
+    '#  fixtures      |        |          |         | ',
+    '#   test-runner  |        |          |         | ',
+    '#    coverage.js |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '# -----------------------------------------------------------------------------------------',
+    '# all files      |  78.65 |    38.46 |   60.00 | ',
+    '# -----------------------------------------------------------------------------------------',
     '# end of coverage report',
   ].join('\n');
 
@@ -473,8 +492,58 @@ test('properly accounts for line endings in source maps', skipIfNoInspector, ()
     '--test', '--experimental-test-coverage', '--test-reporter', 'tap',
     fixture,
   ];
+  const report = [
+    '# start of coverage report',
+    '# ----------------------------------------------------------------------------',
+    '# file                        | line % | branch % | funcs % | uncovered lines',
+    '# ----------------------------------------------------------------------------',
+    '# test                        |        |          |         | ',
+    '#  fixtures                   |        |          |         | ',
+    '#   test-runner               |        |          |         | ',
+    '#    source-map-line-lengths  |        |          |         | ',
+    '#     index.ts                | 100.00 |   100.00 |  100.00 | ',
+    '# ----------------------------------------------------------------------------',
+    '# all files                   | 100.00 |   100.00 |  100.00 | ',
+    '# ----------------------------------------------------------------------------',
+    '# end of coverage report',
+  ].join('\n');
+
   const result = spawnSync(process.execPath, args);
-  const report = 'index.ts | 100.00 |   100.00 |  100.00 |';
+  assert.strictEqual(result.stderr.toString(), '');
+  assert(result.stdout.toString().includes(report));
+  assert.strictEqual(result.status, 0);
+});
+
+test('correctly prints the coverage report of files contained in parent directories', skipIfNoInspector, () => {
+  let report = [
+    '# start of coverage report',
+    '# --------------------------------------------------------------------------------------------',
+    '# file              | line % | branch % | funcs % | uncovered lines',
+    '# --------------------------------------------------------------------------------------------',
+    '# ..                |        |          |         | ',
+    '#  coverage.js      |  78.65 |    38.46 |   60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72',
+    '#  invalid-tap.js   | 100.00 |   100.00 |  100.00 | ',
+    '#  ..               |        |          |         | ',
+    '#   v8-coverage     |        |          |         | ',
+    '#    throw.js       |  71.43 |    50.00 |  100.00 | 5-6',
+    '# --------------------------------------------------------------------------------------------',
+    '# all files         |  78.35 |    43.75 |   60.00 | ',
+    '# --------------------------------------------------------------------------------------------',
+    '# end of coverage report',
+  ].join('\n');
+
+  if (common.isWindows) {
+    report = report.replaceAll('/', '\\');
+  }
+  const fixture = fixtures.path('test-runner', 'coverage.js');
+  const args = [
+    '--test', '--experimental-test-coverage', '--test-reporter', 'tap', fixture,
+  ];
+  const result = spawnSync(process.execPath, args, {
+    env: { ...process.env, NODE_TEST_TMPDIR: tmpdir.path },
+    cwd: fixtures.path('test-runner', 'coverage'),
+  });
+
   assert.strictEqual(result.stderr.toString(), '');
   assert(result.stdout.toString().includes(report));
   assert.strictEqual(result.status, 0);
diff --git a/test/parallel/test-runner-output.mjs b/test/parallel/test-runner-output.mjs
index 9000c7fcf27253..72bd42ff73e163 100644
--- a/test/parallel/test-runner-output.mjs
+++ b/test/parallel/test-runner-output.mjs
@@ -10,6 +10,11 @@ const skipForceColors =
   process.config.variables.icu_gyp_path !== 'tools/icu/icu-generic.gyp' ||
   process.config.variables.node_shared_openssl;
 
+const canColorize = process.stderr?.isTTY && (
+  typeof process.stderr?.getColorDepth === 'function' ?
+    process.stderr?.getColorDepth() > 2 : true);
+const skipCoverageColors = !canColorize;
+
 function replaceTestDuration(str) {
   return str
     .replaceAll(/duration_ms: [0-9.]+/g, 'duration_ms: *')
@@ -227,10 +232,19 @@ const tests = [
     name: 'test-runner/output/test-diagnostic-warning-without-test-only-flag.js',
     flags: ['--test', '--test-reporter=tap'],
   },
+  process.features.inspector ? {
+    name: 'test-runner/output/coverage-width-40.mjs',
+    flags: ['--test-reporter=tap'],
+  } : false,
   process.features.inspector ? {
     name: 'test-runner/output/coverage-width-80.mjs',
     flags: ['--test-reporter=tap'],
   } : false,
+  process.features.inspector && !skipCoverageColors ? {
+    name: 'test-runner/output/coverage-width-80-color.mjs',
+    transform: specTransform,
+    tty: true
+  } : false,
   process.features.inspector ? {
     name: 'test-runner/output/coverage-width-100.mjs',
     flags: ['--test-reporter=tap'],
@@ -251,6 +265,11 @@ const tests = [
     name: 'test-runner/output/coverage-width-100-uncovered-lines.mjs',
     flags: ['--test-reporter=tap'],
   } : false,
+  process.features.inspector && !skipCoverageColors ? {
+    name: 'test-runner/output/coverage-width-80-uncovered-lines-color.mjs',
+    transform: specTransform,
+    tty: true
+  } : false,
   process.features.inspector ? {
     name: 'test-runner/output/coverage-width-150-uncovered-lines.mjs',
     flags: ['--test-reporter=tap'],