@happyvertical/smrt-vitest
Vitest plugin for SMRT projects -- required for all SMRT tests. Auto-generates manifests, loads cross-package class metadata, and provides transaction-isolated test database utilities.
Overview
@happyvertical/smrt-vitest provides the smrtVitestPlugin() Vite plugin
that every SMRT project must include in its vitest.config.ts. Without it, tests fail
with "No field metadata found" or "unregistered class" errors.
The plugin auto-generates manifests at startup by scanning source files for @smrt() classes, discovers @happyvertical/smrt-* dependencies, and loads their manifests
into the global ObjectRegistry. The package also provides transaction-isolated test database
utilities with automatic DB adapter detection (PostgreSQL or SQLite).
Installation
pnpm add -D @happyvertical/smrt-vitestRequired Plugin Setup
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { smrtVitestPlugin } from '@happyvertical/smrt-vitest';
export default defineConfig({
plugins: [smrtVitestPlugin()],
test: {
setupFiles: ['@happyvertical/smrt-vitest/setup'] // optional: globalThis isolation
}
});Plugin Options
| Option | Type | Default | Description |
|---|---|---|---|
generateManifest | boolean | true | Auto-generate manifest at startup |
include | string[] | ['src/**/*.ts'] | Source patterns to scan |
exclude | string[] | ['**/*.d.ts', ...] | Patterns to exclude |
packages | string[] | [] | Additional packages beyond auto-discovered |
verbose | boolean | false | Enable detailed logging |
root | string | process.cwd() | Root directory |
What the Plugin Does
- Scans
src/**/*.tsfor SMRT classes via ManifestBuilder - Discovers
@happyvertical/smrt-*dependencies from package.json - Loads external manifests via ManifestManager
- Registers all classes in ObjectRegistry
Test Database Utilities
DB adapter auto-detection: if DATABASE_URL is set, uses PostgreSQL; otherwise uses SQLite temp files.
| Function | Use Case |
|---|---|
createIsolatedTestDbFromManifest() | Multi-table tests -- auto-creates schema from manifest with FK ordering and STI dedup (recommended) |
createIsolatedTestDb({ schema }) | Single-table tests -- pass raw DDL with transaction isolation |
createTestDb() | No transaction isolation (legacy) |
getTestDbConfig() | Get DB config for current environment |
getTestAdapter() | Detect adapter: 'postgres' or 'sqlite' |
isPostgresAvailable() | Check if DATABASE_URL is set |
Transaction Isolation Example
import { createIsolatedTestDbFromManifest } from '@happyvertical/smrt-vitest';
let db, cleanup;
beforeEach(async () => {
({ db, cleanup } = await createIsolatedTestDbFromManifest());
});
afterEach(async () => {
await cleanup(); // Rolls back transaction
});
it('should insert and query', async () => {
await db.insert('users', { id: '1', name: 'Alice' });
const user = await db.get('users', { id: '1' });
expect(user?.name).toBe('Alice');
});Raw Schema Example
import { createIsolatedTestDb } from '@happyvertical/smrt-vitest';
let db, cleanup;
beforeEach(async () => {
({ db, cleanup } = await createIsolatedTestDb({
schema: `CREATE TABLE users (id TEXT PRIMARY KEY, name TEXT NOT NULL)`
}));
});
afterEach(async () => {
await cleanup();
});Imperative Setup
For non-Vite setups (e.g., globalSetup files), use setupSmrtManifests() directly.
This loads manifests but does not auto-generate them.
import { setupSmrtManifests } from '@happyvertical/smrt-vitest';
// In a globalSetup file or custom bootstrap
await setupSmrtManifests({ verbose: true });Singleton Cache Gotcha
Module-level singleton caches (common in SMRT collections) persist across tests, ignoring
new mocks. Fix by using vi.resetModules() in beforeEach and
dynamic await import(...) in each test instead of top-level imports.