@zenstackhq/testtools 3.0.0-beta.9 → 3.0.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/dist/index.d.cts CHANGED
@@ -1,41 +1,89 @@
1
- import { ClientOptions, ClientContract } from '@zenstackhq/runtime';
2
- import { SchemaDef } from '@zenstackhq/runtime/schema';
1
+ import { ClientOptions, ClientContract } from '@zenstackhq/orm';
2
+ import { SchemaDef } from '@zenstackhq/orm/schema';
3
3
  import { LogEvent } from 'kysely';
4
4
  import * as _zenstackhq_language_ast from '@zenstackhq/language/ast';
5
- import { SchemaDef as SchemaDef$1 } from '@zenstackhq/sdk/schema';
5
+ import { SchemaDef as SchemaDef$1 } from '@zenstackhq/schema';
6
6
 
7
7
  declare function getTestDbProvider(): "sqlite" | "postgresql";
8
- type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> & {
8
+ declare const TEST_PG_CONFIG: {
9
+ host: string;
10
+ port: number;
11
+ user: string;
12
+ password: string;
13
+ };
14
+ declare const TEST_PG_URL: string;
15
+ type ExtraTestClientOptions = {
16
+ /**
17
+ * Database provider
18
+ */
9
19
  provider?: 'sqlite' | 'postgresql';
20
+ /**
21
+ * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.
22
+ */
23
+ schemaFile?: string;
24
+ /**
25
+ * Database name. If not provided, a name will be generated based on the test name.
26
+ */
10
27
  dbName?: string;
28
+ /**
29
+ * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.
30
+ */
11
31
  usePrismaPush?: boolean;
32
+ /**
33
+ * Extra source files to create and compile.
34
+ */
12
35
  extraSourceFiles?: Record<string, string>;
36
+ /**
37
+ * Working directory for the test client. If not provided, a temporary directory will be created.
38
+ */
13
39
  workDir?: string;
40
+ /**
41
+ * Debug mode.
42
+ */
14
43
  debug?: boolean;
44
+ /**
45
+ * A sqlite database file to be used for the test. Only supported for sqlite provider.
46
+ */
47
+ dbFile?: string;
48
+ /**
49
+ * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.
50
+ */
51
+ dataSourceExtensions?: string[];
52
+ /**
53
+ * Additional files to be copied to the working directory. The glob pattern is relative to the test file.
54
+ */
55
+ copyFiles?: {
56
+ globPattern: string;
57
+ destination: string;
58
+ }[];
15
59
  };
16
- declare function createTestClient<Schema extends SchemaDef>(schema: Schema, options?: CreateTestClientOptions<Schema>, schemaFile?: string): Promise<ClientContract<Schema>>;
17
- declare function createTestClient<Schema extends SchemaDef>(schema: string, options?: CreateTestClientOptions<Schema>): Promise<any>;
60
+ type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> & ExtraTestClientOptions;
61
+ declare function createTestClient<Schema extends SchemaDef, Options extends ClientOptions<Schema>, CreateOptions = Omit<Options, 'dialect'>>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;
62
+ declare function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;
18
63
  declare function createPolicyTestClient<Schema extends SchemaDef>(schema: Schema, options?: CreateTestClientOptions<Schema>): Promise<ClientContract<Schema>>;
19
64
  declare function createPolicyTestClient<Schema extends SchemaDef>(schema: string, options?: CreateTestClientOptions<Schema>): Promise<any>;
20
65
  declare function testLogger(e: LogEvent): void;
21
66
 
22
67
  declare function createTestProject(zmodelContent?: string): string;
23
68
 
24
- declare function generateTsSchema(schemaText: string, provider?: 'sqlite' | 'postgresql', dbUrl?: string, extraSourceFiles?: Record<string, string>): Promise<{
69
+ declare function generateTsSchema(schemaText: string, provider?: 'sqlite' | 'postgresql', dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean): Promise<{
25
70
  model: _zenstackhq_language_ast.Model;
26
71
  workDir: string;
27
72
  schema: SchemaDef$1;
73
+ schemaLite: SchemaDef$1 | undefined;
28
74
  }>;
29
75
  declare function generateTsSchemaFromFile(filePath: string): Promise<{
30
76
  model: _zenstackhq_language_ast.Model;
31
77
  workDir: string;
32
78
  schema: SchemaDef$1;
79
+ schemaLite: SchemaDef$1 | undefined;
33
80
  }>;
34
81
  declare function generateTsSchemaInPlace(schemaPath: string): Promise<{
35
82
  workDir: string;
36
83
  schema: SchemaDef$1;
84
+ schemaLite: SchemaDef$1 | undefined;
37
85
  }>;
38
86
  declare function loadSchema(schema: string, additionalSchemas?: Record<string, string>): Promise<_zenstackhq_language_ast.Model>;
39
87
  declare function loadSchemaWithError(schema: string, error: string | RegExp): Promise<void>;
40
88
 
41
- export { type CreateTestClientOptions, createPolicyTestClient, createTestClient, createTestProject, generateTsSchema, generateTsSchemaFromFile, generateTsSchemaInPlace, getTestDbProvider, loadSchema, loadSchemaWithError, testLogger };
89
+ export { type CreateTestClientOptions, TEST_PG_CONFIG, TEST_PG_URL, createPolicyTestClient, createTestClient, createTestProject, generateTsSchema, generateTsSchemaFromFile, generateTsSchemaInPlace, getTestDbProvider, loadSchema, loadSchemaWithError, testLogger };
package/dist/index.d.ts CHANGED
@@ -1,41 +1,89 @@
1
- import { ClientOptions, ClientContract } from '@zenstackhq/runtime';
2
- import { SchemaDef } from '@zenstackhq/runtime/schema';
1
+ import { ClientOptions, ClientContract } from '@zenstackhq/orm';
2
+ import { SchemaDef } from '@zenstackhq/orm/schema';
3
3
  import { LogEvent } from 'kysely';
4
4
  import * as _zenstackhq_language_ast from '@zenstackhq/language/ast';
5
- import { SchemaDef as SchemaDef$1 } from '@zenstackhq/sdk/schema';
5
+ import { SchemaDef as SchemaDef$1 } from '@zenstackhq/schema';
6
6
 
7
7
  declare function getTestDbProvider(): "sqlite" | "postgresql";
8
- type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> & {
8
+ declare const TEST_PG_CONFIG: {
9
+ host: string;
10
+ port: number;
11
+ user: string;
12
+ password: string;
13
+ };
14
+ declare const TEST_PG_URL: string;
15
+ type ExtraTestClientOptions = {
16
+ /**
17
+ * Database provider
18
+ */
9
19
  provider?: 'sqlite' | 'postgresql';
20
+ /**
21
+ * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.
22
+ */
23
+ schemaFile?: string;
24
+ /**
25
+ * Database name. If not provided, a name will be generated based on the test name.
26
+ */
10
27
  dbName?: string;
28
+ /**
29
+ * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.
30
+ */
11
31
  usePrismaPush?: boolean;
32
+ /**
33
+ * Extra source files to create and compile.
34
+ */
12
35
  extraSourceFiles?: Record<string, string>;
36
+ /**
37
+ * Working directory for the test client. If not provided, a temporary directory will be created.
38
+ */
13
39
  workDir?: string;
40
+ /**
41
+ * Debug mode.
42
+ */
14
43
  debug?: boolean;
44
+ /**
45
+ * A sqlite database file to be used for the test. Only supported for sqlite provider.
46
+ */
47
+ dbFile?: string;
48
+ /**
49
+ * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.
50
+ */
51
+ dataSourceExtensions?: string[];
52
+ /**
53
+ * Additional files to be copied to the working directory. The glob pattern is relative to the test file.
54
+ */
55
+ copyFiles?: {
56
+ globPattern: string;
57
+ destination: string;
58
+ }[];
15
59
  };
16
- declare function createTestClient<Schema extends SchemaDef>(schema: Schema, options?: CreateTestClientOptions<Schema>, schemaFile?: string): Promise<ClientContract<Schema>>;
17
- declare function createTestClient<Schema extends SchemaDef>(schema: string, options?: CreateTestClientOptions<Schema>): Promise<any>;
60
+ type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> & ExtraTestClientOptions;
61
+ declare function createTestClient<Schema extends SchemaDef, Options extends ClientOptions<Schema>, CreateOptions = Omit<Options, 'dialect'>>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;
62
+ declare function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;
18
63
  declare function createPolicyTestClient<Schema extends SchemaDef>(schema: Schema, options?: CreateTestClientOptions<Schema>): Promise<ClientContract<Schema>>;
19
64
  declare function createPolicyTestClient<Schema extends SchemaDef>(schema: string, options?: CreateTestClientOptions<Schema>): Promise<any>;
20
65
  declare function testLogger(e: LogEvent): void;
21
66
 
22
67
  declare function createTestProject(zmodelContent?: string): string;
23
68
 
24
- declare function generateTsSchema(schemaText: string, provider?: 'sqlite' | 'postgresql', dbUrl?: string, extraSourceFiles?: Record<string, string>): Promise<{
69
+ declare function generateTsSchema(schemaText: string, provider?: 'sqlite' | 'postgresql', dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean): Promise<{
25
70
  model: _zenstackhq_language_ast.Model;
26
71
  workDir: string;
27
72
  schema: SchemaDef$1;
73
+ schemaLite: SchemaDef$1 | undefined;
28
74
  }>;
29
75
  declare function generateTsSchemaFromFile(filePath: string): Promise<{
30
76
  model: _zenstackhq_language_ast.Model;
31
77
  workDir: string;
32
78
  schema: SchemaDef$1;
79
+ schemaLite: SchemaDef$1 | undefined;
33
80
  }>;
34
81
  declare function generateTsSchemaInPlace(schemaPath: string): Promise<{
35
82
  workDir: string;
36
83
  schema: SchemaDef$1;
84
+ schemaLite: SchemaDef$1 | undefined;
37
85
  }>;
38
86
  declare function loadSchema(schema: string, additionalSchemas?: Record<string, string>): Promise<_zenstackhq_language_ast.Model>;
39
87
  declare function loadSchemaWithError(schema: string, error: string | RegExp): Promise<void>;
40
88
 
41
- export { type CreateTestClientOptions, createPolicyTestClient, createTestClient, createTestProject, generateTsSchema, generateTsSchemaFromFile, generateTsSchemaInPlace, getTestDbProvider, loadSchema, loadSchemaWithError, testLogger };
89
+ export { type CreateTestClientOptions, TEST_PG_CONFIG, TEST_PG_URL, createPolicyTestClient, createTestClient, createTestProject, generateTsSchema, generateTsSchemaFromFile, generateTsSchemaInPlace, getTestDbProvider, loadSchema, loadSchemaWithError, testLogger };
package/dist/index.js CHANGED
@@ -1,13 +1,19 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
3
9
 
4
10
  // src/client.ts
5
11
  import { invariant as invariant2 } from "@zenstackhq/common-helpers";
6
- import { loadDocument as loadDocument2 } from "@zenstackhq/language";
12
+ import { ZenStackClient } from "@zenstackhq/orm";
7
13
  import { PolicyPlugin } from "@zenstackhq/plugin-policy";
8
- import { ZenStackClient } from "@zenstackhq/runtime";
9
14
  import { PrismaSchemaGenerator } from "@zenstackhq/sdk";
10
15
  import SQLite from "better-sqlite3";
16
+ import { glob } from "glob";
11
17
  import { PostgresDialect, SqliteDialect } from "kysely";
12
18
  import { execSync as execSync2 } from "child_process";
13
19
  import { createHash } from "crypto";
@@ -35,7 +41,7 @@ function createTestProject(zmodelContent) {
35
41
  const zenstackPackages = [
36
42
  "language",
37
43
  "sdk",
38
- "runtime",
44
+ "orm",
39
45
  "cli"
40
46
  ];
41
47
  fs.mkdirSync(path.join(workDir, "node_modules/@zenstackhq"));
@@ -69,7 +75,6 @@ __name(createTestProject, "createTestProject");
69
75
 
70
76
  // src/schema.ts
71
77
  import { invariant } from "@zenstackhq/common-helpers";
72
- import { loadDocument } from "@zenstackhq/language";
73
78
  import { TsSchemaGenerator } from "@zenstackhq/sdk";
74
79
  import { execSync } from "child_process";
75
80
  import crypto from "crypto";
@@ -78,6 +83,18 @@ import os from "os";
78
83
  import path2 from "path";
79
84
  import { match } from "ts-pattern";
80
85
  import { expect } from "vitest";
86
+
87
+ // src/utils.ts
88
+ import { loadDocument } from "@zenstackhq/language";
89
+ function loadDocumentWithPlugins(filePath) {
90
+ const pluginModelFiles = [
91
+ __require.resolve("@zenstackhq/plugin-policy/plugin.zmodel")
92
+ ];
93
+ return loadDocument(filePath, pluginModelFiles);
94
+ }
95
+ __name(loadDocumentWithPlugins, "loadDocumentWithPlugins");
96
+
97
+ // src/schema.ts
81
98
  function makePrelude(provider, dbUrl) {
82
99
  return match(provider).with("sqlite", () => {
83
100
  return `
@@ -96,19 +113,27 @@ datasource db {
96
113
  }).exhaustive();
97
114
  }
98
115
  __name(makePrelude, "makePrelude");
99
- async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles) {
116
+ function replacePlaceholders(schemaText, provider, dbUrl) {
117
+ const url = dbUrl ?? (provider === "sqlite" ? "file:./test.db" : "postgres://postgres:postgres@localhost:5432/db");
118
+ return schemaText.replace(/\$DB_URL/g, url).replace(/\$PROVIDER/g, provider);
119
+ }
120
+ __name(replacePlaceholders, "replacePlaceholders");
121
+ async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema) {
100
122
  const workDir = createTestProject();
101
123
  const zmodelPath = path2.join(workDir, "schema.zmodel");
102
124
  const noPrelude = schemaText.includes("datasource ");
103
125
  fs2.writeFileSync(zmodelPath, `${noPrelude ? "" : makePrelude(provider, dbUrl)}
104
126
 
105
- ${schemaText}`);
106
- const result = await loadDocument(zmodelPath);
127
+ ${replacePlaceholders(schemaText, provider, dbUrl)}`);
128
+ const result = await loadDocumentWithPlugins(zmodelPath);
107
129
  if (!result.success) {
108
130
  throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);
109
131
  }
110
132
  const generator = new TsSchemaGenerator();
111
- await generator.generate(result.model, workDir);
133
+ await generator.generate(result.model, {
134
+ outDir: workDir,
135
+ lite: withLiteSchema
136
+ });
112
137
  if (extraSourceFiles) {
113
138
  for (const [fileName, content] of Object.entries(extraSourceFiles)) {
114
139
  const filePath = path2.resolve(workDir, !fileName.endsWith(".ts") ? `${fileName}.ts` : fileName);
@@ -130,9 +155,15 @@ async function compileAndLoad(workDir) {
130
155
  stdio: "inherit"
131
156
  });
132
157
  const module = await import(path2.join(workDir, "schema.js"));
158
+ let moduleLite;
159
+ try {
160
+ moduleLite = await import(path2.join(workDir, "schema-lite.js"));
161
+ } catch {
162
+ }
133
163
  return {
134
164
  workDir,
135
- schema: module.schema
165
+ schema: module.schema,
166
+ schemaLite: moduleLite?.schema
136
167
  };
137
168
  }
138
169
  __name(compileAndLoad, "compileAndLoad");
@@ -143,12 +174,14 @@ function generateTsSchemaFromFile(filePath) {
143
174
  __name(generateTsSchemaFromFile, "generateTsSchemaFromFile");
144
175
  async function generateTsSchemaInPlace(schemaPath) {
145
176
  const workDir = path2.dirname(schemaPath);
146
- const result = await loadDocument(schemaPath);
177
+ const result = await loadDocumentWithPlugins(schemaPath);
147
178
  if (!result.success) {
148
179
  throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);
149
180
  }
150
181
  const generator = new TsSchemaGenerator();
151
- await generator.generate(result.model, workDir);
182
+ await generator.generate(result.model, {
183
+ outDir: workDir
184
+ });
152
185
  return compileAndLoad(workDir);
153
186
  }
154
187
  __name(generateTsSchemaInPlace, "generateTsSchemaInPlace");
@@ -171,7 +204,7 @@ ${schema}`;
171
204
  fs2.writeFileSync(filePath, content);
172
205
  }
173
206
  }
174
- const r = await loadDocument(tempFile);
207
+ const r = await loadDocumentWithPlugins(tempFile);
175
208
  expect(r).toSatisfy((r2) => r2.success, `Failed to load schema: ${r.errors?.map((e) => e.toString()).join(", ")}`);
176
209
  invariant(r.success);
177
210
  return r.model;
@@ -185,7 +218,7 @@ ${schema}`;
185
218
  }
186
219
  const tempFile = path2.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);
187
220
  fs2.writeFileSync(tempFile, schema);
188
- const r = await loadDocument(tempFile);
221
+ const r = await loadDocumentWithPlugins(tempFile);
189
222
  expect(r.success).toBe(false);
190
223
  invariant(!r.success);
191
224
  if (typeof error === "string") {
@@ -214,20 +247,22 @@ var TEST_PG_CONFIG = {
214
247
  user: process.env["TEST_PG_USER"] ?? "postgres",
215
248
  password: process.env["TEST_PG_PASSWORD"] ?? "postgres"
216
249
  };
217
- async function createTestClient(schema, options, schemaFile) {
250
+ var TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;
251
+ async function createTestClient(schema, options) {
218
252
  let workDir = options?.workDir;
219
253
  let _schema;
220
254
  const provider = options?.provider ?? getTestDbProvider() ?? "sqlite";
221
255
  const dbName = options?.dbName ?? getTestDbName(provider);
222
- const dbUrl = provider === "sqlite" ? `file:${dbName}` : `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}/${dbName}`;
256
+ const dbUrl = provider === "sqlite" ? `file:${dbName}` : `${TEST_PG_URL}/${dbName}`;
223
257
  let model;
224
258
  if (typeof schema === "string") {
225
- const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles);
259
+ const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0);
226
260
  workDir = generated.workDir;
227
261
  model = generated.model;
228
262
  _schema = {
229
263
  ...generated.schema,
230
264
  provider: {
265
+ ...generated.schema.provider,
231
266
  type: provider
232
267
  }
233
268
  };
@@ -239,49 +274,80 @@ async function createTestClient(schema, options, schemaFile) {
239
274
  }
240
275
  };
241
276
  workDir ??= createTestProject();
242
- if (schemaFile) {
243
- let schemaContent = fs3.readFileSync(schemaFile, "utf-8");
277
+ if (options?.schemaFile) {
278
+ let schemaContent = fs3.readFileSync(options.schemaFile, "utf-8");
244
279
  if (dbUrl) {
245
280
  schemaContent = schemaContent.replace(/datasource\s+db\s*{[^}]*}/m, `datasource db {
246
281
  provider = '${provider}'
247
282
  url = '${dbUrl}'
283
+ ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(", ")}]` : ""}
248
284
  }`);
249
285
  }
250
286
  fs3.writeFileSync(path3.join(workDir, "schema.zmodel"), schemaContent);
251
287
  }
252
288
  }
253
289
  invariant2(workDir);
254
- if (options?.debug) {
255
- console.log(`Work directory: ${workDir}`);
256
- }
257
290
  const { plugins, ...rest } = options ?? {};
258
291
  const _options = {
259
292
  ...rest
260
293
  };
261
- if (options?.usePrismaPush) {
262
- invariant2(typeof schema === "string" || schemaFile, "a schema file must be provided when using prisma db push");
263
- if (!model) {
264
- const r = await loadDocument2(path3.join(workDir, "schema.zmodel"));
265
- if (!r.success) {
266
- throw new Error(r.errors.join("\n"));
294
+ if (options?.debug) {
295
+ console.log(`Work directory: ${workDir}`);
296
+ console.log(`Database name: ${dbName}`);
297
+ _options.log = testLogger;
298
+ }
299
+ if (options?.dbFile) {
300
+ if (provider !== "sqlite") {
301
+ throw new Error("dbFile option is only supported for sqlite provider");
302
+ }
303
+ fs3.copyFileSync(options.dbFile, path3.join(workDir, dbName));
304
+ }
305
+ if (options?.copyFiles) {
306
+ const state = expect2.getState();
307
+ const currentTestPath = state.testPath;
308
+ if (!currentTestPath) {
309
+ throw new Error("Unable to determine current test file path");
310
+ }
311
+ for (const { globPattern, destination } of options.copyFiles) {
312
+ const files = glob.sync(globPattern, {
313
+ cwd: path3.dirname(currentTestPath)
314
+ });
315
+ for (const file of files) {
316
+ const src = path3.resolve(path3.dirname(currentTestPath), file);
317
+ const dest = path3.resolve(workDir, destination, path3.basename(file));
318
+ fs3.mkdirSync(path3.dirname(dest), {
319
+ recursive: true
320
+ });
321
+ fs3.copyFileSync(src, dest);
267
322
  }
268
- model = r.model;
269
323
  }
270
- const prismaSchema = new PrismaSchemaGenerator(model);
271
- const prismaSchemaText = await prismaSchema.generate();
272
- fs3.writeFileSync(path3.resolve(workDir, "schema.prisma"), prismaSchemaText);
273
- execSync2("npx prisma db push --schema ./schema.prisma --skip-generate --force-reset", {
274
- cwd: workDir,
275
- stdio: "ignore"
276
- });
277
- } else {
278
- if (provider === "postgresql") {
279
- invariant2(dbName, "dbName is required");
280
- const pgClient = new PGClient(TEST_PG_CONFIG);
281
- await pgClient.connect();
282
- await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`);
283
- await pgClient.query(`CREATE DATABASE "${dbName}"`);
284
- await pgClient.end();
324
+ }
325
+ if (!options?.dbFile) {
326
+ if (options?.usePrismaPush) {
327
+ invariant2(typeof schema === "string" || options?.schemaFile, "a schema file must be provided when using prisma db push");
328
+ if (!model) {
329
+ const r = await loadDocumentWithPlugins(path3.join(workDir, "schema.zmodel"));
330
+ if (!r.success) {
331
+ throw new Error(r.errors.join("\n"));
332
+ }
333
+ model = r.model;
334
+ }
335
+ const prismaSchema = new PrismaSchemaGenerator(model);
336
+ const prismaSchemaText = await prismaSchema.generate();
337
+ fs3.writeFileSync(path3.resolve(workDir, "schema.prisma"), prismaSchemaText);
338
+ execSync2("npx prisma db push --schema ./schema.prisma --skip-generate --force-reset", {
339
+ cwd: workDir,
340
+ stdio: "ignore"
341
+ });
342
+ } else {
343
+ if (provider === "postgresql") {
344
+ invariant2(dbName, "dbName is required");
345
+ const pgClient = new PGClient(TEST_PG_CONFIG);
346
+ await pgClient.connect();
347
+ await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`);
348
+ await pgClient.query(`CREATE DATABASE "${dbName}"`);
349
+ await pgClient.end();
350
+ }
285
351
  }
286
352
  }
287
353
  if (provider === "postgresql") {
@@ -297,7 +363,7 @@ async function createTestClient(schema, options, schemaFile) {
297
363
  });
298
364
  }
299
365
  let client = new ZenStackClient(_schema, _options);
300
- if (!options?.usePrismaPush) {
366
+ if (!options?.usePrismaPush && !options?.dbFile) {
301
367
  await client.$pushSchema();
302
368
  }
303
369
  if (plugins) {
@@ -326,38 +392,37 @@ function getTestDbName(provider) {
326
392
  if (provider === "sqlite") {
327
393
  return "./test.db";
328
394
  }
329
- const testName = expect2.getState().currentTestName;
395
+ const testName = expect2.getState().currentTestName ?? "unnamed";
330
396
  const testPath = expect2.getState().testPath ?? "";
331
- invariant2(testName);
332
397
  const digest = createHash("md5").update(testName + testPath).digest("hex");
333
398
  return "test_" + testName.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").substring(0, 30) + digest.slice(0, 6);
334
399
  }
335
400
  __name(getTestDbName, "getTestDbName");
336
401
 
337
402
  // src/vitest-ext.ts
338
- import { InputValidationError, NotFoundError, RejectedByPolicyError } from "@zenstackhq/runtime";
403
+ import { ORMError, ORMErrorReason } from "@zenstackhq/orm";
339
404
  import { expect as expect3 } from "vitest";
340
405
  function isPromise(value) {
341
406
  return typeof value.then === "function" && typeof value.catch === "function";
342
407
  }
343
408
  __name(isPromise, "isPromise");
344
- function expectError(err, errorType) {
345
- if (err instanceof errorType) {
409
+ function expectErrorReason(err, errorReason) {
410
+ if (err instanceof ORMError && err.reason === errorReason) {
346
411
  return {
347
412
  message: /* @__PURE__ */ __name(() => "", "message"),
348
413
  pass: true
349
414
  };
350
415
  } else {
351
416
  return {
352
- message: /* @__PURE__ */ __name(() => `expected ${errorType}, got ${err}`, "message"),
417
+ message: /* @__PURE__ */ __name(() => `expected ORMError of reason ${errorReason}, got ${err}`, "message"),
353
418
  pass: false
354
419
  };
355
420
  }
356
421
  }
357
- __name(expectError, "expectError");
422
+ __name(expectErrorReason, "expectErrorReason");
358
423
  function expectErrorMessages(expectedMessages, message) {
359
424
  for (const m of expectedMessages) {
360
- if (!message.includes(m)) {
425
+ if (!message.toLowerCase().includes(m.toLowerCase())) {
361
426
  return {
362
427
  message: /* @__PURE__ */ __name(() => `expected message not found in error: ${m}, got message: ${message}`, "message"),
363
428
  pass: false
@@ -424,7 +489,7 @@ expect3.extend({
424
489
  try {
425
490
  await received;
426
491
  } catch (err) {
427
- return expectError(err, NotFoundError);
492
+ return expectErrorReason(err, ORMErrorReason.NOT_FOUND);
428
493
  }
429
494
  return {
430
495
  message: /* @__PURE__ */ __name(() => `expected NotFoundError, got no error`, "message"),
@@ -441,13 +506,13 @@ expect3.extend({
441
506
  try {
442
507
  await received;
443
508
  } catch (err) {
444
- if (expectedMessages && err instanceof RejectedByPolicyError) {
509
+ if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {
445
510
  const r = expectErrorMessages(expectedMessages, err.message || "");
446
511
  if (r) {
447
512
  return r;
448
513
  }
449
514
  }
450
- return expectError(err, RejectedByPolicyError);
515
+ return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);
451
516
  }
452
517
  return {
453
518
  message: /* @__PURE__ */ __name(() => `expected PolicyError, got no error`, "message"),
@@ -464,13 +529,13 @@ expect3.extend({
464
529
  try {
465
530
  await received;
466
531
  } catch (err) {
467
- if (expectedMessages && err instanceof InputValidationError) {
532
+ if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {
468
533
  const r = expectErrorMessages(expectedMessages, err.message || "");
469
534
  if (r) {
470
535
  return r;
471
536
  }
472
537
  }
473
- return expectError(err, InputValidationError);
538
+ return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);
474
539
  }
475
540
  return {
476
541
  message: /* @__PURE__ */ __name(() => `expected InputValidationError, got no error`, "message"),
@@ -479,6 +544,8 @@ expect3.extend({
479
544
  }
480
545
  });
481
546
  export {
547
+ TEST_PG_CONFIG,
548
+ TEST_PG_URL,
482
549
  createPolicyTestClient,
483
550
  createTestClient,
484
551
  createTestProject,