@happyvertical/smrt-vitest 0.30.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/AGENTS.md +109 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +103 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/a11y.d.ts +19 -0
- package/dist/a11y.d.ts.map +1 -0
- package/dist/a11y.js +39 -0
- package/dist/a11y.js.map +1 -0
- package/dist/index.d.ts +190 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +718 -0
- package/dist/index.js.map +1 -0
- package/dist/setup.d.ts +22 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +209 -0
- package/dist/setup.js.map +1 -0
- package/dist/svelte-setup.d.ts +2 -0
- package/dist/svelte-setup.d.ts.map +1 -0
- package/dist/svelte-setup.js +46 -0
- package/dist/svelte-setup.js.map +1 -0
- package/dist/svelte.d.ts +21 -0
- package/dist/svelte.d.ts.map +1 -0
- package/dist/svelte.js +21 -0
- package/dist/svelte.js.map +1 -0
- package/dist/test-db.d.ts +381 -0
- package/dist/test-db.d.ts.map +1 -0
- package/dist/test-db.js +887 -0
- package/dist/test-db.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +88 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @happyvertical/smrt-vitest
|
|
2
|
+
|
|
3
|
+
Vitest plugin for manifest generation and test database utilities. **Required for all SMRT projects.**
|
|
4
|
+
|
|
5
|
+
## Plugin Setup
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// vitest.config.ts
|
|
9
|
+
import { defineConfig } from 'vitest/config';
|
|
10
|
+
import { smrtVitestPlugin } from '@happyvertical/smrt-vitest';
|
|
11
|
+
export default defineConfig({
|
|
12
|
+
plugins: [smrtVitestPlugin()],
|
|
13
|
+
test: { setupFiles: ['@happyvertical/smrt-vitest/setup'] } // optional: globalThis isolation
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Without the plugin → "unregistered class" / "No field metadata found" errors.
|
|
18
|
+
|
|
19
|
+
## What the Plugin Does
|
|
20
|
+
|
|
21
|
+
1. Scans `src/**/*.ts` for SMRT classes via ManifestBuilder
|
|
22
|
+
2. Discovers `@happyvertical/smrt-*` dependencies from package.json
|
|
23
|
+
3. Loads external manifests via ManifestManager
|
|
24
|
+
4. Registers all classes in ObjectRegistry
|
|
25
|
+
5. Watch mode caveat: manifest only generated at startup — restart vitest after adding new classes/fields
|
|
26
|
+
|
|
27
|
+
## CI retry (flaky-test resilience)
|
|
28
|
+
|
|
29
|
+
The plugin injects `test.retry` into every consuming package's config: **2 in CI
|
|
30
|
+
(`process.env.CI`), 0 locally** (`resolveCiRetry`). Several packages have rare,
|
|
31
|
+
CI-environment-specific timing flakes that pass on re-run (none reproducible
|
|
32
|
+
locally); retry keeps the shared cross-package "Test Packages" job reliable
|
|
33
|
+
without masking real failures — a deterministic failure still fails all attempts,
|
|
34
|
+
and vitest flags retried tests as `flaky`. Local runs keep retry at 0 so flakes
|
|
35
|
+
surface during development. Override with `SMRT_VITEST_RETRY=<n>`.
|
|
36
|
+
|
|
37
|
+
Packages that don't use `smrtVitestPlugin` (notably `cli`, plus `core`) set the
|
|
38
|
+
same `retry` policy inline in their own `vitest.config.ts`.
|
|
39
|
+
|
|
40
|
+
## Test Database Utilities
|
|
41
|
+
|
|
42
|
+
| Function | Use Case |
|
|
43
|
+
|----------|----------|
|
|
44
|
+
| `createIsolatedTestDbFromManifest()` | Multi-table tests — auto-creates schema from manifest with FK ordering and STI dedup |
|
|
45
|
+
| `createIsolatedTestDb({ schema })` | Single-table tests — pass raw DDL |
|
|
46
|
+
| `createTestDb()` | No transaction isolation (legacy) |
|
|
47
|
+
| `getTestDbConfig()` | Get DB config for current environment |
|
|
48
|
+
|
|
49
|
+
**DB adapter auto-detection**: `DATABASE_URL` set → PostgreSQL; otherwise → SQLite temp files.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
let db, cleanup;
|
|
53
|
+
beforeEach(async () => {
|
|
54
|
+
({ db, cleanup } = await createIsolatedTestDbFromManifest());
|
|
55
|
+
});
|
|
56
|
+
afterEach(async () => { await cleanup(); }); // rolls back transaction
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Singleton Cache Gotcha
|
|
60
|
+
|
|
61
|
+
Module-level singleton caches (common in SMRT collections) persist across tests, ignoring new mocks.
|
|
62
|
+
|
|
63
|
+
**Fix**: `vi.resetModules()` in beforeEach + `await import(...)` in each test (not top-level imports).
|
|
64
|
+
|
|
65
|
+
## Svelte component testing (S11 #1416)
|
|
66
|
+
|
|
67
|
+
Shared component-test harness so any UI package can render Svelte components, drive
|
|
68
|
+
them, and assert a11y — without copying setup or adding Testing Library deps
|
|
69
|
+
(smrt-vitest carries `@testing-library/{svelte,jest-dom,user-event}` + `axe-core`).
|
|
70
|
+
|
|
71
|
+
Wire it into a package's `vitest.config.ts` (keep `environment: 'node'` as default
|
|
72
|
+
so DB tests are unaffected — the harness only activates under a DOM):
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
test: {
|
|
76
|
+
environment: 'node',
|
|
77
|
+
setupFiles: [smrtVitestSetupPath, '@happyvertical/smrt-vitest/svelte-setup'],
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`svelte-setup` adds jest-dom matchers, Testing Library auto-cleanup, and a jsdom
|
|
82
|
+
`<dialog>` `showModal`/`close` polyfill — guarded behind a `document` check, so it
|
|
83
|
+
is inert in node-environment test files.
|
|
84
|
+
|
|
85
|
+
Component tests opt into the DOM per-file and import the whole surface from one place:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// @vitest-environment jsdom
|
|
89
|
+
import { render, screen, userEvent, expectNoA11yViolations }
|
|
90
|
+
from '@happyvertical/smrt-vitest/svelte';
|
|
91
|
+
|
|
92
|
+
const { container } = render(MyComponent, { props });
|
|
93
|
+
await userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
|
94
|
+
await expectNoA11yViolations(container); // axe; color-contrast off (jsdom can't paint)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Exports: `./svelte` (render/screen/fireEvent/within/userEvent + `expectNoA11yViolations`),
|
|
98
|
+
`./svelte-setup` (the setupFiles entry), `./a11y` (just the axe helper). The plugin
|
|
99
|
+
aliases these subpaths to source for workspace consumers (`getWorkspaceViteAliases`).
|
|
100
|
+
Pattern: render → assert role/name/state → drive with user-event → prove axe-clean.
|
|
101
|
+
|
|
102
|
+
## Key Files
|
|
103
|
+
|
|
104
|
+
- `src/index.ts` — Vite plugin, manifest generation, workspace aliases, all exports
|
|
105
|
+
- `src/setup.ts` — globalThis isolation setup file
|
|
106
|
+
- `src/svelte-setup.ts` — Svelte component-test setup (jest-dom, cleanup, dialog polyfill)
|
|
107
|
+
- `src/svelte.ts` — component-test surface (Testing Library + a11y, one import)
|
|
108
|
+
- `src/a11y.ts` — `expectNoA11yViolations` (axe-core)
|
|
109
|
+
- `src/test-db.ts` — createIsolatedTestDb, createIsolatedTestDbFromManifest, createTestDb
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @happyvertical/smrt-vitest
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @happyvertical/smrt-vitest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Required Plugin Setup
|
|
14
|
+
|
|
15
|
+
Every SMRT project must include `smrtVitestPlugin()` in vitest.config.ts:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { defineConfig } from 'vitest/config';
|
|
19
|
+
import { smrtVitestPlugin } from '@happyvertical/smrt-vitest';
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
plugins: [smrtVitestPlugin()],
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Without this plugin, tests fail with `"No field metadata found"` or `"unregistered class"` errors.
|
|
27
|
+
|
|
28
|
+
### Plugin Options
|
|
29
|
+
|
|
30
|
+
| Option | Type | Default | Description |
|
|
31
|
+
|--------|------|---------|-------------|
|
|
32
|
+
| `generateManifest` | `boolean` | `true` | Auto-generate manifest at startup |
|
|
33
|
+
| `include` | `string[]` | `['src/**/*.ts']` | Source patterns to scan |
|
|
34
|
+
| `exclude` | `string[]` | `['**/*.d.ts', ...]` | Patterns to exclude |
|
|
35
|
+
| `packages` | `string[]` | `[]` | Additional packages beyond auto-discovered |
|
|
36
|
+
| `verbose` | `boolean` | `false` | Enable detailed logging |
|
|
37
|
+
| `root` | `string` | `process.cwd()` | Root directory |
|
|
38
|
+
|
|
39
|
+
### Watch Mode Note
|
|
40
|
+
|
|
41
|
+
The manifest is generated once at vitest startup. Restart vitest after adding new `@smrt()` classes or fields.
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### Plugin
|
|
46
|
+
|
|
47
|
+
| Export | Description |
|
|
48
|
+
|--------|-------------|
|
|
49
|
+
| `smrtVitestPlugin(options?)` | Vite plugin -- generates manifest and loads cross-package classes |
|
|
50
|
+
| `setupSmrtManifests(options?)` | Imperative alternative for non-Vite setups (e.g., globalSetup files) |
|
|
51
|
+
|
|
52
|
+
### Test Database Utilities
|
|
53
|
+
|
|
54
|
+
| Export | Description |
|
|
55
|
+
|--------|-------------|
|
|
56
|
+
| `createIsolatedTestDbFromManifest(options?)` | Create DB from manifest with FK ordering and STI dedup (recommended) |
|
|
57
|
+
| `createIsolatedTestDb(options?)` | Create DB with raw DDL schema and transaction isolation |
|
|
58
|
+
| `createTestDb(prefix?)` | Create DB with cleanup function (no transaction isolation) |
|
|
59
|
+
| `getTestDbConfig(prefix?)` | Get DB config for current environment |
|
|
60
|
+
| `getInMemoryDbConfig()` | Get in-memory SQLite config |
|
|
61
|
+
| `getTestAdapter()` | Detect adapter: `'postgres'` or `'sqlite'` |
|
|
62
|
+
| `getAdapterDisplayName()` | Human-readable adapter name for test labels |
|
|
63
|
+
| `isPostgresAvailable()` | Check if `DATABASE_URL` is set |
|
|
64
|
+
|
|
65
|
+
DB adapter auto-detection: `DATABASE_URL` set -> PostgreSQL; otherwise -> SQLite temp files.
|
|
66
|
+
|
|
67
|
+
### Transaction Isolation Example
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { createIsolatedTestDb } from '@happyvertical/smrt-vitest';
|
|
71
|
+
|
|
72
|
+
let db, cleanup;
|
|
73
|
+
|
|
74
|
+
beforeEach(async () => {
|
|
75
|
+
({ db, cleanup } = await createIsolatedTestDb({
|
|
76
|
+
schema: `CREATE TABLE users (id TEXT PRIMARY KEY, name TEXT NOT NULL)`
|
|
77
|
+
}));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
afterEach(async () => {
|
|
81
|
+
await cleanup(); // Rolls back transaction
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should insert and query', async () => {
|
|
85
|
+
await db.insert('users', { id: '1', name: 'Alice' });
|
|
86
|
+
const user = await db.get('users', { id: '1' });
|
|
87
|
+
expect(user?.name).toBe('Alice');
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Types
|
|
92
|
+
|
|
93
|
+
`IsolatedTestDbOptions`, `IsolatedTestDbResult`, `ManifestTestDbOptions`, `TestDbAdapter`, `TestDbConfig`, `TransactionHandle`
|
|
94
|
+
|
|
95
|
+
## Dependencies
|
|
96
|
+
|
|
97
|
+
- `@happyvertical/smrt-core` -- manifest builder, object registry
|
|
98
|
+
- `@happyvertical/sql` -- database connections and transactions
|
|
99
|
+
- `vitest` (peer) -- Vite test framework
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|