supercov 4.20.3 → 4.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/cli.md CHANGED
@@ -926,6 +926,7 @@ terminal or offline environment after the package has been downloaded.
926
926
  | `SUPERCOV_RUN_ID` | Set by Supercov, not by you: in every process a measured command starts, the run's id, so a test or harness can tell it is measured |
927
927
  | `SUPERCOV_RUN_ID_FILE` | A file to write the recorded run's id to, for a script to query that run rather than `latest` |
928
928
  | `SUPERCOV_KEEP_WORKSPACE` | Set to `1` to leave the instrumented copy of the project in `.supercov/workspaces/` after the run, to inspect what the command ran |
929
+ | `SUPERCOV_COMMAND_TIMEOUT_MS` | Stop the test command after this many milliseconds: what is still running is asked to stop, then made to five seconds later, what ran is recorded, and Supercov exits `124`. No deadline by default |
929
930
 
930
931
  Examples:
931
932
 
@@ -941,6 +942,7 @@ SUPERCOV_TEST_KIND=e2e npx supercov -- npx playwright test
941
942
  | `0` | The command or query succeeded |
942
943
  | Wrapped command's code | The test command failed and Supercov preserved its status |
943
944
  | `127`, `126` | The test command could not start: no such program, or one that may not be run, as a shell reports it |
945
+ | `124` | The test command ran past `SUPERCOV_COMMAND_TIMEOUT_MS` and was stopped |
944
946
  | `1` | A valid measurement failed a policy you set, such as a coverage floor |
945
947
  | `2` | Supercov could not complete the request, or the evidence cannot answer it |
946
948
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "4.20.3",
3
+ "version": "4.21.0",
4
4
  "description": "Coverage, security and code quality for coding agents",
5
5
  "keywords": [
6
6
  "coverage",
@@ -122,14 +122,14 @@
122
122
  "test:windows-tls": "node scripts/windows-tls-test.mjs"
123
123
  },
124
124
  "optionalDependencies": {
125
- "@supercov/cli-darwin-arm64": "4.20.3",
126
- "@supercov/cli-darwin-x64": "4.20.3",
127
- "@supercov/cli-linux-arm64-gnu": "4.20.3",
128
- "@supercov/cli-linux-arm64-musl": "4.20.3",
129
- "@supercov/cli-linux-x64-gnu": "4.20.3",
130
- "@supercov/cli-linux-x64-musl": "4.20.3",
131
- "@supercov/cli-win32-arm64": "4.20.3",
132
- "@supercov/cli-win32-x64": "4.20.3"
125
+ "@supercov/cli-darwin-arm64": "4.21.0",
126
+ "@supercov/cli-darwin-x64": "4.21.0",
127
+ "@supercov/cli-linux-arm64-gnu": "4.21.0",
128
+ "@supercov/cli-linux-arm64-musl": "4.21.0",
129
+ "@supercov/cli-linux-x64-gnu": "4.21.0",
130
+ "@supercov/cli-linux-x64-musl": "4.21.0",
131
+ "@supercov/cli-win32-arm64": "4.21.0",
132
+ "@supercov/cli-win32-x64": "4.21.0"
133
133
  },
134
134
  "peerDependencies": {
135
135
  "@playwright/test": ">=1.55.0",
@@ -944,10 +944,40 @@ if (supportDirectory) {
944
944
  };
945
945
  syncBuiltinESMExports();
946
946
  }
947
+ // A file a test asked for by its path that Node did not find in the copy:
948
+ // the copy leaves out build output, and a test that loads `../dist/x.js` an
949
+ // earlier build made fails as a missing module. Noted where
950
+ // SUPERCOV_MISSING_LOADS names, here for `require` and in the loader for
951
+ // `import`, so the run can say which file the copy lacks and why.
952
+ const missingFile = process.env.SUPERCOV_MISSING_LOADS;
953
+ if (missingFile) {
954
+ const copyRoot = process.env.SUPERCOV_PROJECT_ROOT;
955
+ const resolveFilename = Module._resolveFilename;
956
+ Module._resolveFilename = function supercovNotedResolve(request, parent, ...rest) {
957
+ try {
958
+ return resolveFilename.call(this, request, parent, ...rest);
959
+ }
960
+ catch (error) {
961
+ if (error?.code === "MODULE_NOT_FOUND" && copyRoot && /^(?:\.{1,2}[\\/]|[\\/])/.test(request)) {
962
+ try {
963
+ const file = resolve(parent?.filename ? dirname(parent.filename) : process.cwd(), request);
964
+ const inside = file.startsWith(copyRoot + sep) ? file.slice(copyRoot.length + 1) : undefined;
965
+ if (inside && !inside.startsWith(`.supercov${sep}`) && !inside.split(sep).includes("node_modules"))
966
+ fs.appendFileSync(missingFile, `${JSON.stringify({ missing: file })}\n`);
967
+ }
968
+ catch {
969
+ // Not noted: the run says nothing of it, as before.
970
+ }
971
+ }
972
+ throw error;
973
+ }
974
+ };
975
+ }
947
976
  register(new URL("./resolve-loader.mjs", import.meta.url), {
948
977
  data: {
949
978
  typescriptRequireHook: typeof typescriptHandler === "function" && typescriptHandler.name !== "loadTS",
950
979
  supportFile,
980
+ missingFile,
951
981
  },
952
982
  });
953
983
  if (process.env.SUPERCOV_DEBUG === "1") {
@@ -58,9 +58,27 @@ function noteLoaded(url) {
58
58
  // Not recorded: the file counts for every test, as before.
59
59
  }
60
60
  }
61
+ // Where this process notes a file a test asked for by its path and Node did
62
+ // not find, in the copy: a file the copy left out, build output above all,
63
+ // fails a test as a missing module, and Supercov can say why (`register.mjs`
64
+ // names it, and does the same for `require`).
65
+ let missingFile;
66
+ function noteMissing(specifier, parentURL) {
67
+ if (!missingFile || !/^(?:\.{1,2}\/|\/|file:)/.test(specifier))
68
+ return;
69
+ try {
70
+ const file = fileURLToPath(new URL(specifier, parentURL ?? pathToFileURL(`${process.cwd()}/`)));
71
+ if (projectFile(file))
72
+ appendFileSync(missingFile, `${JSON.stringify({ missing: file })}\n`);
73
+ }
74
+ catch {
75
+ // Not noted: the run says nothing of it, as before.
76
+ }
77
+ }
61
78
  export function initialize(data) {
62
79
  typescriptRequireHook = data?.typescriptRequireHook === true;
63
80
  supportFile = typeof data?.supportFile === "string" ? data.supportFile : undefined;
81
+ missingFile = typeof data?.missingFile === "string" ? data.missingFile : undefined;
64
82
  }
65
83
  const packageTypes = new Map();
66
84
  function packageType(directory) {
@@ -141,7 +159,14 @@ export async function resolve(specifier, context, nextResolve) {
141
159
  }
142
160
  return nextResolve(REPLACEMENT, context);
143
161
  }
144
- return throughRequireHook(await nextResolve(specifier, context));
162
+ try {
163
+ return throughRequireHook(await nextResolve(specifier, context));
164
+ }
165
+ catch (error) {
166
+ if (error?.code === "ERR_MODULE_NOT_FOUND")
167
+ noteMissing(specifier, context.parentURL);
168
+ throw error;
169
+ }
145
170
  }
146
171
 
147
172
  // Node's own test coverage filters files by `--test-coverage-include` and