@ultimat3/testing 22.3.5 → 22.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/testing",
3
- "version": "22.3.5",
3
+ "version": "22.4.0",
4
4
  "description": "Test harness: cloned template DBs per worker, frozen clock, sealed network, 6 test types",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,16 +35,16 @@
35
35
  "test": "bun test"
36
36
  },
37
37
  "dependencies": {
38
- "@ultimat3/cache": "22.3.5",
39
- "@ultimat3/core": "22.3.5",
40
- "@ultimat3/db": "22.3.5",
41
- "@ultimat3/entity": "22.3.5",
42
- "@ultimat3/i18n": "22.3.5",
43
- "@ultimat3/jobs": "22.3.5",
44
- "@ultimat3/mail": "22.3.5",
45
- "@ultimat3/policy": "22.3.5",
46
- "@ultimat3/query": "22.3.5",
47
- "@ultimat3/realtime": "22.3.5",
48
- "@ultimat3/time": "22.3.5"
38
+ "@ultimat3/cache": "22.4.0",
39
+ "@ultimat3/core": "22.4.0",
40
+ "@ultimat3/db": "22.4.0",
41
+ "@ultimat3/entity": "22.4.0",
42
+ "@ultimat3/i18n": "22.4.0",
43
+ "@ultimat3/jobs": "22.4.0",
44
+ "@ultimat3/mail": "22.4.0",
45
+ "@ultimat3/policy": "22.4.0",
46
+ "@ultimat3/query": "22.4.0",
47
+ "@ultimat3/realtime": "22.4.0",
48
+ "@ultimat3/time": "22.4.0"
49
49
  }
50
50
  }
package/src/index.ts CHANGED
@@ -250,6 +250,7 @@ export {
250
250
  missingIslandFiles,
251
251
  normalizeIslandName,
252
252
  } from './island-states-resolve';
253
+ export { ISOLATED_ENV, releasePluginsAfterIsolatedFile } from './isolated-plugins';
253
254
  export type { LiveConnection, LiveNodeHandle, LiveNodeOptions } from './live-node';
254
255
  export { createLiveNode } from './live-node';
255
256
  /**
@@ -0,0 +1,37 @@
1
+ // Frees each finished test file in an ISOLATED run. Bun 1.4.0 keeps every finished file's global
2
+ // object — its module graph, PGlite heap and fakes — alive under `--isolate` (implied by
3
+ // `--parallel`) once any `Bun.plugin` load/resolve handler is registered, and the framework
4
+ // registers two in every file. `isolated-plugins.test.ts` measures it with real `bun test` runs.
5
+
6
+ import { afterAll } from 'bun:test';
7
+
8
+ /**
9
+ * Set by `x test` (`@ultimat3/cli`'s `test-shards.ts`) on every `bun test` it spawns in isolated
10
+ * mode. A preload cannot tell for itself: an isolated file sees the same argv, and a fresh process
11
+ * and env are exactly what isolation looks like from inside.
12
+ */
13
+ export const ISOLATED_ENV = 'ULTIMATE_TEST_ISOLATED';
14
+
15
+ /**
16
+ * `Bun.plugin.clearAll()` after each file, isolated runs only. Measured on notificado.co's unit
17
+ * suite (652 files, 18 workers): per-worker peak 2.1–2.3 GB → 1.0–1.5 GB, total ~30 GB → 18 GB. The
18
+ * next file's preload registers the plugins again, so every file still gets them.
19
+ *
20
+ * NEVER in a shared process: render's loader keeps an `installed` flag, so a cleared plugin is
21
+ * never re-registered and the next `.tsx` compiles with Bun's classic factory — `__xh is not
22
+ * defined`.
23
+ */
24
+ export function releasePluginsAfterIsolatedFile(
25
+ env: Readonly<Record<string, string | undefined>> = Bun.env,
26
+ after: (hook: () => void) => void = afterAll,
27
+ plugin: { clearAll(): void } = Bun.plugin,
28
+ ): boolean {
29
+ if (env[ISOLATED_ENV] !== '1') return false;
30
+ after(() => clearPlugins(plugin));
31
+ return true;
32
+ }
33
+
34
+ /** Every `Bun.plugin` handler this process registered. The next file's preload registers them again. */
35
+ export const clearPlugins = (plugin: { clearAll(): void } = Bun.plugin): void => {
36
+ plugin.clearAll();
37
+ };
package/src/preload.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  import { installDeterminism } from './determinism';
9
9
  import { registerFrameworkFixtures } from './framework-fixtures';
10
10
  import './matchers';
11
+ import { releasePluginsAfterIsolatedFile } from './isolated-plugins';
11
12
  import { installRegistryLeakGuard } from './registry-leak-guard';
12
13
  import { sealNetwork } from './sealed-network';
13
14
 
@@ -25,6 +26,10 @@ registerFrameworkFixtures();
25
26
  // fails a later file in another package, for a reason nothing in that file explains.
26
27
  installRegistryLeakGuard();
27
28
 
29
+ // Isolated runs only (`x test` says so): Bun 1.4.0 keeps every finished file alive while a plugin
30
+ // is registered. See `isolated-plugins.ts`.
31
+ releasePluginsAfterIsolatedFile();
32
+
28
33
  // Opt-out exists for one case: a test that deliberately exercises a real integration in a job the
29
34
  // team runs on purpose. It is an env var, not an API, so it cannot be set from inside a test file.
30
35
  if (Bun.env['ULTIMATE_TEST_ALLOW_NET'] !== '1') sealNetwork();
@@ -111,8 +111,10 @@ let installed = false;
111
111
  * otherwise register the hooks twice and report every leak twice.
112
112
  *
113
113
  * Under `--isolate` each file gets its own module registry, so the guard judges that one file and
114
- * nothing carries across — which is correct, not a hole: with `--isolate` there is no cross-file
115
- * pollution to find, and a file that leaks is still reported against itself.
114
+ * no REGISTRY state carries across — which is correct, not a hole: a file that leaks is still
115
+ * reported against itself. MEMORY does carry across: on Bun 1.4.0 the plugin this registers keeps
116
+ * every finished file's global object alive for the life of the worker (~57 MB per file measured).
117
+ * `isolated-plugins.ts` clears the plugins after each isolated file.
116
118
  */
117
119
  export function installRegistryLeakGuard(): void {
118
120
  if (installed) return;