@naturalcycles/dev-lib 20.59.0 → 20.61.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.
@@ -83,6 +83,7 @@ export function getSharedConfig(cwd) {
83
83
  testTimeout: 60_000,
84
84
  hookTimeout: 60_000,
85
85
  slowTestThreshold: isCI ? 500 : 300, // higher threshold in CI
86
+ injectCjsGlobals: false,
86
87
  sequence: {
87
88
  sequencer: VitestAlphabeticSequencer,
88
89
  // shuffle: {
@@ -1,3 +1,4 @@
1
+ import path from 'node:path';
1
2
  import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
2
3
  import { red } from '@naturalcycles/nodejs-lib/colors';
3
4
  import { createMitm } from '../vendor/mitm.js';
@@ -18,7 +19,8 @@ export function testOffline(opt) {
18
19
  mitm.on('connect', (socket, socketOptions) => {
19
20
  const { host } = socketOptions;
20
21
  if (!LOCAL_HOSTS.has(host)) {
21
- process.stderr.write(red(`Network request forbidden by testOffline: ${host}\n`));
22
+ const testInfo = getCurrentTestInfo(host);
23
+ process.stderr.write(red(`Network request forbidden by testOffline: ${testInfo}\n`));
22
24
  opt?.onForbiddenRequest?.(host);
23
25
  throw new AppError(`Network request forbidden by testOffline: ${host}`, {
24
26
  backendResponseStatusCode: 410,
@@ -34,3 +36,39 @@ export function testOnline() {
34
36
  mitm?.disable();
35
37
  mitm = undefined;
36
38
  }
39
+ /**
40
+ * Returns the test name and test file that triggered the request (as tracked by vitest),
41
+ * formatted as `test: <name>, file: <path>` to append to the alert, so the culprit is easy to find.
42
+ * Returns an empty string when nothing is known (e.g. vitest is not installed or not running,
43
+ * or the request was made outside of any test).
44
+ *
45
+ * Reads vitest's worker state from the global vitest stores it in (the same source that
46
+ * `expect.getState()` uses for `testPath` and `currentTestName`), instead of importing `vitest`:
47
+ * - it has to be synchronous (see the `connect` listener), and `vitest` can only be imported asynchronously
48
+ * - `vitest` may not be installed in the consuming project
49
+ */
50
+ function getCurrentTestInfo(host) {
51
+ const tokens = [host];
52
+ const state = globalThis['__vitest_worker__'];
53
+ if (state) {
54
+ if (state.filepath) {
55
+ tokens.push(`file: ${path.relative(process.cwd(), state.filepath)}`);
56
+ }
57
+ if (state.current?.type === 'test') {
58
+ tokens.push(`test: ${getFullTestName(state.current)}`);
59
+ }
60
+ }
61
+ return tokens.filter(Boolean).join('\n');
62
+ }
63
+ /**
64
+ * Test name prefixed with the names of its parent suites (same as `expect.getState().currentTestName`),
65
+ * e.g. `describe name > nested describe name > test name`.
66
+ */
67
+ function getFullTestName(test) {
68
+ const names = [];
69
+ // Walk up the chain of parent suites; it ends with `undefined` (or with the file itself, which is excluded)
70
+ for (let task = test; task && task !== test.file; task = task.suite) {
71
+ names.push(task.name);
72
+ }
73
+ return names.reverse().join(' > ');
74
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.59.0",
4
+ "version": "20.61.0",
5
5
  "dependencies": {
6
6
  "prompts": "^2",
7
7
  "@naturalcycles/js-lib": "^15",
8
8
  "@naturalcycles/nodejs-lib": "^15",
9
- "@vitest/coverage-v8": "^4",
9
+ "@vitest/coverage-v8": "^5",
10
10
  "eslint-plugin-oxlint": "^1",
11
11
  "globals": "^17",
12
12
  "lint-staged": "^17",