@happyvertical/smrt-vitest 0.51.1 → 0.51.3

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/AGENTS.md CHANGED
@@ -24,6 +24,31 @@ Without the plugin → "unregistered class" / "No field metadata found" errors.
24
24
  4. Registers all classes in ObjectRegistry
25
25
  5. Watch mode caveat: manifest only generated at startup — restart vitest after adding new classes/fields
26
26
 
27
+ ## Pool and isolation (#2897)
28
+
29
+ Measured on a 333-file, 3,259-test unit suite, 16 cores (follow-up to #2893):
30
+
31
+ | mode | wall | CPU | result |
32
+ |---|---|---|---|
33
+ | `pool: 'forks'`, isolated (default) | 22.9 s | 274 s | all pass |
34
+ | `pool: 'threads'`, isolated | 19.4 s | 234 s | all pass |
35
+ | `pool: 'forks'`, `isolate: false` | 12.1 s | 93 s | 7 fail in 1 file (leaked module mock from another file) |
36
+
37
+ - `pool: 'threads'` is supported and ran ~15% cheaper here; try it per project
38
+ since native drivers can behave differently under threads vs. forks.
39
+ - `isolate: false` is supported by this plugin's own setup: the registration
40
+ guard in `src/setup.ts` is self-healing by design (it re-registers after
41
+ `ObjectRegistry.clear()`, which is why that guard exists — #2750). Turning
42
+ isolation off is a consumer decision: it removes the leak guard between test
43
+ files, so a failing file under it is a real cross-file leak to fix, not a
44
+ plugin bug. Recommend it for unit projects only, never for integration
45
+ projects.
46
+ - The per-file fixed cost is process + module-graph bootstrap (roughly half a
47
+ second of CPU per file), not manifest registration (50-90 ms). Precomputing
48
+ registration saves little against that fixed cost; see the #2893
49
+ measurements. Lazy-loading `@happyvertical/ai` in core is the
50
+ isolation-preserving lever, tracked separately.
51
+
27
52
  ## Vite 8 (rolldown/oxc) normalization (#2017)
28
53
 
29
54
  The plugin's `config` hook normalizes three vite 8 behaviors so consumers
@@ -116,6 +141,27 @@ the test transaction. Transaction handles are treated as already initialized
116
141
  by SMRT objects, so moving this provisioning into the transaction would leave
117
142
  the first interceptor-driven write without its required function (#2427).
118
143
 
144
+ The setup file's mocked `getDatabase()` also prechecks a PostgreSQL handle's
145
+ live schema before calling `syncSchema` (#2890): two constant-count queries
146
+ (`information_schema.columns` joined to `information_schema.tables` on
147
+ `table_type = 'BASE TABLE'` + `pg_indexes`, scoped to `current_schema()` —
148
+ never a literal `'public'`, since in-repo suites open handles against other
149
+ schemas via `search_path` — and batched across every registered table)
150
+ replace a per-column `SELECT EXISTS` round trip for every table on every
151
+ call, so a handle reopened against an already-provisioned database (a
152
+ per-test database name defeats the connection-URL-keyed
153
+ `preparedSchemasByConfig` cache) skips `syncSchema` entirely for tables that
154
+ already have every declared column and index. The `BASE TABLE` join matters
155
+ because `information_schema.columns` alone also lists a VIEW's columns; a
156
+ same-named view would otherwise satisfy the precheck (no `pg_indexes` rows
157
+ required) but cannot store rows. The precheck never runs on a
158
+ transactional handle (it would read un-savepointed, and PostgreSQL silently
159
+ no-ops every later statement on an aborted transaction) — `syncSchema` runs
160
+ for every table there, same as on any precheck failure on a non-transactional
161
+ handle, matching pre-#2890 behavior in both cases. Opt out per call with
162
+ `getDatabase({ ..., __smrtSkipVitestSchemaPreparation: true })`, or disable
163
+ automatic schema preparation globally with `SMRT_VITEST_AUTO_SCHEMA=0`.
164
+
119
165
  For local file-backed SQLite, identical schemas are prepared once per Vitest
120
166
  process and cloned from an immutable schema-only template for later databases.
121
167
  The cache key is the full generated DDL, concurrent first callers share one
package/README.md CHANGED
@@ -33,7 +33,7 @@ Without this plugin, tests fail with `"No field metadata found"` or `"unregister
33
33
  | `include` | `string[]` | `['src/**/*.ts']` | Source patterns to scan |
34
34
  | `exclude` | `string[]` | `['**/*.d.ts', ...]` | Patterns to exclude |
35
35
  | `packages` | `string[]` | `[]` | Additional packages beyond auto-discovered |
36
- | `verbose` | `boolean` | `false` | Enable detailed logging |
36
+ | `verbose` | `boolean` | `false` | Emit per-package manifest-registration log lines. Also on with `SMRT_VERBOSE=true` or `DEBUG` containing `smrt`, regardless of this option. A one-line per-process summary (`Loaded manifests from N/M packages`) always logs once even when this is `false`. |
37
37
  | `root` | `string` | `process.cwd()` | Root directory |
38
38
  | `setupFile` | `string` | package setup entry | Override the setup file injected into Vitest projects |
39
39
  | `aliasFilter` | `(entry) => boolean` | keep all | Drop auto-generated workspace alias entries (receives the raw string `find` and `replacement`) |
@@ -83,6 +83,31 @@ settings on vite 8.
83
83
 
84
84
  The manifest is generated once at vitest startup. Restart vitest after adding new `@smrt()` classes or fields.
85
85
 
86
+ ### Pool and Isolation
87
+
88
+ Measured on a 333-file, 3,259-test unit suite, 16 cores (#2897, follow-up to #2893):
89
+
90
+ | mode | wall | CPU | result |
91
+ |---|---|---|---|
92
+ | `pool: 'forks'`, isolated (default) | 22.9 s | 274 s | all pass |
93
+ | `pool: 'threads'`, isolated | 19.4 s | 234 s | all pass |
94
+ | `pool: 'forks'`, `isolate: false` | 12.1 s | 93 s | 7 fail in 1 file (leaked module mock from another file) |
95
+
96
+ - **`pool: 'threads'` is supported** and came in ~15% cheaper on this suite. Try it per
97
+ project -- native drivers can behave differently under threads vs. forks.
98
+ - **`isolate: false` is supported** by this plugin's own setup: the registration guard
99
+ in `src/setup.ts` is self-healing by design (it re-registers after
100
+ `ObjectRegistry.clear()`, which is why that guard exists -- #2750). Turning isolation
101
+ off is a consumer decision, though: it removes the leak guard *between* test files, so
102
+ a failing file under it is signaling a real cross-file leak to fix, not a plugin bug.
103
+ Recommended for unit projects only, never for integration projects.
104
+ - The per-file fixed cost this plugin pays is process + module-graph bootstrap
105
+ (roughly half a second of CPU per file), not manifest registration itself
106
+ (50-90 ms). Precomputing registration would save little against that fixed cost; see
107
+ the measurements in #2893. Lazy-loading `@happyvertical/ai` in core (a separate,
108
+ isolation-preserving change) is the bigger lever for consumers with the ai package on
109
+ their dependency graph.
110
+
86
111
  ## API
87
112
 
88
113
  ### Plugin