@naturalcycles/dev-lib 20.61.0 → 20.63.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.
File without changes
File without changes
@@ -467,6 +467,18 @@ export const sharedConfig = {
467
467
  ],
468
468
  'vitest/max-nested-describe': [0, { max: 4 }], // not good
469
469
  'vitest/no-alias-methods': 2,
470
+ 'vitest/no-restricted-vi-methods': [
471
+ 2,
472
+ {
473
+ mock: 'vi.mock() is never cleared (isolate: false) and leaks into other test files on the same worker. Spy on the module namespace instead: vi.spyOn(ns, "fn") or vi.spyOn(ns, "constName", "get").',
474
+ doMock:
475
+ 'vi.doMock() is never cleared (isolate: false) and leaks into other test files on the same worker. Use vi.spyOn() on the module namespace instead.',
476
+ hoisted:
477
+ 'vi.hoisted() only exists to feed vi.mock() factories, which are banned. Use vi.spyOn() instead.',
478
+ resetModules:
479
+ 'vi.resetModules() clears the shared module cache for every later test file on this worker (isolate: false).',
480
+ },
481
+ ],
470
482
  'vue/no-multiple-slot-args': 2,
471
483
  'vue/no-deprecated-destroyed-lifecycle': 2,
472
484
  'vue/define-emits-declaration': [2, 'type-based'],
@@ -77,6 +77,9 @@ export function getSharedConfig(cwd) {
77
77
  watch: false,
78
78
  // dir: 'src',
79
79
  restoreMocks: true,
80
+ // restoreMocks does not cover vi.stubEnv/vi.stubGlobal
81
+ unstubEnvs: true,
82
+ unstubGlobals: true,
80
83
  silent,
81
84
  setupFiles: getSetupFiles(testType, cwd),
82
85
  logHeapUsage: true,
@@ -1,4 +1,9 @@
1
1
  /**
2
+ * Forbids network requests to anything but local hosts for the rest of the test run.
3
+ *
4
+ * A forbidden request throws into the code under test and also fails the test that made it,
5
+ * so the failure survives the code under test catching the error.
6
+ *
2
7
  * Based on: https://github.com/palmerj3/jest-offline/blob/master/index.js
3
8
  */
4
9
  export declare function testOffline(opt?: TestOfflineOptions): void;
@@ -6,6 +6,11 @@ const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1']);
6
6
  const detectLeaks = process.argv.some(a => a.includes('detectLeaks'));
7
7
  let mitm;
8
8
  /**
9
+ * Forbids network requests to anything but local hosts for the rest of the test run.
10
+ *
11
+ * A forbidden request throws into the code under test and also fails the test that made it,
12
+ * so the failure survives the code under test catching the error.
13
+ *
9
14
  * Based on: https://github.com/palmerj3/jest-offline/blob/master/index.js
10
15
  */
11
16
  export function testOffline(opt) {
@@ -22,9 +27,11 @@ export function testOffline(opt) {
22
27
  const testInfo = getCurrentTestInfo(host);
23
28
  process.stderr.write(red(`Network request forbidden by testOffline: ${testInfo}\n`));
24
29
  opt?.onForbiddenRequest?.(host);
25
- throw new AppError(`Network request forbidden by testOffline: ${host}`, {
30
+ const error = new AppError(`Network request forbidden by testOffline: ${host}`, {
26
31
  backendResponseStatusCode: 410,
27
32
  });
33
+ failCurrentTest(error);
34
+ throw error;
28
35
  }
29
36
  socket.bypass();
30
37
  });
@@ -49,7 +56,7 @@ export function testOnline() {
49
56
  */
50
57
  function getCurrentTestInfo(host) {
51
58
  const tokens = [host];
52
- const state = globalThis['__vitest_worker__'];
59
+ const state = getWorkerState();
53
60
  if (state) {
54
61
  if (state.filepath) {
55
62
  tokens.push(`file: ${path.relative(process.cwd(), state.filepath)}`);
@@ -60,6 +67,27 @@ function getCurrentTestInfo(host) {
60
67
  }
61
68
  return tokens.filter(Boolean).join('\n');
62
69
  }
70
+ /**
71
+ * Records the error on the running test the way `expect.soft` does: vitest only marks a test
72
+ * passed if nothing set its state to `fail` first. This is what makes the test fail even when the
73
+ * code under test catches the error thrown from the `connect` listener (a `pTry`, a fetcher that
74
+ * swallows failures) — otherwise such a test passes with nothing but the alert on stderr.
75
+ */
76
+ function failCurrentTest(error) {
77
+ const result = getCurrentTest()?.result;
78
+ if (!result)
79
+ return;
80
+ result.state = 'fail';
81
+ result.errors ||= [];
82
+ result.errors.push({ name: error.name, message: error.message, stack: error.stack });
83
+ }
84
+ function getCurrentTest() {
85
+ const current = getWorkerState()?.current;
86
+ return current?.type === 'test' ? current : undefined;
87
+ }
88
+ function getWorkerState() {
89
+ return globalThis['__vitest_worker__'];
90
+ }
63
91
  /**
64
92
  * Test name prefixed with the names of its parent suites (same as `expect.getState().currentTestName`),
65
93
  * e.g. `describe name > nested describe name > test name`.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.61.0",
4
+ "version": "20.63.0",
5
5
  "dependencies": {
6
6
  "prompts": "^2",
7
7
  "@naturalcycles/js-lib": "^15",