@stratal/testing 0.0.21 → 0.0.23
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/README.md +0 -17
- package/dist/database/index.d.mts +2 -0
- package/dist/database/index.mjs +2 -0
- package/dist/database-B02eYKhE.mjs +334 -0
- package/dist/database-B02eYKhE.mjs.map +1 -0
- package/dist/decorate-B7nr7eBl.mjs +9 -0
- package/dist/feature-flags/index.d.mts +2 -0
- package/dist/feature-flags/index.mjs +2 -0
- package/dist/feature-flags-BiLhfSGh.mjs +86 -0
- package/dist/feature-flags-BiLhfSGh.mjs.map +1 -0
- package/dist/index-BIr5nLof.d.mts +122 -0
- package/dist/index-BIr5nLof.d.mts.map +1 -0
- package/dist/{index-D-Q2cR2v.d.mts → index-CrHzUDKX.d.mts} +1 -1
- package/dist/index-CrHzUDKX.d.mts.map +1 -0
- package/dist/index-qgWNJRdC.d.mts +65 -0
- package/dist/index-qgWNJRdC.d.mts.map +1 -0
- package/dist/index.d.mts +29 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +98 -68
- package/dist/index.mjs.map +1 -1
- package/dist/mocks/zenstack-language.d.mts.map +1 -1
- package/dist/mocks/zenstack-language.mjs.map +1 -1
- package/dist/storage/index.d.mts +2 -2
- package/dist/storage/index.mjs +1 -1
- package/dist/{storage-CIXR3QUE.mjs → storage-DhoxWqyF.mjs} +5 -18
- package/dist/{storage-CIXR3QUE.mjs.map → storage-DhoxWqyF.mjs.map} +1 -1
- package/dist/vitest-plugin/index.d.mts +71 -5
- package/dist/vitest-plugin/index.d.mts.map +1 -1
- package/dist/vitest-plugin/index.mjs +82 -11
- package/dist/vitest-plugin/index.mjs.map +1 -1
- package/package.json +26 -18
- package/dist/index-D-Q2cR2v.d.mts.map +0 -1
- package/dist/mocks/nodemailer.d.mts +0 -12
- package/dist/mocks/nodemailer.d.mts.map +0 -1
- package/dist/mocks/nodemailer.mjs +0 -7
- package/dist/mocks/nodemailer.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-CIXR3QUE.mjs","names":[],"sources":["../src/storage/fake-storage.service.ts"],"sourcesContent":["import { Transient, inject } from 'stratal/di'\nimport {\n FileNotFoundError,\n STORAGE_TOKENS,\n type StorageManagerService,\n StorageService,\n type StreamingBlobPayloadInputTypes,\n type DownloadResult,\n type PresignedUrlResult,\n type StorageConfig,\n type UploadOptions,\n type UploadResult,\n} from 'stratal/storage'\nimport { expect } from 'vitest'\n\n/**\n * Stored file representation in memory\n */\nexport interface StoredFile {\n content: Uint8Array\n mimeType: string\n size: number\n metadata?: Record<string, string>\n uploadedAt: Date\n}\n\n/**\n * FakeStorageService\n *\n * In-memory storage implementation for testing.\n * Registered by default in TestingModuleBuilder.\n *\n * Similar to Laravel's Storage::fake() - stores files in memory\n * and provides assertion helpers for testing.\n *\n * @example\n * ```typescript\n * // Access via TestingModule\n * module.storage.assertExists('path/to/file.pdf')\n * module.storage.assertMissing('deleted/file.pdf')\n * module.storage.clear() // Reset between tests\n * ```\n */\n@Transient(STORAGE_TOKENS.StorageService)\nexport class FakeStorageService extends StorageService {\n private files = new Map<string, StoredFile>()\n\n constructor(\n @inject(STORAGE_TOKENS.StorageManager)\n protected readonly storageManager: StorageManagerService,\n @inject(STORAGE_TOKENS.Options)\n protected readonly options: StorageConfig\n ) {\n super(storageManager, options)\n }\n\n /**\n * Upload content to fake storage\n */\n async upload(\n body: StreamingBlobPayloadInputTypes,\n relativePath: string,\n options: UploadOptions,\n disk?: string\n ): Promise<UploadResult> {\n const content = await this.bodyToUint8Array(body)\n const diskName = this.resolveDisk(disk)\n\n this.files.set(relativePath, {\n content,\n mimeType: options.mimeType ?? 'application/octet-stream',\n size: options.size,\n metadata: options.metadata,\n uploadedAt: new Date(),\n })\n\n return {\n path: relativePath,\n disk: diskName,\n fullPath: relativePath,\n size: options.size,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n }\n }\n\n /**\n * Download a file from fake storage\n */\n download(path: string): Promise<DownloadResult> {\n const file = this.files.get(path)\n\n if (!file) {\n return Promise.reject(new FileNotFoundError(path))\n }\n\n return Promise.resolve({\n toStream: () => new ReadableStream({\n start(controller) {\n controller.enqueue(file.content)\n controller.close()\n },\n }),\n toString: () => Promise.resolve(new TextDecoder().decode(file.content)),\n toArrayBuffer: () => Promise.resolve(file.content),\n contentType: file.mimeType,\n size: file.size,\n metadata: file.metadata,\n })\n }\n\n /**\n * Delete a file from fake storage\n */\n delete(path: string): Promise<void> {\n this.files.delete(path)\n return Promise.resolve()\n }\n\n /**\n * Check if a file exists in fake storage\n */\n exists(path: string): Promise<boolean> {\n return Promise.resolve(this.files.has(path))\n }\n\n /**\n * Generate a fake presigned download URL\n */\n getPresignedDownloadUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'GET', expiresIn))\n }\n\n /**\n * Generate a fake presigned upload URL\n */\n getPresignedUploadUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'PUT', expiresIn))\n }\n\n /**\n * Generate a fake presigned delete URL\n */\n getPresignedDeleteUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'DELETE', expiresIn))\n }\n\n /**\n * Chunked upload (same as regular upload for fake)\n */\n async chunkedUpload(\n body: StreamingBlobPayloadInputTypes,\n path: string,\n options: Omit<UploadOptions, 'size'> & { size?: number },\n disk?: string\n ): Promise<UploadResult> {\n const content = await this.bodyToUint8Array(body)\n const size = options.size ?? content.length\n\n return this.upload(body, path, { ...options, size }, disk)\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Test Assertion Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Assert that a file exists at the given path\n *\n * @param path - Path to check\n * @throws AssertionError if file does not exist\n */\n assertExists(path: string): void {\n expect(\n this.files.has(path),\n `Expected file to exist at: ${path}\\nStored files: ${this.getStoredPaths().join(', ') || '(none)'}`\n ).toBe(true)\n }\n\n /**\n * Assert that a file does NOT exist at the given path\n *\n * @param path - Path to check\n * @throws AssertionError if file exists\n */\n assertMissing(path: string): void {\n expect(\n this.files.has(path),\n `Expected file NOT to exist at: ${path}`\n ).toBe(false)\n }\n\n /**\n * Assert storage is empty\n *\n * @throws AssertionError if any files exist\n */\n assertEmpty(): void {\n expect(\n this.files.size,\n `Expected storage to be empty but found ${this.files.size} files: ${this.getStoredPaths().join(', ')}`\n ).toBe(0)\n }\n\n /**\n * Assert storage has exactly N files\n *\n * @param count - Expected number of files\n * @throws AssertionError if count doesn't match\n */\n assertCount(count: number): void {\n expect(\n this.files.size,\n `Expected ${count} files in storage but found ${this.files.size}`\n ).toBe(count)\n }\n\n /**\n * Get all stored files (for inspection)\n */\n getStoredFiles(): Map<string, StoredFile> {\n return new Map(this.files)\n }\n\n /**\n * Get all stored file paths\n */\n getStoredPaths(): string[] {\n return Array.from(this.files.keys())\n }\n\n /**\n * Get a specific file by path\n */\n getFile(path: string): StoredFile | undefined {\n return this.files.get(path)\n }\n\n /**\n * Clear all stored files (call in beforeEach for test isolation)\n */\n clear(): void {\n this.files.clear()\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n private createPresignedUrl(\n path: string,\n method: 'GET' | 'PUT' | 'DELETE' | 'HEAD',\n expiresIn = 300\n ): PresignedUrlResult {\n const expiresAt = new Date(Date.now() + expiresIn * 1000)\n\n return {\n url: `https://fake-storage.test/${path}?method=${method}&expires=${expiresAt.toISOString()}`,\n expiresIn,\n expiresAt,\n method,\n }\n }\n\n private async bodyToUint8Array(body: StreamingBlobPayloadInputTypes | null | undefined): Promise<Uint8Array> {\n if (!body) {\n return new Uint8Array(0)\n }\n\n if (body instanceof Uint8Array) {\n return body\n }\n\n if (body instanceof ArrayBuffer) {\n return new Uint8Array(body)\n }\n\n if (typeof body === 'string') {\n return new TextEncoder().encode(body)\n }\n\n if (body instanceof Blob) {\n const buffer = await body.arrayBuffer()\n return new Uint8Array(buffer)\n }\n\n if (body instanceof ReadableStream) {\n return new Uint8Array(await new Response(body).arrayBuffer())\n }\n\n // FormData or URLSearchParams - convert via Response\n if (body instanceof FormData || body instanceof URLSearchParams) {\n return new Uint8Array(await new Response(body).arrayBuffer())\n }\n\n return new Uint8Array(0)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-DhoxWqyF.mjs","names":[],"sources":["../src/storage/fake-storage.service.ts"],"sourcesContent":["import { Transient, inject } from 'stratal/di'\nimport {\n FileNotFoundError,\n STORAGE_TOKENS,\n type StorageManagerService,\n StorageService,\n type StreamingBlobPayloadInputTypes,\n type DownloadResult,\n type PresignedUrlResult,\n type StorageConfig,\n type UploadOptions,\n type UploadResult,\n} from 'stratal/storage'\nimport { expect } from 'vitest'\n\n/**\n * Stored file representation in memory\n */\nexport interface StoredFile {\n content: Uint8Array\n mimeType: string\n size: number\n metadata?: Record<string, string>\n uploadedAt: Date\n}\n\n/**\n * FakeStorageService\n *\n * In-memory storage implementation for testing.\n * Registered by default in TestingModuleBuilder.\n *\n * Similar to Laravel's Storage::fake() - stores files in memory\n * and provides assertion helpers for testing.\n *\n * @example\n * ```typescript\n * // Access via TestingModule\n * module.storage.assertExists('path/to/file.pdf')\n * module.storage.assertMissing('deleted/file.pdf')\n * module.storage.clear() // Reset between tests\n * ```\n */\n@Transient(STORAGE_TOKENS.StorageService)\nexport class FakeStorageService extends StorageService {\n private files = new Map<string, StoredFile>()\n\n constructor(\n @inject(STORAGE_TOKENS.StorageManager)\n protected readonly storageManager: StorageManagerService,\n @inject(STORAGE_TOKENS.Options)\n protected readonly options: StorageConfig\n ) {\n super(storageManager, options)\n }\n\n /**\n * Upload content to fake storage\n */\n async upload(\n body: StreamingBlobPayloadInputTypes,\n relativePath: string,\n options: UploadOptions,\n disk?: string\n ): Promise<UploadResult> {\n const content = await this.bodyToUint8Array(body)\n const diskName = this.resolveDisk(disk)\n\n this.files.set(relativePath, {\n content,\n mimeType: options.mimeType ?? 'application/octet-stream',\n size: options.size,\n metadata: options.metadata,\n uploadedAt: new Date(),\n })\n\n return {\n path: relativePath,\n disk: diskName,\n fullPath: relativePath,\n size: options.size,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n }\n }\n\n /**\n * Download a file from fake storage\n */\n download(path: string): Promise<DownloadResult> {\n const file = this.files.get(path)\n\n if (!file) {\n return Promise.reject(new FileNotFoundError(path))\n }\n\n return Promise.resolve({\n toStream: () => new ReadableStream({\n start(controller) {\n controller.enqueue(file.content)\n controller.close()\n },\n }),\n toString: () => Promise.resolve(new TextDecoder().decode(file.content)),\n toArrayBuffer: () => Promise.resolve(file.content),\n contentType: file.mimeType,\n size: file.size,\n metadata: file.metadata,\n })\n }\n\n /**\n * Delete a file from fake storage\n */\n delete(path: string): Promise<void> {\n this.files.delete(path)\n return Promise.resolve()\n }\n\n /**\n * Check if a file exists in fake storage\n */\n exists(path: string): Promise<boolean> {\n return Promise.resolve(this.files.has(path))\n }\n\n /**\n * Generate a fake presigned download URL\n */\n getPresignedDownloadUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'GET', expiresIn))\n }\n\n /**\n * Generate a fake presigned upload URL\n */\n getPresignedUploadUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'PUT', expiresIn))\n }\n\n /**\n * Generate a fake presigned delete URL\n */\n getPresignedDeleteUrl(\n path: string,\n expiresIn?: number\n ): Promise<PresignedUrlResult> {\n return Promise.resolve(this.createPresignedUrl(path, 'DELETE', expiresIn))\n }\n\n /**\n * Chunked upload (same as regular upload for fake)\n */\n async chunkedUpload(\n body: StreamingBlobPayloadInputTypes,\n path: string,\n options: Omit<UploadOptions, 'size'> & { size?: number },\n disk?: string\n ): Promise<UploadResult> {\n const content = await this.bodyToUint8Array(body)\n const size = options.size ?? content.length\n\n return this.upload(body, path, { ...options, size }, disk)\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Test Assertion Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Assert that a file exists at the given path\n *\n * @param path - Path to check\n * @throws AssertionError if file does not exist\n */\n assertExists(path: string): void {\n expect(\n this.files.has(path),\n `Expected file to exist at: ${path}\\nStored files: ${this.getStoredPaths().join(', ') || '(none)'}`\n ).toBe(true)\n }\n\n /**\n * Assert that a file does NOT exist at the given path\n *\n * @param path - Path to check\n * @throws AssertionError if file exists\n */\n assertMissing(path: string): void {\n expect(\n this.files.has(path),\n `Expected file NOT to exist at: ${path}`\n ).toBe(false)\n }\n\n /**\n * Assert storage is empty\n *\n * @throws AssertionError if any files exist\n */\n assertEmpty(): void {\n expect(\n this.files.size,\n `Expected storage to be empty but found ${this.files.size} files: ${this.getStoredPaths().join(', ')}`\n ).toBe(0)\n }\n\n /**\n * Assert storage has exactly N files\n *\n * @param count - Expected number of files\n * @throws AssertionError if count doesn't match\n */\n assertCount(count: number): void {\n expect(\n this.files.size,\n `Expected ${count} files in storage but found ${this.files.size}`\n ).toBe(count)\n }\n\n /**\n * Get all stored files (for inspection)\n */\n getStoredFiles(): Map<string, StoredFile> {\n return new Map(this.files)\n }\n\n /**\n * Get all stored file paths\n */\n getStoredPaths(): string[] {\n return Array.from(this.files.keys())\n }\n\n /**\n * Get a specific file by path\n */\n getFile(path: string): StoredFile | undefined {\n return this.files.get(path)\n }\n\n /**\n * Clear all stored files (call in beforeEach for test isolation)\n */\n clear(): void {\n this.files.clear()\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n private createPresignedUrl(\n path: string,\n method: 'GET' | 'PUT' | 'DELETE' | 'HEAD',\n expiresIn = 300\n ): PresignedUrlResult {\n const expiresAt = new Date(Date.now() + expiresIn * 1000)\n\n return {\n url: `https://fake-storage.test/${path}?method=${method}&expires=${expiresAt.toISOString()}`,\n expiresIn,\n expiresAt,\n method,\n }\n }\n\n private async bodyToUint8Array(body: StreamingBlobPayloadInputTypes | null | undefined): Promise<Uint8Array> {\n if (!body) {\n return new Uint8Array(0)\n }\n\n if (body instanceof Uint8Array) {\n return body\n }\n\n if (body instanceof ArrayBuffer) {\n return new Uint8Array(body)\n }\n\n if (typeof body === 'string') {\n return new TextEncoder().encode(body)\n }\n\n if (body instanceof Blob) {\n const buffer = await body.arrayBuffer()\n return new Uint8Array(buffer)\n }\n\n if (body instanceof ReadableStream) {\n return new Uint8Array(await new Response(body).arrayBuffer())\n }\n\n // FormData or URLSearchParams - convert via Response\n if (body instanceof FormData || body instanceof URLSearchParams) {\n return new Uint8Array(await new Response(body).arrayBuffer())\n }\n\n return new Uint8Array(0)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,42 @@
|
|
|
1
|
+
import { r as DatabaseIsolation } from "../index-BIr5nLof.mjs";
|
|
2
|
+
import { StratalEnv } from "stratal";
|
|
1
3
|
import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
|
|
2
4
|
import { Plugin } from "vite";
|
|
3
5
|
|
|
4
6
|
//#region src/vitest-plugin/stratal-test.d.ts
|
|
5
7
|
type CloudflareTestOptions = Parameters<typeof cloudflareTest>[0];
|
|
8
|
+
/** String keys of `StratalEnv` whose value is a Hyperdrive binding. */
|
|
9
|
+
type HyperdriveKeys = Extract<{ [K in keyof StratalEnv]-?: StratalEnv[K] extends Hyperdrive ? K : never }[keyof StratalEnv], string>;
|
|
10
|
+
/**
|
|
11
|
+
* Names of declared Hyperdrive bindings, drawn from the consumer's augmented
|
|
12
|
+
* `StratalEnv` (which extends `Cloudflare.Env`). Falls back to `string` only
|
|
13
|
+
* when no Hyperdrive binding is declared (nothing to constrain to).
|
|
14
|
+
*/
|
|
15
|
+
type HyperdriveBindingName = [HyperdriveKeys] extends [never] ? string : HyperdriveKeys;
|
|
16
|
+
/** Stratal-specific test database configuration for {@link stratalTest}. */
|
|
17
|
+
interface StratalTestDatabaseOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Database isolation mode for parallel runs. Defaults to `'shared'`.
|
|
20
|
+
*
|
|
21
|
+
* - `'shared'` — all test files share one database (serial; today's behaviour).
|
|
22
|
+
* - `'database'` — each test file gets its own database cloned from a migrated
|
|
23
|
+
* template (dropped on teardown), and file parallelism is enabled.
|
|
24
|
+
*
|
|
25
|
+
* Pair with `createTestDatabaseGlobalSetup({ isolation })` from
|
|
26
|
+
* `@stratal/testing/database` in your Vitest `globalSetup`.
|
|
27
|
+
*/
|
|
28
|
+
isolation?: DatabaseIsolation;
|
|
29
|
+
/**
|
|
30
|
+
* Name of the Hyperdrive binding to isolate per test file. Defaults to `'DB'`.
|
|
31
|
+
* Constrained to Hyperdrive binding names declared on `Cloudflare.Env` /
|
|
32
|
+
* `StratalEnv`.
|
|
33
|
+
*/
|
|
34
|
+
binding?: HyperdriveBindingName;
|
|
35
|
+
}
|
|
36
|
+
type WorkersPoolOptions = Exclude<CloudflareTestOptions, (...args: never[]) => unknown>;
|
|
37
|
+
type StratalTestOptions = WorkersPoolOptions & {
|
|
38
|
+
database?: StratalTestDatabaseOptions;
|
|
39
|
+
};
|
|
6
40
|
/**
|
|
7
41
|
* Returns a Vite plugin that forces CJS resolution for `pg` sub-dependencies.
|
|
8
42
|
*
|
|
@@ -33,18 +67,50 @@ type CloudflareTestOptions = Parameters<typeof cloudflareTest>[0];
|
|
|
33
67
|
* ```
|
|
34
68
|
*/
|
|
35
69
|
declare const fixPgCjs: () => Plugin;
|
|
70
|
+
/**
|
|
71
|
+
* Returns a Vite plugin that forces CJS resolution for `@noble/hashes` subpaths
|
|
72
|
+
* used by `@paralleldrive/cuid2@2.x` (the version `@zenstackhq/orm` depends on).
|
|
73
|
+
*
|
|
74
|
+
* cuid2@2.x is CJS and does `require("@noble/hashes/sha3")` without the `.js`
|
|
75
|
+
* extension. In a workspace that also installs `@noble/hashes@2.x` (ESM-only),
|
|
76
|
+
* the hoisted v2 package has no extensionless `./sha3` entry in its exports
|
|
77
|
+
* map, so Vite/workerd resolution fails. This plugin routes the extensionless
|
|
78
|
+
* subpaths through the consumer's nested `@noble/hashes@1.x` (a sibling of
|
|
79
|
+
* cuid2 under `@zenstackhq/orm/node_modules`), which ships proper CJS exports.
|
|
80
|
+
*
|
|
81
|
+
* If the consumer doesn't depend on `@zenstackhq/orm`, the plugin is a no-op.
|
|
82
|
+
* Otherwise it throws loudly at config-resolution time if the resolution chain
|
|
83
|
+
* is unexpectedly broken — surfacing dependency drift instead of letting the
|
|
84
|
+
* symptom resurface as an opaque test failure.
|
|
85
|
+
*
|
|
86
|
+
* Must be used at the **root** `defineConfig` level (same constraint as
|
|
87
|
+
* `fixPgCjs`).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* import { fixNobleHashesCjs, fixPgCjs, stratalTest } from '@stratal/testing/vitest-plugin'
|
|
92
|
+
*
|
|
93
|
+
* export default defineConfig({
|
|
94
|
+
* plugins: [fixPgCjs(), fixNobleHashesCjs()],
|
|
95
|
+
* // ...
|
|
96
|
+
* })
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare const fixNobleHashesCjs: () => Plugin;
|
|
36
100
|
/**
|
|
37
101
|
* Returns Vite plugins for Stratal tests running in the Cloudflare Workers (workerd) environment.
|
|
38
102
|
*
|
|
39
|
-
* Includes the cloudflare pool plugin and Stratal alias plugin.
|
|
40
|
-
*
|
|
103
|
+
* Includes the cloudflare pool plugin and Stratal alias plugin. Pass
|
|
104
|
+
* `database: { isolation: 'database' }` to give each test file its own
|
|
105
|
+
* database (cloned from a migrated template, dropped on teardown) and enable
|
|
106
|
+
* file parallelism. Use inside a project-level `plugins` array.
|
|
41
107
|
*
|
|
42
108
|
* **Note:** `fixPgCjs()` must be registered separately at the root `defineConfig` level.
|
|
43
109
|
*
|
|
44
|
-
* @param options -
|
|
110
|
+
* @param options - `cloudflareTest()` options plus Stratal `database` options
|
|
45
111
|
* @returns An array of Vite plugins
|
|
46
112
|
*/
|
|
47
|
-
declare function stratalTest(options?:
|
|
113
|
+
declare function stratalTest(options?: StratalTestOptions): Plugin[];
|
|
48
114
|
//#endregion
|
|
49
|
-
export { fixPgCjs, stratalTest };
|
|
115
|
+
export { type StratalTestDatabaseOptions, fixNobleHashesCjs, fixPgCjs, stratalTest };
|
|
50
116
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vitest-plugin/stratal-test.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vitest-plugin/stratal-test.ts"],"mappings":";;;;;;KAWK,qBAAA,GAAwB,UAAU,QAAQ,cAAA;;KAG1C,cAAA,GAAiB,OAAA,eACN,UAAA,KAAe,UAAA,CAAW,CAAA,UAAW,UAAA,GAAa,CAAA,iBAAkB,UAAA;;AAJvB;AAAA;;;KAaxD,qBAAA,IAAyB,cAAA,6BAA2C,cAAc;;UAGtE,0BAAA;EAZoC;;;;;;;;;;EAuBnD,SAAA,GAAY,iBAAA;EAvBuC;;;;AAAyC;EA6B5F,OAAA,GAAU,qBAAqB;AAAA;AAAA,KAG5B,kBAAA,GAAqB,OAAO,CAAC,qBAAA,MAA2B,IAAA;AAAA,KACxD,kBAAA,GAAqB,kBAAA;EAAuB,QAAA,GAAW,0BAA0B;AAAA;;;;;;;;;AAJrD;AAChC;;;;;;;;AAEgE;AAAA;;;;;;;;AACqB;AAsCtF;;cAAa,QAAA,QAAe,MAY1B;;AAAA;AA+BF;;;;AA0BC;AA4CD;;;;;;;;AAAqE;;;;;;;;;;;;;;cAtExD,iBAAA,QAAwB,MA0BpC;;;;;;;;;;;;;;iBA4Ce,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,MAAM"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { f as normalizeIsolation, r as ISOLATION_ENV_VAR, t as BINDING_ENV_VAR } from "../database-B02eYKhE.mjs";
|
|
1
2
|
import { createRequire } from "node:module";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
|
|
@@ -51,36 +52,106 @@ const fixPgCjs = () => ({
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Returns a Vite plugin that forces CJS resolution for `@noble/hashes` subpaths
|
|
57
|
+
* used by `@paralleldrive/cuid2@2.x` (the version `@zenstackhq/orm` depends on).
|
|
58
|
+
*
|
|
59
|
+
* cuid2@2.x is CJS and does `require("@noble/hashes/sha3")` without the `.js`
|
|
60
|
+
* extension. In a workspace that also installs `@noble/hashes@2.x` (ESM-only),
|
|
61
|
+
* the hoisted v2 package has no extensionless `./sha3` entry in its exports
|
|
62
|
+
* map, so Vite/workerd resolution fails. This plugin routes the extensionless
|
|
63
|
+
* subpaths through the consumer's nested `@noble/hashes@1.x` (a sibling of
|
|
64
|
+
* cuid2 under `@zenstackhq/orm/node_modules`), which ships proper CJS exports.
|
|
65
|
+
*
|
|
66
|
+
* If the consumer doesn't depend on `@zenstackhq/orm`, the plugin is a no-op.
|
|
67
|
+
* Otherwise it throws loudly at config-resolution time if the resolution chain
|
|
68
|
+
* is unexpectedly broken — surfacing dependency drift instead of letting the
|
|
69
|
+
* symptom resurface as an opaque test failure.
|
|
70
|
+
*
|
|
71
|
+
* Must be used at the **root** `defineConfig` level (same constraint as
|
|
72
|
+
* `fixPgCjs`).
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { fixNobleHashesCjs, fixPgCjs, stratalTest } from '@stratal/testing/vitest-plugin'
|
|
77
|
+
*
|
|
78
|
+
* export default defineConfig({
|
|
79
|
+
* plugins: [fixPgCjs(), fixNobleHashesCjs()],
|
|
80
|
+
* // ...
|
|
81
|
+
* })
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
const fixNobleHashesCjs = () => {
|
|
85
|
+
const ids = ["@noble/hashes/sha3", "@noble/hashes/crypto"];
|
|
86
|
+
let resolved = null;
|
|
87
|
+
return {
|
|
88
|
+
name: "stratal-noble-hashes-cjs",
|
|
89
|
+
enforce: "pre",
|
|
90
|
+
configResolved(config) {
|
|
91
|
+
const consumerRequire = createRequire(path.join(config.root, "noop.js"));
|
|
92
|
+
let zenstackPath;
|
|
93
|
+
try {
|
|
94
|
+
zenstackPath = consumerRequire.resolve("@zenstackhq/orm");
|
|
95
|
+
} catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const cuid2Require = createRequire(createRequire(zenstackPath).resolve("@paralleldrive/cuid2"));
|
|
99
|
+
resolved = new Map(ids.map((id) => [id, cuid2Require.resolve(id)]));
|
|
100
|
+
},
|
|
101
|
+
resolveId(id) {
|
|
102
|
+
return resolved?.get(id);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
const createStratalPlugin = (isolation) => ({
|
|
55
107
|
name: "stratal-test",
|
|
56
108
|
config() {
|
|
57
|
-
|
|
109
|
+
const config = {
|
|
58
110
|
resolve: { alias: {
|
|
59
|
-
tslib: "
|
|
111
|
+
tslib: "tslib/tslib.es6.mjs",
|
|
60
112
|
"@zenstackhq/language/ast": "@stratal/testing/mocks/zenstack-language",
|
|
61
113
|
"@zenstackhq/language/utils": "@stratal/testing/mocks/zenstack-language",
|
|
62
|
-
"@zenstackhq/language": "@stratal/testing/mocks/zenstack-language"
|
|
63
|
-
nodemailer: "@stratal/testing/mocks/nodemailer"
|
|
114
|
+
"@zenstackhq/language": "@stratal/testing/mocks/zenstack-language"
|
|
64
115
|
} },
|
|
65
116
|
ssr: { noExternal: ["@zenstackhq/better-auth"] }
|
|
66
117
|
};
|
|
118
|
+
if (isolation === "database") config.test = {
|
|
119
|
+
fileParallelism: true,
|
|
120
|
+
isolate: true
|
|
121
|
+
};
|
|
122
|
+
return config;
|
|
67
123
|
}
|
|
68
|
-
};
|
|
124
|
+
});
|
|
69
125
|
/**
|
|
70
126
|
* Returns Vite plugins for Stratal tests running in the Cloudflare Workers (workerd) environment.
|
|
71
127
|
*
|
|
72
|
-
* Includes the cloudflare pool plugin and Stratal alias plugin.
|
|
73
|
-
*
|
|
128
|
+
* Includes the cloudflare pool plugin and Stratal alias plugin. Pass
|
|
129
|
+
* `database: { isolation: 'database' }` to give each test file its own
|
|
130
|
+
* database (cloned from a migrated template, dropped on teardown) and enable
|
|
131
|
+
* file parallelism. Use inside a project-level `plugins` array.
|
|
74
132
|
*
|
|
75
133
|
* **Note:** `fixPgCjs()` must be registered separately at the root `defineConfig` level.
|
|
76
134
|
*
|
|
77
|
-
* @param options -
|
|
135
|
+
* @param options - `cloudflareTest()` options plus Stratal `database` options
|
|
78
136
|
* @returns An array of Vite plugins
|
|
79
137
|
*/
|
|
80
138
|
function stratalTest(options = {}) {
|
|
81
|
-
|
|
139
|
+
const { database, ...cfOptions } = options;
|
|
140
|
+
const isolation = normalizeIsolation(database?.isolation);
|
|
141
|
+
const binding = database?.binding ?? "DB";
|
|
142
|
+
return [cloudflareTest({
|
|
143
|
+
...cfOptions,
|
|
144
|
+
miniflare: {
|
|
145
|
+
...cfOptions.miniflare,
|
|
146
|
+
bindings: {
|
|
147
|
+
...cfOptions.miniflare?.bindings,
|
|
148
|
+
[ISOLATION_ENV_VAR]: isolation,
|
|
149
|
+
[BINDING_ENV_VAR]: binding
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}), createStratalPlugin(isolation)];
|
|
82
153
|
}
|
|
83
154
|
//#endregion
|
|
84
|
-
export { fixPgCjs, stratalTest };
|
|
155
|
+
export { fixNobleHashesCjs, fixPgCjs, stratalTest };
|
|
85
156
|
|
|
86
157
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/vitest-plugin/stratal-test.ts"],"sourcesContent":["import { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport { cloudflareTest } from '@cloudflare/vitest-pool-workers'\nimport type { Plugin, UserConfig } from 'vite'\n\nconst require = createRequire(import.meta.url)\n\ntype CloudflareTestOptions = Parameters<typeof cloudflareTest>[0]\n\nconst pgCjsResolvers = new Map<string, () => string>([\n ['pg-protocol', () => require.resolve('pg-protocol')],\n ['pg-connection-string', () => require.resolve('pg-connection-string')],\n ['pg-pool', () => require.resolve('pg-pool')],\n ['pg-cloudflare', () => path.join(path.dirname(require.resolve('pg-cloudflare')), 'index.js')],\n])\n\n/**\n * Returns a Vite plugin that forces CJS resolution for `pg` sub-dependencies.\n *\n * `pg` is CJS but its dependencies (`pg-protocol`, `pg-connection-string`, `pg-pool`) ship\n * dual CJS/ESM exports. In workerd, the module fallback resolver prefers the ESM condition,\n * causing `SyntaxError: Cannot use import statement outside a module` when CJS `pg` does\n * `require()`. Additionally, `pg-cloudflare` uses a `workerd` export condition that the\n * root Vite instance doesn't resolve.\n *\n * Must be used at the **root** `defineConfig` level so that the\n * `@cloudflare/vitest-pool-workers` module fallback resolver (which uses the root Vite\n * instance) resolves pg sub-deps correctly.\n *\n * @example\n * ```ts\n * import { fixPgCjs, stratalTest } from '@stratal/testing/vitest-plugin'\n * import { defineConfig } from 'vitest/config'\n *\n * export default defineConfig({\n * plugins: [fixPgCjs()],\n * test: {\n * projects: [{\n * plugins: [stratalTest({ wrangler: { configPath: './wrangler.jsonc' } })],\n * test: { name: 'e2e', include: ['test/e2e/**\\/*.spec.ts'] },\n * }],\n * },\n * })\n * ```\n */\nexport const fixPgCjs = (): Plugin => ({\n name: 'stratal-pg-cjs',\n enforce: 'pre',\n resolveId(id) {\n const resolver = pgCjsResolvers.get(id)\n if (!resolver) return\n try {\n return resolver()\n } catch {\n return\n }\n },\n})\n\nconst stratalPlugin: Plugin = {\n name: 'stratal-test',\n config() {\n return {\n resolve: {\n alias: {\n tslib: 'tsyringe/node_modules/tslib/tslib.es6.js',\n '@zenstackhq/language/ast': '@stratal/testing/mocks/zenstack-language',\n '@zenstackhq/language/utils': '@stratal/testing/mocks/zenstack-language',\n '@zenstackhq/language': '@stratal/testing/mocks/zenstack-language',\n nodemailer: '@stratal/testing/mocks/nodemailer',\n },\n },\n ssr: {\n noExternal: ['@zenstackhq/better-auth'],\n },\n } satisfies UserConfig\n },\n}\n\n/**\n * Returns Vite plugins for Stratal tests running in the Cloudflare Workers (workerd) environment.\n *\n * Includes the cloudflare pool plugin and Stratal alias plugin.\n * Use inside a project-level `plugins` array.\n *\n * **Note:** `fixPgCjs()` must be registered separately at the root `defineConfig` level.\n *\n * @param options - Same options as `cloudflareTest()` from `@cloudflare/vitest-pool-workers`\n * @returns An array of Vite plugins\n */\nexport function stratalTest(options: CloudflareTestOptions = {}): Plugin[] {\n return [cloudflareTest(options) as unknown as Plugin, stratalPlugin]\n}\n"],"mappings":";;;;AAMA,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;AAI9C,MAAM,iBAAiB,IAAI,IAA0B;CACnD,CAAC,qBAAqB,QAAQ,QAAQ,cAAc,CAAC;CACrD,CAAC,8BAA8B,QAAQ,QAAQ,uBAAuB,CAAC;CACvE,CAAC,iBAAiB,QAAQ,QAAQ,UAAU,CAAC;CAC7C,CAAC,uBAAuB,KAAK,KAAK,KAAK,QAAQ,QAAQ,QAAQ,gBAAgB,CAAC,EAAE,WAAW,CAAC;CAC/F,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BF,MAAa,kBAA0B;CACrC,MAAM;CACN,SAAS;CACT,UAAU,IAAI;EACZ,MAAM,WAAW,eAAe,IAAI,GAAG;EACvC,IAAI,CAAC,UAAU;EACf,IAAI;GACF,OAAO,UAAU;UACX;GACN;;;CAGL;AAED,MAAM,gBAAwB;CAC5B,MAAM;CACN,SAAS;EACP,OAAO;GACL,SAAS,EACP,OAAO;IACL,OAAO;IACP,4BAA4B;IAC5B,8BAA8B;IAC9B,wBAAwB;IACxB,YAAY;IACb,EACF;GACD,KAAK,EACH,YAAY,CAAC,0BAA0B,EACxC;GACF;;CAEJ;;;;;;;;;;;;AAaD,SAAgB,YAAY,UAAiC,EAAE,EAAY;CACzE,OAAO,CAAC,eAAe,QAAQ,EAAuB,cAAc"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/vitest-plugin/stratal-test.ts"],"sourcesContent":["import { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport { cloudflareTest } from '@cloudflare/vitest-pool-workers'\nimport type { StratalEnv } from 'stratal'\nimport type { Plugin, UserConfig } from 'vite'\nimport type { TestUserConfig } from 'vitest/config'\nimport { BINDING_ENV_VAR, DEFAULT_DB_BINDING, ISOLATION_ENV_VAR, normalizeIsolation, type DatabaseIsolation } from '../database'\n\nconst require = createRequire(import.meta.url)\n\ntype CloudflareTestOptions = Parameters<typeof cloudflareTest>[0]\n\n/** String keys of `StratalEnv` whose value is a Hyperdrive binding. */\ntype HyperdriveKeys = Extract<\n { [K in keyof StratalEnv]-?: StratalEnv[K] extends Hyperdrive ? K : never }[keyof StratalEnv],\n string\n>\n\n/**\n * Names of declared Hyperdrive bindings, drawn from the consumer's augmented\n * `StratalEnv` (which extends `Cloudflare.Env`). Falls back to `string` only\n * when no Hyperdrive binding is declared (nothing to constrain to).\n */\ntype HyperdriveBindingName = [HyperdriveKeys] extends [never] ? string : HyperdriveKeys\n\n/** Stratal-specific test database configuration for {@link stratalTest}. */\nexport interface StratalTestDatabaseOptions {\n /**\n * Database isolation mode for parallel runs. Defaults to `'shared'`.\n *\n * - `'shared'` — all test files share one database (serial; today's behaviour).\n * - `'database'` — each test file gets its own database cloned from a migrated\n * template (dropped on teardown), and file parallelism is enabled.\n *\n * Pair with `createTestDatabaseGlobalSetup({ isolation })` from\n * `@stratal/testing/database` in your Vitest `globalSetup`.\n */\n isolation?: DatabaseIsolation\n /**\n * Name of the Hyperdrive binding to isolate per test file. Defaults to `'DB'`.\n * Constrained to Hyperdrive binding names declared on `Cloudflare.Env` /\n * `StratalEnv`.\n */\n binding?: HyperdriveBindingName\n}\n\ntype WorkersPoolOptions = Exclude<CloudflareTestOptions, (...args: never[]) => unknown>\ntype StratalTestOptions = WorkersPoolOptions & { database?: StratalTestDatabaseOptions }\n\nconst pgCjsResolvers = new Map<string, () => string>([\n ['pg-protocol', () => require.resolve('pg-protocol')],\n ['pg-connection-string', () => require.resolve('pg-connection-string')],\n ['pg-pool', () => require.resolve('pg-pool')],\n ['pg-cloudflare', () => path.join(path.dirname(require.resolve('pg-cloudflare')), 'index.js')],\n])\n\n/**\n * Returns a Vite plugin that forces CJS resolution for `pg` sub-dependencies.\n *\n * `pg` is CJS but its dependencies (`pg-protocol`, `pg-connection-string`, `pg-pool`) ship\n * dual CJS/ESM exports. In workerd, the module fallback resolver prefers the ESM condition,\n * causing `SyntaxError: Cannot use import statement outside a module` when CJS `pg` does\n * `require()`. Additionally, `pg-cloudflare` uses a `workerd` export condition that the\n * root Vite instance doesn't resolve.\n *\n * Must be used at the **root** `defineConfig` level so that the\n * `@cloudflare/vitest-pool-workers` module fallback resolver (which uses the root Vite\n * instance) resolves pg sub-deps correctly.\n *\n * @example\n * ```ts\n * import { fixPgCjs, stratalTest } from '@stratal/testing/vitest-plugin'\n * import { defineConfig } from 'vitest/config'\n *\n * export default defineConfig({\n * plugins: [fixPgCjs()],\n * test: {\n * projects: [{\n * plugins: [stratalTest({ wrangler: { configPath: './wrangler.jsonc' } })],\n * test: { name: 'e2e', include: ['test/e2e/**\\/*.spec.ts'] },\n * }],\n * },\n * })\n * ```\n */\nexport const fixPgCjs = (): Plugin => ({\n name: 'stratal-pg-cjs',\n enforce: 'pre',\n resolveId(id) {\n const resolver = pgCjsResolvers.get(id)\n if (!resolver) return\n try {\n return resolver()\n } catch {\n return\n }\n },\n})\n\n/**\n * Returns a Vite plugin that forces CJS resolution for `@noble/hashes` subpaths\n * used by `@paralleldrive/cuid2@2.x` (the version `@zenstackhq/orm` depends on).\n *\n * cuid2@2.x is CJS and does `require(\"@noble/hashes/sha3\")` without the `.js`\n * extension. In a workspace that also installs `@noble/hashes@2.x` (ESM-only),\n * the hoisted v2 package has no extensionless `./sha3` entry in its exports\n * map, so Vite/workerd resolution fails. This plugin routes the extensionless\n * subpaths through the consumer's nested `@noble/hashes@1.x` (a sibling of\n * cuid2 under `@zenstackhq/orm/node_modules`), which ships proper CJS exports.\n *\n * If the consumer doesn't depend on `@zenstackhq/orm`, the plugin is a no-op.\n * Otherwise it throws loudly at config-resolution time if the resolution chain\n * is unexpectedly broken — surfacing dependency drift instead of letting the\n * symptom resurface as an opaque test failure.\n *\n * Must be used at the **root** `defineConfig` level (same constraint as\n * `fixPgCjs`).\n *\n * @example\n * ```ts\n * import { fixNobleHashesCjs, fixPgCjs, stratalTest } from '@stratal/testing/vitest-plugin'\n *\n * export default defineConfig({\n * plugins: [fixPgCjs(), fixNobleHashesCjs()],\n * // ...\n * })\n * ```\n */\nexport const fixNobleHashesCjs = (): Plugin => {\n const ids = ['@noble/hashes/sha3', '@noble/hashes/crypto']\n let resolved: Map<string, string> | null = null\n\n return {\n name: 'stratal-noble-hashes-cjs',\n enforce: 'pre',\n configResolved(config) {\n const consumerRequire = createRequire(path.join(config.root, 'noop.js'))\n let zenstackPath: string\n try {\n zenstackPath = consumerRequire.resolve('@zenstackhq/orm')\n } catch {\n // Consumer doesn't use ZenStack — nothing to fix.\n return\n }\n const cuid2Path = createRequire(zenstackPath).resolve('@paralleldrive/cuid2')\n const cuid2Require = createRequire(cuid2Path)\n resolved = new Map<string, string>(\n ids.map((id) => [id, cuid2Require.resolve(id)]),\n )\n },\n resolveId(id) {\n return resolved?.get(id)\n },\n }\n}\n\nconst createStratalPlugin = (isolation: DatabaseIsolation): Plugin => ({\n name: 'stratal-test',\n config() {\n const config: UserConfig & { test?: TestUserConfig } = {\n resolve: {\n alias: {\n tslib: 'tslib/tslib.es6.mjs',\n '@zenstackhq/language/ast': '@stratal/testing/mocks/zenstack-language',\n '@zenstackhq/language/utils': '@stratal/testing/mocks/zenstack-language',\n '@zenstackhq/language': '@stratal/testing/mocks/zenstack-language',\n },\n },\n ssr: {\n noExternal: ['@zenstackhq/better-auth'],\n },\n }\n\n // In 'database' mode each test file owns its database, so enable file\n // parallelism + isolation. In 'shared' mode leave these untouched so the\n // project's own defaults stand (forcing them would alter maxWorkers and\n // can collide with sibling projects' sequence.groupOrder).\n if (isolation === 'database') {\n config.test = { fileParallelism: true, isolate: true }\n }\n\n return config\n },\n})\n\n/**\n * Returns Vite plugins for Stratal tests running in the Cloudflare Workers (workerd) environment.\n *\n * Includes the cloudflare pool plugin and Stratal alias plugin. Pass\n * `database: { isolation: 'database' }` to give each test file its own\n * database (cloned from a migrated template, dropped on teardown) and enable\n * file parallelism. Use inside a project-level `plugins` array.\n *\n * **Note:** `fixPgCjs()` must be registered separately at the root `defineConfig` level.\n *\n * @param options - `cloudflareTest()` options plus Stratal `database` options\n * @returns An array of Vite plugins\n */\nexport function stratalTest(options: StratalTestOptions = {}): Plugin[] {\n const { database, ...cfOptions } = options\n const isolation = normalizeIsolation(database?.isolation)\n const binding = database?.binding ?? DEFAULT_DB_BINDING\n\n // Expose the mode + binding name to the worker as env vars so\n // TestingModule.compile() can decide whether and what to provision.\n const merged = {\n ...cfOptions,\n miniflare: {\n ...cfOptions.miniflare,\n bindings: {\n ...(cfOptions.miniflare?.bindings as Record<string, unknown> | undefined),\n [ISOLATION_ENV_VAR]: isolation,\n [BINDING_ENV_VAR]: binding,\n },\n },\n }\n\n return [cloudflareTest(merged) as unknown as Plugin, createStratalPlugin(isolation)]\n}\n"],"mappings":";;;;;AASA,MAAM,UAAU,cAAc,OAAO,KAAK,GAAG;AAyC7C,MAAM,iBAAiB,IAAI,IAA0B;CACnD,CAAC,qBAAqB,QAAQ,QAAQ,aAAa,CAAC;CACpD,CAAC,8BAA8B,QAAQ,QAAQ,sBAAsB,CAAC;CACtE,CAAC,iBAAiB,QAAQ,QAAQ,SAAS,CAAC;CAC5C,CAAC,uBAAuB,KAAK,KAAK,KAAK,QAAQ,QAAQ,QAAQ,eAAe,CAAC,GAAG,UAAU,CAAC;AAC/F,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BD,MAAa,kBAA0B;CACrC,MAAM;CACN,SAAS;CACT,UAAU,IAAI;EACZ,MAAM,WAAW,eAAe,IAAI,EAAE;EACtC,IAAI,CAAC,UAAU;EACf,IAAI;GACF,OAAO,SAAS;EAClB,QAAQ;GACN;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,0BAAkC;CAC7C,MAAM,MAAM,CAAC,sBAAsB,sBAAsB;CACzD,IAAI,WAAuC;CAE3C,OAAO;EACL,MAAM;EACN,SAAS;EACT,eAAe,QAAQ;GACrB,MAAM,kBAAkB,cAAc,KAAK,KAAK,OAAO,MAAM,SAAS,CAAC;GACvE,IAAI;GACJ,IAAI;IACF,eAAe,gBAAgB,QAAQ,iBAAiB;GAC1D,QAAQ;IAEN;GACF;GAEA,MAAM,eAAe,cADH,cAAc,YAAY,EAAE,QAAQ,sBACX,CAAC;GAC5C,WAAW,IAAI,IACb,IAAI,KAAK,OAAO,CAAC,IAAI,aAAa,QAAQ,EAAE,CAAC,CAAC,CAChD;EACF;EACA,UAAU,IAAI;GACZ,OAAO,UAAU,IAAI,EAAE;EACzB;CACF;AACF;AAEA,MAAM,uBAAuB,eAA0C;CACrE,MAAM;CACN,SAAS;EACP,MAAM,SAAiD;GACrD,SAAS,EACP,OAAO;IACL,OAAO;IACP,4BAA4B;IAC5B,8BAA8B;IAC9B,wBAAwB;GAC1B,EACF;GACA,KAAK,EACH,YAAY,CAAC,yBAAyB,EACxC;EACF;EAMA,IAAI,cAAc,YAChB,OAAO,OAAO;GAAE,iBAAiB;GAAM,SAAS;EAAK;EAGvD,OAAO;CACT;AACF;;;;;;;;;;;;;;AAeA,SAAgB,YAAY,UAA8B,CAAC,GAAa;CACtE,MAAM,EAAE,UAAU,GAAG,cAAc;CACnC,MAAM,YAAY,mBAAmB,UAAU,SAAS;CACxD,MAAM,UAAU,UAAU,WAAA;CAgB1B,OAAO,CAAC,eAAe;EAXrB,GAAG;EACH,WAAW;GACT,GAAG,UAAU;GACb,UAAU;IACR,GAAI,UAAU,WAAW;KACxB,oBAAoB;KACpB,kBAAkB;GACrB;EACF;CAG0B,CAAC,GAAwB,oBAAoB,SAAS,CAAC;AACrF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratal/testing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Testing utilities and mocks for Stratal framework applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,14 +37,18 @@
|
|
|
37
37
|
"types": "./dist/index.d.mts",
|
|
38
38
|
"import": "./dist/index.mjs"
|
|
39
39
|
},
|
|
40
|
+
"./database": {
|
|
41
|
+
"types": "./dist/database/index.d.mts",
|
|
42
|
+
"import": "./dist/database/index.mjs"
|
|
43
|
+
},
|
|
44
|
+
"./feature-flags": {
|
|
45
|
+
"types": "./dist/feature-flags/index.d.mts",
|
|
46
|
+
"import": "./dist/feature-flags/index.mjs"
|
|
47
|
+
},
|
|
40
48
|
"./mocks": {
|
|
41
49
|
"types": "./dist/mocks/index.d.mts",
|
|
42
50
|
"import": "./dist/mocks/index.mjs"
|
|
43
51
|
},
|
|
44
|
-
"./mocks/nodemailer": {
|
|
45
|
-
"types": "./dist/mocks/nodemailer.d.mts",
|
|
46
|
-
"import": "./dist/mocks/nodemailer.mjs"
|
|
47
|
-
},
|
|
48
52
|
"./mocks/zenstack-language": {
|
|
49
53
|
"types": "./dist/mocks/zenstack-language.d.mts",
|
|
50
54
|
"import": "./dist/mocks/zenstack-language.mjs"
|
|
@@ -66,15 +70,15 @@
|
|
|
66
70
|
"lint:fix": "npx oxlint --fix ."
|
|
67
71
|
},
|
|
68
72
|
"dependencies": {
|
|
69
|
-
"@cloudflare/vitest-pool-workers": "^0.16.
|
|
73
|
+
"@cloudflare/vitest-pool-workers": "^0.16.12",
|
|
70
74
|
"@golevelup/ts-vitest": "^4.0.0",
|
|
71
|
-
"msw": "^2.14.
|
|
75
|
+
"msw": "^2.14.6"
|
|
72
76
|
},
|
|
73
77
|
"peerDependencies": {
|
|
74
|
-
"@stratal/framework": ">=0.0.
|
|
78
|
+
"@stratal/framework": ">=0.0.23",
|
|
75
79
|
"better-auth": ">=1.4",
|
|
76
|
-
"
|
|
77
|
-
"stratal": ">=0.0.
|
|
80
|
+
"pg": "^8.0.0",
|
|
81
|
+
"stratal": ">=0.0.23",
|
|
78
82
|
"vitest": "^4.1.0"
|
|
79
83
|
},
|
|
80
84
|
"peerDependenciesMeta": {
|
|
@@ -83,19 +87,23 @@
|
|
|
83
87
|
},
|
|
84
88
|
"better-auth": {
|
|
85
89
|
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"pg": {
|
|
92
|
+
"optional": true
|
|
86
93
|
}
|
|
87
94
|
},
|
|
88
95
|
"devDependencies": {
|
|
89
|
-
"@cloudflare/workers-types": "4.
|
|
96
|
+
"@cloudflare/workers-types": "4.20260603.1",
|
|
90
97
|
"@stratal/framework": "workspace:*",
|
|
91
|
-
"@types/node": "^25.
|
|
92
|
-
"@
|
|
93
|
-
"@vitest/
|
|
94
|
-
"
|
|
95
|
-
"
|
|
98
|
+
"@types/node": "^25.9.1",
|
|
99
|
+
"@types/pg": "^8.20.0",
|
|
100
|
+
"@vitest/runner": "~4.1.8",
|
|
101
|
+
"@vitest/snapshot": "~4.1.8",
|
|
102
|
+
"better-auth": "^1.6.14",
|
|
103
|
+
"pg": "^8.21.0",
|
|
96
104
|
"stratal": "workspace:*",
|
|
97
|
-
"tsdown": "^0.22.
|
|
105
|
+
"tsdown": "^0.22.1",
|
|
98
106
|
"typescript": "^6.0.3",
|
|
99
|
-
"vitest": "~4.1.
|
|
107
|
+
"vitest": "~4.1.8"
|
|
100
108
|
}
|
|
101
109
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-D-Q2cR2v.d.mts","names":[],"sources":["../src/storage/fake-storage.service.ts"],"mappings":";;;;;AAkBA;UAAiB,UAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA;EACA,IAAA;EACA,QAAA,GAAW,MAAA;EACX,UAAA,EAAY,IAAA;AAAA;;;;;;;;;;;AAoBd;;;;;;;cACa,kBAAA,SAA2B,cAAA;EAAA,mBAKjB,cAAA,EAAgB,qBAAA;EAAA,mBAEhB,OAAA,EAAS,aAAA;EAAA,QANtB,KAAA;cAIa,cAAA,EAAgB,qBAAA,EAEhB,OAAA,EAAS,aAAA;EAsCN;;;EA9BlB,MAAA,CACJ,IAAA,EAAM,8BAAA,EACN,YAAA,UACA,OAAA,EAAS,aAAA,EACT,IAAA,YACC,OAAA,CAAQ,YAAA;EAoER;;;EA3CH,QAAA,CAAS,IAAA,WAAe,OAAA,CAAQ,cAAA;EA+D7B;;;EAtCH,MAAA,CAAO,IAAA,WAAe,OAAA;EAkDX;;;EA1CX,MAAA,CAAO,IAAA,WAAe,OAAA;EAyHC;;;EAlHvB,uBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EAxF2B;;;EA+FtC,qBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EA3FmB;;;EAkG9B,qBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EAvGU;;;EA8Gf,aAAA,CACJ,IAAA,EAAM,8BAAA,EACN,IAAA,UACA,OAAA,EAAS,IAAA,CAAK,aAAA;IAA2B,IAAA;EAAA,GACzC,IAAA,YACC,OAAA,CAAQ,YAAA;EAvGT;;;;;;EAwHF,YAAA,CAAa,IAAA;EA5FJ;;;;;;EAyGT,aAAA,CAAc,IAAA;EAxEP;;;;;EAoFP,WAAA,CAAA;EA1EW;;;;;;EAuFX,WAAA,CAAY,KAAA;EArEV;;;EA+EF,cAAA,CAAA,GAAkB,GAAA,SAAY,UAAA;EAtExB;;;EA6EN,cAAA,CAAA;EA1EW;;;EAiFX,OAAA,CAAQ,IAAA,WAAe,UAAA;EAhFrB;;;EAuFF,KAAA,CAAA;EAAA,QAQQ,kBAAA;EAAA,QAeM,gBAAA;AAAA"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
//#region src/mocks/nodemailer.d.ts
|
|
2
|
-
declare const _default: {
|
|
3
|
-
createTransport: () => {
|
|
4
|
-
sendMail: () => Promise<{}>;
|
|
5
|
-
};
|
|
6
|
-
};
|
|
7
|
-
declare const createTransport: () => {
|
|
8
|
-
sendMail: () => Promise<{}>;
|
|
9
|
-
};
|
|
10
|
-
//#endregion
|
|
11
|
-
export { createTransport, _default as default };
|
|
12
|
-
//# sourceMappingURL=nodemailer.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nodemailer.d.mts","names":[],"sources":["../../src/mocks/nodemailer.ts"],"mappings":";;;;;;cAMa,eAAA;kBAEX,OAAA;AAAA"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
//#region src/mocks/nodemailer.ts
|
|
2
|
-
var nodemailer_default = { createTransport: () => ({ sendMail: () => Promise.resolve({}) }) };
|
|
3
|
-
const createTransport = () => ({ sendMail: () => Promise.resolve({}) });
|
|
4
|
-
//#endregion
|
|
5
|
-
export { createTransport, nodemailer_default as default };
|
|
6
|
-
|
|
7
|
-
//# sourceMappingURL=nodemailer.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nodemailer.mjs","names":[],"sources":["../../src/mocks/nodemailer.ts"],"sourcesContent":["export default {\n createTransport: () => ({\n sendMail: () => Promise.resolve({}),\n }),\n}\n\nexport const createTransport = () => ({\n sendMail: () => Promise.resolve({}),\n})\n"],"mappings":";AAAA,IAAA,qBAAe,EACb,wBAAwB,EACtB,gBAAgB,QAAQ,QAAQ,EAAE,CAAC,EACpC,GACF;AAED,MAAa,yBAAyB,EACpC,gBAAgB,QAAQ,QAAQ,EAAE,CAAC,EACpC"}
|