@danceroutine/tango-testing 1.11.0 → 1.11.2
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/{aDBClient-CH-ZcOaP.js → aDBClient-fMkIdR7p.js} +16 -7
- package/dist/aDBClient-fMkIdR7p.js.map +1 -0
- package/dist/assertions/index.d.ts +2 -4
- package/dist/assertions/index.js +2 -3
- package/dist/assertions-lsAd7fhA.js +15 -0
- package/dist/assertions-lsAd7fhA.js.map +1 -0
- package/dist/chunk-D7D4PA-g.js +13 -0
- package/dist/express/index.d.ts +2 -3
- package/dist/express/index.js +2 -3
- package/dist/{express-Czpfz_Ay.js → express-CH6_GAyC.js} +23 -15
- package/dist/express-CH6_GAyC.js.map +1 -0
- package/dist/factories/index.d.ts +2 -4
- package/dist/factories/index.js +2 -3
- package/dist/{factories-Cl_CAzbj.js → factories-qAJouv1I.js} +10 -8
- package/dist/factories-qAJouv1I.js.map +1 -0
- package/dist/index-49XmDOxW.d.ts +40 -0
- package/dist/index-B4H3wYuR.d.ts +325 -0
- package/dist/index-BCWo7zAn.d.ts +41 -0
- package/dist/index-CKVKW5j_.d.ts +15 -0
- package/dist/index-CnUPgs3G.d.ts +208 -0
- package/dist/index.d.ts +7 -19
- package/dist/index.js +8 -9
- package/dist/integration/index.d.ts +2 -18
- package/dist/integration/index.js +2 -4
- package/dist/{integration-CaRF_lF_.js → integration-CLzkacon.js} +99 -84
- package/dist/integration-CLzkacon.js.map +1 -0
- package/dist/mocks/index.d.ts +2 -20
- package/dist/mocks/index.js +3 -4
- package/dist/{mocks-BL_0iuAI.js → mocks-JyZwO-W4.js} +77 -65
- package/dist/mocks-JyZwO-W4.js.map +1 -0
- package/dist/vitest/index.d.ts +60 -3
- package/dist/vitest/index.js +119 -4
- package/dist/vitest/index.js.map +1 -0
- package/package.json +8 -8
- package/dist/aDBClient-CH-ZcOaP.js.map +0 -1
- package/dist/assertions/assertions.d.ts +0 -7
- package/dist/assertions-CCFZ53Y-.js +0 -15
- package/dist/assertions-CCFZ53Y-.js.map +0 -1
- package/dist/chunk-BkvOhyD0.js +0 -12
- package/dist/express/anExpressRequest.d.ts +0 -24
- package/dist/express/anExpressResponse.d.ts +0 -9
- package/dist/express-Czpfz_Ay.js.map +0 -1
- package/dist/factories/ModelDataFactory.d.ts +0 -33
- package/dist/factories-Cl_CAzbj.js.map +0 -1
- package/dist/integration/HarnessStrategyRegistry.d.ts +0 -25
- package/dist/integration/TestHarness.d.ts +0 -38
- package/dist/integration/anIntegrationHarness.d.ts +0 -5
- package/dist/integration/config.d.ts +0 -11
- package/dist/integration/conformance/index.d.ts +0 -1
- package/dist/integration/conformance/runDialectConformanceSuite.d.ts +0 -11
- package/dist/integration/domain/Dialect.d.ts +0 -5
- package/dist/integration/domain/HarnessStrategy.d.ts +0 -17
- package/dist/integration/domain/IntegrationHarness.d.ts +0 -22
- package/dist/integration/domain/ResetMode.d.ts +0 -6
- package/dist/integration/domain/index.d.ts +0 -7
- package/dist/integration/migrations/ApplyAndVerifyMigrations.d.ts +0 -16
- package/dist/integration/migrations/AssertMigrationPlan.d.ts +0 -9
- package/dist/integration/migrations/IntrospectSchema.d.ts +0 -5
- package/dist/integration/migrations/index.d.ts +0 -6
- package/dist/integration/orm/createModelQuerySetFixture.d.ts +0 -10
- package/dist/integration/orm/createQuerySetFixture.d.ts +0 -10
- package/dist/integration/orm/expectQueryResult.d.ts +0 -4
- package/dist/integration/orm/index.d.ts +0 -7
- package/dist/integration/orm/seedTable.d.ts +0 -5
- package/dist/integration/runtime/aTangoConfig.d.ts +0 -9
- package/dist/integration/runtime/aTangoRuntime.d.ts +0 -6
- package/dist/integration/runtime/index.d.ts +0 -7
- package/dist/integration/runtime/setupTestTangoRuntime.d.ts +0 -6
- package/dist/integration/smoke/AppProcessHarness.d.ts +0 -83
- package/dist/integration/smoke/index.d.ts +0 -4
- package/dist/integration/strategies/PostgresHarnessStrategy.d.ts +0 -19
- package/dist/integration/strategies/SqliteHarnessStrategy.d.ts +0 -19
- package/dist/integration-CaRF_lF_.js.map +0 -1
- package/dist/mocks/DBClient.d.ts +0 -1
- package/dist/mocks/MockQuerySetResult.d.ts +0 -6
- package/dist/mocks/aDBClient.d.ts +0 -24
- package/dist/mocks/aManager.d.ts +0 -20
- package/dist/mocks/aManyToManyRelatedManager.d.ts +0 -52
- package/dist/mocks/aModelQuerySet.d.ts +0 -8
- package/dist/mocks/aQueryExecutor.d.ts +0 -16
- package/dist/mocks/aQueryResult.d.ts +0 -9
- package/dist/mocks/aQuerySet.d.ts +0 -5
- package/dist/mocks/aRelationMeta.d.ts +0 -20
- package/dist/mocks/aRequestContext.d.ts +0 -22
- package/dist/mocks/anAdapter.d.ts +0 -13
- package/dist/mocks-BL_0iuAI.js.map +0 -1
- package/dist/vitest/registerVitestTango.d.ts +0 -46
- package/dist/vitest/withGlobalTestApi.d.ts +0 -7
- package/dist/vitest-BqZmULOa.js +0 -111
- package/dist/vitest-BqZmULOa.js.map +0 -1
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { ManyToManyRelatedManager, ModelQuerySet
|
|
4
|
-
import { vi
|
|
5
|
-
import { QueryResult
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.js";
|
|
2
|
+
import { n as anAdapter, t as aDBClient } from "./aDBClient-fMkIdR7p.js";
|
|
3
|
+
import { ManyToManyRelatedManager, ModelQuerySet } from "@danceroutine/tango-orm";
|
|
4
|
+
import { vi } from "vitest";
|
|
5
|
+
import { QueryResult } from "@danceroutine/tango-orm/query";
|
|
6
6
|
import { getLogger } from "@danceroutine/tango-core";
|
|
7
7
|
import { RequestContext } from "@danceroutine/tango-resources/context";
|
|
8
|
-
|
|
9
8
|
//#region src/mocks/aQueryResult.ts
|
|
9
|
+
/**
|
|
10
|
+
* Create a query-result test value with optional overrides.
|
|
11
|
+
*/
|
|
10
12
|
function aQueryResult(overrides = {}) {
|
|
11
|
-
|
|
12
|
-
return new QueryResultClass(items);
|
|
13
|
+
return new QueryResult(overrides.items ?? overrides.results ?? []);
|
|
13
14
|
}
|
|
14
|
-
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/mocks/aQueryExecutor.ts
|
|
17
|
+
/**
|
|
18
|
+
* Create a minimal `QueryExecutor` test double for `QuerySet` tests.
|
|
19
|
+
*/
|
|
17
20
|
function aQueryExecutor(overrides = {}) {
|
|
18
21
|
const adapter = overrides.adapter ?? anAdapter({ dialect: overrides.dialect ?? "postgres" });
|
|
19
22
|
const meta = overrides.meta ?? {
|
|
@@ -21,27 +24,31 @@ function aQueryExecutor(overrides = {}) {
|
|
|
21
24
|
pk: "id",
|
|
22
25
|
columns: {}
|
|
23
26
|
};
|
|
24
|
-
const run = overrides.run ?? vi
|
|
25
|
-
const client = aDBClient(overrides.query ? { query: overrides.query } : {});
|
|
27
|
+
const run = overrides.run ?? vi.fn(async () => []);
|
|
26
28
|
return {
|
|
27
29
|
meta,
|
|
28
|
-
client,
|
|
30
|
+
client: aDBClient(overrides.query ? { query: overrides.query } : {}),
|
|
29
31
|
adapter,
|
|
30
32
|
run,
|
|
31
33
|
...overrides.attachPersistedRecordAccessors ? { attachPersistedRecordAccessors: overrides.attachPersistedRecordAccessors } : {}
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
|
-
|
|
35
36
|
//#endregion
|
|
36
37
|
//#region src/mocks/aModelQuerySet.ts
|
|
38
|
+
/**
|
|
39
|
+
* Create a chainable model-queryset test double with optional behavior overrides.
|
|
40
|
+
*
|
|
41
|
+
* All methods are wrapped in `vi.fn()` so they can be asserted on directly
|
|
42
|
+
* without an additional `vi.mocked()` call.
|
|
43
|
+
*/
|
|
37
44
|
function aModelQuerySet(overrides = {}) {
|
|
38
|
-
const queryset = new
|
|
45
|
+
const queryset = new ModelQuerySet(aQueryExecutor());
|
|
39
46
|
const filterImpl = overrides.filter ?? ((_input) => queryset);
|
|
40
47
|
const excludeImpl = overrides.exclude ?? ((_input) => queryset);
|
|
41
48
|
const orderByImpl = overrides.orderBy ?? ((..._tokens) => queryset);
|
|
42
49
|
const limitImpl = overrides.limit ?? ((_n) => queryset);
|
|
43
50
|
const offsetImpl = overrides.offset ?? ((_n) => queryset);
|
|
44
|
-
const defaultSelect = (_cols) => queryset;
|
|
51
|
+
const defaultSelect = ((_cols) => queryset);
|
|
45
52
|
const selectImpl = overrides.select ?? defaultSelect;
|
|
46
53
|
const selectRelatedImpl = overrides.selectRelated ?? ((..._rels) => queryset);
|
|
47
54
|
const prefetchRelatedImpl = overrides.prefetchRelated ?? ((..._rels) => queryset);
|
|
@@ -49,23 +56,25 @@ function aModelQuerySet(overrides = {}) {
|
|
|
49
56
|
const fetchOneImpl = overrides.fetchOne ?? (async (_shape) => null);
|
|
50
57
|
const countImpl = overrides.count ?? (async () => 0);
|
|
51
58
|
const existsImpl = overrides.exists ?? (async () => false);
|
|
52
|
-
queryset.filter = vi
|
|
53
|
-
queryset.exclude = vi
|
|
54
|
-
queryset.orderBy = vi
|
|
55
|
-
queryset.limit = vi
|
|
56
|
-
queryset.offset = vi
|
|
57
|
-
queryset.select = vi
|
|
58
|
-
queryset.selectRelated = vi
|
|
59
|
-
queryset.prefetchRelated = vi
|
|
60
|
-
queryset.fetch = vi
|
|
61
|
-
queryset.fetchOne = vi
|
|
62
|
-
queryset.count = vi
|
|
63
|
-
queryset.exists = vi
|
|
59
|
+
queryset.filter = vi.fn((input) => filterImpl(input));
|
|
60
|
+
queryset.exclude = vi.fn((input) => excludeImpl(input));
|
|
61
|
+
queryset.orderBy = vi.fn((...tokens) => orderByImpl(...tokens));
|
|
62
|
+
queryset.limit = vi.fn((n) => limitImpl(n));
|
|
63
|
+
queryset.offset = vi.fn((n) => offsetImpl(n));
|
|
64
|
+
queryset.select = vi.fn((cols) => selectImpl(cols));
|
|
65
|
+
queryset.selectRelated = vi.fn((...rels) => selectRelatedImpl(...rels));
|
|
66
|
+
queryset.prefetchRelated = vi.fn((...rels) => prefetchRelatedImpl(...rels));
|
|
67
|
+
queryset.fetch = vi.fn(fetchImpl);
|
|
68
|
+
queryset.fetchOne = vi.fn(fetchOneImpl);
|
|
69
|
+
queryset.count = vi.fn(() => countImpl());
|
|
70
|
+
queryset.exists = vi.fn(() => existsImpl());
|
|
64
71
|
return queryset;
|
|
65
72
|
}
|
|
66
|
-
|
|
67
73
|
//#endregion
|
|
68
74
|
//#region src/mocks/aManager.ts
|
|
75
|
+
/**
|
|
76
|
+
* Create a manager-shaped test double for resource and service tests.
|
|
77
|
+
*/
|
|
69
78
|
function aManager(overrides = {}) {
|
|
70
79
|
const meta = overrides.meta ?? {
|
|
71
80
|
table: "mock_table",
|
|
@@ -96,21 +105,26 @@ function aManager(overrides = {}) {
|
|
|
96
105
|
}));
|
|
97
106
|
return {
|
|
98
107
|
meta,
|
|
99
|
-
query: vi
|
|
100
|
-
all: vi
|
|
101
|
-
getOrCreate: vi
|
|
102
|
-
updateOrCreate: vi
|
|
103
|
-
findById: vi
|
|
104
|
-
getOrThrow: vi
|
|
105
|
-
create: vi
|
|
106
|
-
update: vi
|
|
107
|
-
delete: vi
|
|
108
|
-
bulkCreate: vi
|
|
108
|
+
query: vi.fn(() => queryImpl()),
|
|
109
|
+
all: vi.fn(() => allImpl()),
|
|
110
|
+
getOrCreate: vi.fn((args) => getOrCreateImpl(args)),
|
|
111
|
+
updateOrCreate: vi.fn((args) => updateOrCreateImpl(args)),
|
|
112
|
+
findById: vi.fn((id) => findByIdImpl(id)),
|
|
113
|
+
getOrThrow: vi.fn((id) => getOrThrowImpl(id)),
|
|
114
|
+
create: vi.fn((input) => createImpl(input)),
|
|
115
|
+
update: vi.fn((id, patch) => updateImpl(id, patch)),
|
|
116
|
+
delete: vi.fn((id) => deleteImpl(id)),
|
|
117
|
+
bulkCreate: vi.fn((inputs) => bulkCreateImpl(inputs))
|
|
109
118
|
};
|
|
110
119
|
}
|
|
111
|
-
|
|
112
120
|
//#endregion
|
|
113
121
|
//#region src/mocks/aManyToManyRelatedManager.ts
|
|
122
|
+
/**
|
|
123
|
+
* Build a {@link ManyToManyRelatedManager} instance wired to lightweight spies
|
|
124
|
+
* for its underlying join-table operations. The fixture skips the
|
|
125
|
+
* relation-metadata and registry plumbing exercised by `ModelManager`, so
|
|
126
|
+
* tests can focus on manager behavior in isolation.
|
|
127
|
+
*/
|
|
114
128
|
function aManyToManyRelatedManager(overrides = {}) {
|
|
115
129
|
const insertLink = vi.fn(overrides.insertLink ?? (async () => {}));
|
|
116
130
|
const insertLinks = vi.fn(overrides.insertLinks ?? (async () => {}));
|
|
@@ -131,18 +145,17 @@ function aManyToManyRelatedManager(overrides = {}) {
|
|
|
131
145
|
deleteAllLinksForOwner,
|
|
132
146
|
selectTargetIdsForOwner
|
|
133
147
|
};
|
|
134
|
-
const manager = new ManyToManyRelatedManager({
|
|
135
|
-
ownerPrimaryKey: overrides.ownerPrimaryKey ?? 7,
|
|
136
|
-
relationName: overrides.relationName ?? "tags",
|
|
137
|
-
ownerModelLabel: overrides.ownerModelLabel ?? "Post",
|
|
138
|
-
targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? "id",
|
|
139
|
-
throughTableManager,
|
|
140
|
-
targetExecutorProvider: () => overrides.targetExecutor === undefined ? {} : overrides.targetExecutor,
|
|
141
|
-
createTarget,
|
|
142
|
-
runAtomic: runAtomicSpy
|
|
143
|
-
});
|
|
144
148
|
return {
|
|
145
|
-
manager
|
|
149
|
+
manager: new ManyToManyRelatedManager({
|
|
150
|
+
ownerPrimaryKey: overrides.ownerPrimaryKey ?? 7,
|
|
151
|
+
relationName: overrides.relationName ?? "tags",
|
|
152
|
+
ownerModelLabel: overrides.ownerModelLabel ?? "Post",
|
|
153
|
+
targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? "id",
|
|
154
|
+
throughTableManager,
|
|
155
|
+
targetExecutorProvider: () => overrides.targetExecutor === void 0 ? {} : overrides.targetExecutor,
|
|
156
|
+
createTarget,
|
|
157
|
+
runAtomic: runAtomicSpy
|
|
158
|
+
}),
|
|
146
159
|
insertLink,
|
|
147
160
|
insertLinks,
|
|
148
161
|
deleteLink,
|
|
@@ -153,11 +166,13 @@ function aManyToManyRelatedManager(overrides = {}) {
|
|
|
153
166
|
runAtomic: runAtomicSpy
|
|
154
167
|
};
|
|
155
168
|
}
|
|
156
|
-
|
|
157
169
|
//#endregion
|
|
158
170
|
//#region src/mocks/aQuerySet.ts
|
|
159
171
|
const logger = getLogger("tango.testing.mocks");
|
|
160
172
|
let hasWarned = false;
|
|
173
|
+
/**
|
|
174
|
+
* @deprecated Use `aModelQuerySet(...)` instead.
|
|
175
|
+
*/
|
|
161
176
|
function aQuerySet(overrides = {}) {
|
|
162
177
|
if (!hasWarned) {
|
|
163
178
|
hasWarned = true;
|
|
@@ -165,33 +180,32 @@ function aQuerySet(overrides = {}) {
|
|
|
165
180
|
}
|
|
166
181
|
return aModelQuerySet(overrides);
|
|
167
182
|
}
|
|
168
|
-
|
|
169
183
|
//#endregion
|
|
170
184
|
//#region src/mocks/aRequestContext.ts
|
|
171
185
|
function aRequestContext(optionsOrMethod = {}, urlArg, bodyArg) {
|
|
172
|
-
const
|
|
186
|
+
const { method = "GET", url = "https://example.test", body, user = null, params = {}, headers, contextFactory } = typeof optionsOrMethod === "string" ? {
|
|
173
187
|
method: optionsOrMethod,
|
|
174
188
|
url: urlArg,
|
|
175
189
|
body: bodyArg
|
|
176
190
|
} : optionsOrMethod;
|
|
177
|
-
const
|
|
178
|
-
const resolvedHeaders = body === undefined ? headers : {
|
|
191
|
+
const resolvedHeaders = body === void 0 ? headers : {
|
|
179
192
|
"content-type": "application/json",
|
|
180
193
|
...headers
|
|
181
194
|
};
|
|
182
195
|
const request = new Request(url, {
|
|
183
196
|
method,
|
|
184
197
|
headers: resolvedHeaders,
|
|
185
|
-
body: body ===
|
|
198
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
186
199
|
});
|
|
187
|
-
const
|
|
188
|
-
const context = createContext(request, user);
|
|
200
|
+
const context = (contextFactory ?? ((req, currentUser) => RequestContext.create(req, currentUser)))(request, user);
|
|
189
201
|
context.params = params;
|
|
190
202
|
return context;
|
|
191
203
|
}
|
|
192
|
-
|
|
193
204
|
//#endregion
|
|
194
205
|
//#region src/mocks/aRelationMeta.ts
|
|
206
|
+
/**
|
|
207
|
+
* Build recursive relation metadata fixtures for planner/compiler/query tests.
|
|
208
|
+
*/
|
|
195
209
|
function aRelationMeta(input) {
|
|
196
210
|
const cardinality = input.kind === "belongsTo" || input.kind === "hasOne" ? "single" : "many";
|
|
197
211
|
const defaultHydratable = input.kind !== "manyToMany";
|
|
@@ -223,11 +237,9 @@ function aRelationMeta(input) {
|
|
|
223
237
|
targetMeta
|
|
224
238
|
};
|
|
225
239
|
}
|
|
226
|
-
|
|
227
240
|
//#endregion
|
|
228
241
|
//#region src/mocks/index.ts
|
|
229
|
-
var mocks_exports = {
|
|
230
|
-
__export(mocks_exports, {
|
|
242
|
+
var mocks_exports = /* @__PURE__ */ __exportAll({
|
|
231
243
|
aDBClient: () => aDBClient,
|
|
232
244
|
aManager: () => aManager,
|
|
233
245
|
aManyToManyRelatedManager: () => aManyToManyRelatedManager,
|
|
@@ -239,7 +251,7 @@ __export(mocks_exports, {
|
|
|
239
251
|
aRequestContext: () => aRequestContext,
|
|
240
252
|
anAdapter: () => anAdapter
|
|
241
253
|
});
|
|
242
|
-
|
|
243
254
|
//#endregion
|
|
244
|
-
export {
|
|
245
|
-
|
|
255
|
+
export { aManyToManyRelatedManager as a, aQueryExecutor as c, aQuerySet as i, aQueryResult as l, aRelationMeta as n, aManager as o, aRequestContext as r, aModelQuerySet as s, mocks_exports as t };
|
|
256
|
+
|
|
257
|
+
//# sourceMappingURL=mocks-JyZwO-W4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mocks-JyZwO-W4.js","names":["QueryResultClass","QuerySetClass"],"sources":["../src/mocks/aQueryResult.ts","../src/mocks/aQueryExecutor.ts","../src/mocks/aModelQuerySet.ts","../src/mocks/aManager.ts","../src/mocks/aManyToManyRelatedManager.ts","../src/mocks/aQuerySet.ts","../src/mocks/aRequestContext.ts","../src/mocks/aRelationMeta.ts","../src/mocks/index.ts"],"sourcesContent":["import type { QueryResult } from '@danceroutine/tango-orm/query';\nimport { QueryResult as QueryResultClass } from '@danceroutine/tango-orm/query';\n\nexport type AQueryResultOverrides<TModel> = {\n items?: readonly TModel[];\n results?: readonly TModel[];\n};\n\n/**\n * Create a query-result test value with optional overrides.\n */\nexport function aQueryResult<TModel>(overrides: AQueryResultOverrides<TModel> = {}): QueryResult<TModel> {\n const items = overrides.items ?? overrides.results ?? ([] as TModel[]);\n return new QueryResultClass(items);\n}\n","import { vi } from 'vitest';\nimport type { Adapter, QueryExecutor } from '@danceroutine/tango-orm';\nimport type { Dialect, TableMeta } from '@danceroutine/tango-orm/query';\nimport { anAdapter } from './anAdapter';\nimport { aDBClient } from './aDBClient';\n\nexport type QueryExecutorOverrides<TModel extends Record<string, unknown>> = {\n dialect?: Dialect;\n adapter?: Adapter;\n meta?: TableMeta;\n query?: (sql: string, params?: readonly unknown[]) => Promise<{ rows: unknown[] }>;\n run?: QueryExecutor<TModel>['run'];\n attachPersistedRecordAccessors?: QueryExecutor<TModel>['attachPersistedRecordAccessors'];\n};\n\n/**\n * Create a minimal `QueryExecutor` test double for `QuerySet` tests.\n */\nexport function aQueryExecutor<TModel extends Record<string, unknown>>(\n overrides: QueryExecutorOverrides<TModel> = {}\n): QueryExecutor<TModel> {\n const adapter = overrides.adapter ?? anAdapter({ dialect: overrides.dialect ?? 'postgres' });\n const meta: TableMeta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const run = overrides.run ?? vi.fn(async () => [] as TModel[]);\n const client = aDBClient(overrides.query ? { query: overrides.query } : {});\n\n return {\n meta,\n client,\n adapter,\n run,\n ...(overrides.attachPersistedRecordAccessors\n ? { attachPersistedRecordAccessors: overrides.attachPersistedRecordAccessors }\n : {}),\n };\n}\n","import { vi } from 'vitest';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { ModelQuerySet as QuerySetClass } from '@danceroutine/tango-orm';\nimport { aQueryResult } from './aQueryResult';\nimport { aQueryExecutor } from './aQueryExecutor';\n\n/**\n * Create a chainable model-queryset test double with optional behavior overrides.\n *\n * All methods are wrapped in `vi.fn()` so they can be asserted on directly\n * without an additional `vi.mocked()` call.\n */\nexport function aModelQuerySet<\n TModel extends Record<string, unknown>,\n TResult extends Record<string, unknown> = TModel,\n>(overrides: Partial<QuerySet<TModel, TResult>> = {}): QuerySet<TModel, TResult> {\n const queryset = new QuerySetClass<TModel, TResult>(aQueryExecutor<TModel>());\n const filterImpl: QuerySet<TModel, TResult>['filter'] = overrides.filter ?? ((_input) => queryset);\n const excludeImpl: QuerySet<TModel, TResult>['exclude'] = overrides.exclude ?? ((_input) => queryset);\n const orderByImpl: QuerySet<TModel, TResult>['orderBy'] = overrides.orderBy ?? ((..._tokens) => queryset);\n const limitImpl: QuerySet<TModel, TResult>['limit'] = overrides.limit ?? ((_n) => queryset);\n const offsetImpl: QuerySet<TModel, TResult>['offset'] = overrides.offset ?? ((_n) => queryset);\n const defaultSelect = ((_cols: readonly (keyof TModel)[]) => queryset) as unknown as QuerySet<\n TModel,\n TResult\n >['select'];\n const selectImpl = overrides.select ?? defaultSelect;\n const selectRelatedImpl =\n (overrides.selectRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const prefetchRelatedImpl =\n (overrides.prefetchRelated as ((...rels: readonly string[]) => QuerySet<TModel, TResult>) | undefined) ??\n ((..._rels: readonly string[]) => queryset);\n const fetchImpl: QuerySet<TModel, TResult>['fetch'] =\n overrides.fetch ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => aQueryResult<Out>());\n const fetchOneImpl: QuerySet<TModel, TResult>['fetchOne'] =\n overrides.fetchOne ??\n (async <Out = TResult>(_shape?: ((r: TResult) => Out) | { parse: (r: TResult) => Out }) => null as Out | null);\n const countImpl: QuerySet<TModel, TResult>['count'] = overrides.count ?? (async () => 0);\n const existsImpl: QuerySet<TModel, TResult>['exists'] = overrides.exists ?? (async () => false);\n\n queryset.filter = vi.fn((input: Parameters<QuerySet<TModel, TResult>['filter']>[0]) =>\n filterImpl(input)\n ) as QuerySet<TModel, TResult>['filter'];\n queryset.exclude = vi.fn((input: Parameters<QuerySet<TModel, TResult>['exclude']>[0]) =>\n excludeImpl(input)\n ) as QuerySet<TModel, TResult>['exclude'];\n queryset.orderBy = vi.fn((...tokens: Parameters<QuerySet<TModel, TResult>['orderBy']>) =>\n orderByImpl(...tokens)\n ) as QuerySet<TModel, TResult>['orderBy'];\n queryset.limit = vi.fn((n: number) => limitImpl(n)) as QuerySet<TModel, TResult>['limit'];\n queryset.offset = vi.fn((n: number) => offsetImpl(n)) as QuerySet<TModel, TResult>['offset'];\n queryset.select = vi.fn((cols: Parameters<QuerySet<TModel, TResult>['select']>[0]) =>\n selectImpl(cols)\n ) as unknown as QuerySet<TModel, TResult>['select'];\n queryset.selectRelated = vi.fn((...rels: readonly string[]) => selectRelatedImpl(...rels)) as unknown as QuerySet<\n TModel,\n TResult\n >['selectRelated'];\n queryset.prefetchRelated = vi.fn((...rels: readonly string[]) =>\n prefetchRelatedImpl(...rels)\n ) as unknown as QuerySet<TModel, TResult>['prefetchRelated'];\n queryset.fetch = vi.fn(fetchImpl) as unknown as QuerySet<TModel, TResult>['fetch'];\n queryset.fetchOne = vi.fn(fetchOneImpl) as unknown as QuerySet<TModel, TResult>['fetchOne'];\n queryset.count = vi.fn(() => countImpl()) as QuerySet<TModel, TResult>['count'];\n queryset.exists = vi.fn(() => existsImpl()) as QuerySet<TModel, TResult>['exists'];\n\n return queryset;\n}\n","import { vi } from 'vitest';\nimport type { ManagerLike, QuerySet } from '@danceroutine/tango-orm';\nimport type { TableMeta } from '@danceroutine/tango-orm/query';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nexport type ManagerOverrides<TModel extends Record<string, unknown>> = {\n meta?: TableMeta;\n querySet?: QuerySet<TModel>;\n query?: ManagerLike<TModel>['query'];\n all?: ManagerLike<TModel>['all'];\n getOrCreate?: ManagerLike<TModel>['getOrCreate'];\n updateOrCreate?: ManagerLike<TModel>['updateOrCreate'];\n findById?: ManagerLike<TModel>['findById'];\n getOrThrow?: ManagerLike<TModel>['getOrThrow'];\n create?: ManagerLike<TModel>['create'];\n update?: ManagerLike<TModel>['update'];\n delete?: ManagerLike<TModel>['delete'];\n bulkCreate?: ManagerLike<TModel>['bulkCreate'];\n};\n\n/**\n * Create a manager-shaped test double for resource and service tests.\n */\nexport function aManager<TModel extends Record<string, unknown>>(\n overrides: ManagerOverrides<TModel> = {}\n): ManagerLike<TModel> {\n const meta = overrides.meta ?? { table: 'mock_table', pk: 'id', columns: {} };\n const querySet = overrides.querySet ?? aModelQuerySet<TModel>();\n type ModelId = TModel[keyof TModel];\n\n const queryImpl = overrides.query ?? (() => querySet);\n const allImpl = overrides.all ?? (() => queryImpl());\n const findByIdImpl = overrides.findById ?? (async () => null as TModel | null);\n const getOrThrowImpl =\n overrides.getOrThrow ??\n (async (id: ModelId) => {\n const record = await findByIdImpl(id);\n if (!record) {\n throw new Error(`No ${meta.table} record found for ${String(meta.pk)}=${String(id)}.`);\n }\n return record;\n });\n const createImpl = overrides.create ?? (async (input: Partial<TModel>) => input as TModel);\n const updateImpl = overrides.update ?? (async (_id: ModelId, patch: Partial<TModel>) => patch as TModel);\n const deleteImpl = overrides.delete ?? (async (_id: ModelId) => {});\n const bulkCreateImpl = overrides.bulkCreate ?? (async (inputs: Partial<TModel>[]) => inputs as TModel[]);\n const getOrCreateImpl =\n overrides.getOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n }));\n const updateOrCreateImpl =\n overrides.updateOrCreate ??\n (async ({ defaults }: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => ({\n record: { ...defaults } as TModel,\n created: true,\n updated: false,\n }));\n\n return {\n meta,\n query: vi.fn(() => queryImpl()),\n all: vi.fn(() => allImpl()),\n getOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['getOrCreate']>[0]) => getOrCreateImpl(args)),\n updateOrCreate: vi.fn((args: Parameters<ManagerLike<TModel>['updateOrCreate']>[0]) => updateOrCreateImpl(args)),\n findById: vi.fn((id: ModelId) => findByIdImpl(id)),\n getOrThrow: vi.fn((id: ModelId) => getOrThrowImpl(id)),\n create: vi.fn((input: Partial<TModel>) => createImpl(input)),\n update: vi.fn((id: ModelId, patch: Partial<TModel>) => updateImpl(id, patch)),\n delete: vi.fn((id: ModelId) => deleteImpl(id)),\n bulkCreate: vi.fn((inputs: Partial<TModel>[]) => bulkCreateImpl(inputs)),\n };\n}\n","import { vi } from 'vitest';\nimport type { QueryExecutor } from '@danceroutine/tango-orm';\nimport { ManyToManyRelatedManager } from '@danceroutine/tango-orm';\n\ntype ManagerConstructorInputs = ConstructorParameters<typeof ManyToManyRelatedManager>[0];\n\n/**\n * Overrides accepted by the {@link aManyToManyRelatedManager} fixture. All\n * fields are optional; defaults produce a manager bound to owner primary key\n * `7`, relation name `'tags'`, owner label `'Post'`, and target primary-key\n * field `'id'`.\n */\nexport interface ManyToManyRelatedManagerFixtureOverrides<TTarget extends Record<string, unknown>> {\n ownerPrimaryKey?: unknown;\n relationName?: string;\n ownerModelLabel?: string;\n targetPrimaryKeyField?: string;\n /**\n * Resolver returned by the manager's `targetExecutorProvider`. Pass `null`\n * to simulate the registry not yet knowing about the target model; omit to\n * return a minimal executor stub.\n */\n targetExecutor?: QueryExecutor<TTarget> | null;\n insertLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n insertLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteLink?: (ownerPrimaryKey: unknown, targetPrimaryKey: unknown) => Promise<void>;\n deleteLinks?: (ownerPrimaryKey: unknown, targetPrimaryKeys: readonly unknown[]) => Promise<void>;\n deleteAllLinksForOwner?: (ownerPrimaryKey: unknown) => Promise<void>;\n selectTargetIdsForOwner?: (ownerPrimaryKey: unknown) => Promise<readonly (string | number)[]>;\n createTarget?: (input: Partial<TTarget>) => Promise<TTarget>;\n runAtomic?: <T>(work: () => Promise<T>) => Promise<T>;\n}\n\n/**\n * Return shape of the {@link aManyToManyRelatedManager} fixture. The spy\n * references are returned alongside the manager so tests can assert against\n * the join-table calls without reaching into private fields.\n */\nexport interface ManyToManyRelatedManagerFixture<TTarget extends Record<string, unknown>> {\n manager: ManyToManyRelatedManager<TTarget>;\n insertLink: ReturnType<typeof vi.fn>;\n insertLinks: ReturnType<typeof vi.fn>;\n deleteLink: ReturnType<typeof vi.fn>;\n deleteLinks: ReturnType<typeof vi.fn>;\n deleteAllLinksForOwner: ReturnType<typeof vi.fn>;\n selectTargetIdsForOwner: ReturnType<typeof vi.fn>;\n createTarget: ReturnType<typeof vi.fn>;\n runAtomic: ReturnType<typeof vi.fn>;\n}\n\n/**\n * Build a {@link ManyToManyRelatedManager} instance wired to lightweight spies\n * for its underlying join-table operations. The fixture skips the\n * relation-metadata and registry plumbing exercised by `ModelManager`, so\n * tests can focus on manager behavior in isolation.\n */\nexport function aManyToManyRelatedManager<TTarget extends Record<string, unknown>>(\n overrides: ManyToManyRelatedManagerFixtureOverrides<TTarget> = {}\n): ManyToManyRelatedManagerFixture<TTarget> {\n const insertLink = vi.fn(overrides.insertLink ?? (async () => {}));\n const insertLinks = vi.fn(overrides.insertLinks ?? (async () => {}));\n const deleteLink = vi.fn(overrides.deleteLink ?? (async () => {}));\n const deleteLinks = vi.fn(overrides.deleteLinks ?? (async () => {}));\n const deleteAllLinksForOwner = vi.fn(overrides.deleteAllLinksForOwner ?? (async () => {}));\n const selectTargetIdsForOwner = vi.fn(\n overrides.selectTargetIdsForOwner ?? (async (): Promise<readonly (string | number)[]> => [])\n );\n const createTarget = vi.fn(\n overrides.createTarget ??\n (async (input: Partial<TTarget>) => {\n return input as TTarget;\n })\n );\n const runAtomicImpl: ManagerConstructorInputs['runAtomic'] =\n overrides.runAtomic ?? (async <T>(work: () => Promise<T>) => work());\n const runAtomicSpy = vi.fn(async <T>(work: () => Promise<T>) => runAtomicImpl(work));\n\n const throughTableManager = {\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n } as unknown as ManagerConstructorInputs['throughTableManager'];\n\n const manager = new ManyToManyRelatedManager<TTarget>({\n ownerPrimaryKey: overrides.ownerPrimaryKey ?? 7,\n relationName: overrides.relationName ?? 'tags',\n ownerModelLabel: overrides.ownerModelLabel ?? 'Post',\n targetPrimaryKeyField: overrides.targetPrimaryKeyField ?? 'id',\n throughTableManager,\n targetExecutorProvider: () =>\n overrides.targetExecutor === undefined ? ({} as QueryExecutor<TTarget>) : overrides.targetExecutor,\n createTarget,\n runAtomic: runAtomicSpy as ManagerConstructorInputs['runAtomic'],\n });\n\n return {\n manager,\n insertLink,\n insertLinks,\n deleteLink,\n deleteLinks,\n deleteAllLinksForOwner,\n selectTargetIdsForOwner,\n createTarget,\n runAtomic: runAtomicSpy,\n };\n}\n","import { getLogger } from '@danceroutine/tango-core';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport { aModelQuerySet } from './aModelQuerySet';\n\nconst logger = getLogger('tango.testing.mocks');\n// TODO this pattern keeps showing up, perhaps we should implement logger.warnOnce\nlet hasWarned = false;\n\n/**\n * @deprecated Use `aModelQuerySet(...)` instead.\n */\nexport function aQuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel>(\n overrides: Partial<QuerySet<TModel, TResult>> = {}\n): QuerySet<TModel, TResult> {\n if (!hasWarned) {\n hasWarned = true;\n logger.warn('`aQuerySet(...)` is deprecated. Use `aModelQuerySet(...)` instead.');\n }\n\n return aModelQuerySet(overrides);\n}\n","// Import through the package subpath so fixtures stay aligned with the public nominal type.\nimport { RequestContext, type BaseUser } from '@danceroutine/tango-resources/context';\n\ntype RequestContextFactory<TUser, TContext extends RequestContextLike<TUser>> = (\n request: Request,\n user: TUser | null\n) => TContext;\n\ntype RequestContextLike<TUser> = {\n request: Request;\n user: TUser | null;\n params: Record<string, string>;\n};\n\nexport type RequestContextFixtureOptions<\n TUser = BaseUser,\n TContext extends RequestContextLike<TUser> = RequestContext<TUser>,\n> = {\n method?: string;\n url?: string;\n body?: unknown;\n user?: TUser | null;\n params?: Record<string, string>;\n headers?: HeadersInit;\n contextFactory?: RequestContextFactory<TUser, TContext>;\n};\n\n/**\n * Create a RequestContext fixture with optional method/url/body/user/params.\n */\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n method: string,\n url: string,\n body?: unknown\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n options?: RequestContextFixtureOptions<TUser, TContext>\n): TContext;\nexport function aRequestContext<TUser = BaseUser, TContext extends RequestContextLike<TUser> = RequestContext<TUser>>(\n optionsOrMethod: RequestContextFixtureOptions<TUser, TContext> | string = {},\n urlArg?: string,\n bodyArg?: unknown\n): TContext {\n const resolvedOptions: RequestContextFixtureOptions<TUser, TContext> =\n typeof optionsOrMethod === 'string'\n ? {\n method: optionsOrMethod,\n url: urlArg,\n body: bodyArg,\n }\n : optionsOrMethod;\n const {\n method = 'GET',\n url = 'https://example.test',\n body,\n user = null,\n params = {},\n headers,\n contextFactory,\n } = resolvedOptions;\n\n const resolvedHeaders: HeadersInit | undefined =\n body === undefined ? headers : { 'content-type': 'application/json', ...headers };\n\n const request = new Request(url, {\n method,\n headers: resolvedHeaders,\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n const createContext =\n contextFactory ?? ((req: Request, currentUser: TUser | null) => RequestContext.create<TUser>(req, currentUser));\n const context = createContext(request, user) as TContext;\n context.params = params;\n return context;\n}\n","import type { RelationMeta, TableMeta } from '@danceroutine/tango-orm/query';\n\ntype RelationMetaInput = {\n kind: RelationMeta['kind'];\n table: string;\n sourceKey: string;\n targetKey: string;\n targetColumns: Record<string, string>;\n alias: string;\n edgeId?: string;\n sourceModelKey?: string;\n targetModelKey?: string;\n targetPrimaryKey?: string;\n targetMeta?: TableMeta;\n capabilities?: Partial<RelationMeta['capabilities']>;\n};\n\n/**\n * Build recursive relation metadata fixtures for planner/compiler/query tests.\n */\nexport function aRelationMeta(input: RelationMetaInput): RelationMeta {\n const cardinality = input.kind === 'belongsTo' || input.kind === 'hasOne' ? 'single' : 'many';\n const defaultHydratable = input.kind !== ('manyToMany' as RelationMeta['kind']);\n\n const targetMeta =\n input.targetMeta ??\n ({\n modelKey: input.targetModelKey ?? `${input.alias}:target`,\n table: input.table,\n pk: input.targetPrimaryKey ?? 'id',\n columns: input.targetColumns,\n } satisfies TableMeta);\n\n return {\n edgeId: input.edgeId ?? `${input.alias}:${input.sourceKey}:${input.targetKey}`,\n sourceModelKey: input.sourceModelKey ?? `${input.alias}:source`,\n targetModelKey: input.targetModelKey ?? `${input.alias}:target`,\n kind: input.kind,\n cardinality,\n capabilities: {\n queryable: true,\n hydratable: defaultHydratable,\n joinable: cardinality === 'single' && defaultHydratable,\n prefetchable: defaultHydratable,\n ...input.capabilities,\n },\n table: input.table,\n sourceKey: input.sourceKey,\n targetKey: input.targetKey,\n targetPrimaryKey: input.targetPrimaryKey ?? 'id',\n targetColumns: input.targetColumns,\n alias: input.alias,\n targetMeta,\n };\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { anAdapter } from './anAdapter';\nexport { aDBClient } from './aDBClient';\nexport { aManager } from './aManager';\nexport { aManyToManyRelatedManager } from './aManyToManyRelatedManager';\nexport { aModelQuerySet } from './aModelQuerySet';\nexport { aQueryResult } from './aQueryResult';\nexport { aQuerySet } from './aQuerySet';\nexport { aRequestContext } from './aRequestContext';\nexport { aQueryExecutor } from './aQueryExecutor';\nexport { aRelationMeta } from './aRelationMeta';\nexport type { AdapterOverrides } from './anAdapter';\nexport type { QueryExecutorOverrides } from './aQueryExecutor';\nexport type { ManagerOverrides } from './aManager';\nexport type {\n ManyToManyRelatedManagerFixture,\n ManyToManyRelatedManagerFixtureOverrides,\n} from './aManyToManyRelatedManager';\nexport type { DBClient } from './DBClient';\nexport type { MockQuerySetResult } from './MockQuerySetResult';\nexport type { RequestContextFixtureOptions } from './aRequestContext';\n"],"mappings":"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"}
|
package/dist/vitest/index.d.ts
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
|
+
import { A as IntegrationHarness, s as HarnessStrategyRegistry, w as AssertMigrationPlanOptions, x as ApplyAndVerifyMigrationsOptions } from "../index-B4H3wYuR.js";
|
|
2
|
+
|
|
3
|
+
//#region src/vitest/registerVitestTango.d.ts
|
|
4
|
+
interface Parseable {
|
|
5
|
+
parse(data: unknown): unknown;
|
|
6
|
+
}
|
|
7
|
+
interface TangoVitestHelpers {
|
|
8
|
+
useHarness(input: IntegrationHarness | (() => IntegrationHarness | Promise<IntegrationHarness>)): Promise<IntegrationHarness>;
|
|
9
|
+
getTestHarness(): IntegrationHarness;
|
|
10
|
+
getRegistry(): HarnessStrategyRegistry;
|
|
11
|
+
assertMigrationPlan(options: AssertMigrationPlanOptions & {
|
|
12
|
+
harness?: IntegrationHarness;
|
|
13
|
+
}): Promise<string>;
|
|
14
|
+
applyAndVerifyMigrations(options: ApplyAndVerifyMigrationsOptions & {
|
|
15
|
+
harness?: IntegrationHarness;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
statuses: {
|
|
18
|
+
id: string;
|
|
19
|
+
applied: boolean;
|
|
20
|
+
}[];
|
|
21
|
+
}>;
|
|
22
|
+
introspectSchema(harness?: IntegrationHarness): Promise<unknown>;
|
|
23
|
+
seedTable<T extends Record<string, unknown>>(table: string, rows: T[], harness?: IntegrationHarness): Promise<void>;
|
|
24
|
+
createModelQuerySetFixture<TModel extends Record<string, unknown>>(options: {
|
|
25
|
+
meta: import('@danceroutine/tango-orm/query').TableMeta;
|
|
26
|
+
harness?: IntegrationHarness;
|
|
27
|
+
}): import('@danceroutine/tango-orm').QuerySet<TModel>;
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated Use `vi.tango.createModelQuerySetFixture(...)` instead.
|
|
30
|
+
*/
|
|
31
|
+
createQuerySetFixture<TModel extends Record<string, unknown>>(options: {
|
|
32
|
+
meta: import('@danceroutine/tango-orm/query').TableMeta;
|
|
33
|
+
harness?: IntegrationHarness;
|
|
34
|
+
}): import('@danceroutine/tango-orm').QuerySet<TModel>;
|
|
35
|
+
expectQueryResult<T>(actual: Promise<T> | T, expected: T): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
declare module 'vitest' {
|
|
38
|
+
interface Assertion<T> {
|
|
39
|
+
toMatchSchema(schema: Parseable): void;
|
|
40
|
+
}
|
|
41
|
+
interface AsymmetricMatchersContaining {
|
|
42
|
+
toMatchSchema(schema: Parseable): void;
|
|
43
|
+
}
|
|
44
|
+
interface VitestUtils {
|
|
45
|
+
tango: TangoVitestHelpers;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/vitest/withGlobalTestApi.d.ts
|
|
1
50
|
/**
|
|
2
|
-
*
|
|
51
|
+
* Install a temporary global test API for the duration of one callback.
|
|
52
|
+
*
|
|
53
|
+
* This is useful for module-loading tests that need a stable escape hatch into
|
|
54
|
+
* already-imported symbols without introducing a second copy of the same package.
|
|
3
55
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
56
|
+
declare function withGlobalTestApi<TValue, TResult>(key: string, value: TValue, work: () => TResult | Promise<TResult>): Promise<TResult>;
|
|
57
|
+
declare namespace index_d_exports {
|
|
58
|
+
export { TangoVitestHelpers, withGlobalTestApi };
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { TangoVitestHelpers, index_d_exports as t, withGlobalTestApi };
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/vitest/index.js
CHANGED
|
@@ -1,5 +1,120 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../integration-
|
|
3
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "../chunk-D7D4PA-g.js";
|
|
2
|
+
import { a as seedTable, b as assertMigrationPlan, i as createModelQuerySetFixture, n as expectQueryResult, o as TestHarness, v as introspectSchema, y as applyAndVerifyMigrations } from "../integration-CLzkacon.js";
|
|
3
|
+
import { expect, vi } from "vitest";
|
|
4
|
+
import { getLogger } from "@danceroutine/tango-core";
|
|
5
|
+
//#region src/vitest/registerVitestTango.ts
|
|
6
|
+
/**
|
|
7
|
+
* Vitest custom matchers and helpers for Tango.
|
|
8
|
+
*
|
|
9
|
+
* Import this module in your Vitest setup file:
|
|
10
|
+
*
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import '@danceroutine/tango-testing/vitest';
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
function isError(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.message === "string";
|
|
17
|
+
}
|
|
18
|
+
let activeHarness = null;
|
|
19
|
+
const logger = getLogger("tango.testing.vitest");
|
|
20
|
+
let hasWarnedForCreateQuerySetFixture = false;
|
|
21
|
+
async function resolveHarness(input) {
|
|
22
|
+
if (typeof input === "function") return input();
|
|
23
|
+
return input;
|
|
24
|
+
}
|
|
25
|
+
const tangoHelpers = {
|
|
26
|
+
async useHarness(input) {
|
|
27
|
+
const harness = await resolveHarness(input);
|
|
28
|
+
await harness.setup();
|
|
29
|
+
activeHarness = harness;
|
|
30
|
+
return harness;
|
|
31
|
+
},
|
|
32
|
+
getTestHarness() {
|
|
33
|
+
if (!activeHarness) throw new Error("No active test harness. Call vi.tango.useHarness(...) in beforeAll first.");
|
|
34
|
+
return activeHarness;
|
|
35
|
+
},
|
|
36
|
+
getRegistry() {
|
|
37
|
+
return TestHarness.getRegistry();
|
|
38
|
+
},
|
|
39
|
+
async assertMigrationPlan(options) {
|
|
40
|
+
return assertMigrationPlan(options.harness ?? tangoHelpers.getTestHarness(), {
|
|
41
|
+
migrationsDir: options.migrationsDir,
|
|
42
|
+
expectSqlContains: options.expectSqlContains
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
async applyAndVerifyMigrations(options) {
|
|
46
|
+
return applyAndVerifyMigrations(options.harness ?? tangoHelpers.getTestHarness(), {
|
|
47
|
+
migrationsDir: options.migrationsDir,
|
|
48
|
+
toId: options.toId,
|
|
49
|
+
expectedAppliedIds: options.expectedAppliedIds
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
async introspectSchema(harness) {
|
|
53
|
+
return introspectSchema(harness ?? tangoHelpers.getTestHarness());
|
|
54
|
+
},
|
|
55
|
+
async seedTable(table, rows, harness) {
|
|
56
|
+
await seedTable(harness ?? tangoHelpers.getTestHarness(), table, rows);
|
|
57
|
+
},
|
|
58
|
+
createModelQuerySetFixture(options) {
|
|
59
|
+
return createModelQuerySetFixture({
|
|
60
|
+
harness: options.harness ?? tangoHelpers.getTestHarness(),
|
|
61
|
+
meta: options.meta
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
createQuerySetFixture(options) {
|
|
65
|
+
if (!hasWarnedForCreateQuerySetFixture) {
|
|
66
|
+
hasWarnedForCreateQuerySetFixture = true;
|
|
67
|
+
logger.warn("`vi.tango.createQuerySetFixture(...)` is deprecated. Use `vi.tango.createModelQuerySetFixture(...)` instead.");
|
|
68
|
+
}
|
|
69
|
+
return createModelQuerySetFixture({
|
|
70
|
+
harness: options.harness ?? tangoHelpers.getTestHarness(),
|
|
71
|
+
meta: options.meta
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
async expectQueryResult(actual, expected) {
|
|
75
|
+
await expectQueryResult(actual, expected);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
expect.extend({ toMatchSchema(received, schema) {
|
|
79
|
+
try {
|
|
80
|
+
schema.parse(received);
|
|
81
|
+
return {
|
|
82
|
+
pass: true,
|
|
83
|
+
message: () => "expected data not to match schema"
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const detail = isError(error) ? error.message : String(error);
|
|
87
|
+
return {
|
|
88
|
+
pass: false,
|
|
89
|
+
message: () => `expected data to match schema\n\n${detail}`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
} });
|
|
93
|
+
vi.tango = tangoHelpers;
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/vitest/withGlobalTestApi.ts
|
|
96
|
+
/**
|
|
97
|
+
* Install a temporary global test API for the duration of one callback.
|
|
98
|
+
*
|
|
99
|
+
* This is useful for module-loading tests that need a stable escape hatch into
|
|
100
|
+
* already-imported symbols without introducing a second copy of the same package.
|
|
101
|
+
*/
|
|
102
|
+
async function withGlobalTestApi(key, value, work) {
|
|
103
|
+
const globalRecord = globalThis;
|
|
104
|
+
const previousValue = globalRecord[key];
|
|
105
|
+
const hadPreviousValue = Object.prototype.hasOwnProperty.call(globalRecord, key);
|
|
106
|
+
globalRecord[key] = value;
|
|
107
|
+
try {
|
|
108
|
+
return await work();
|
|
109
|
+
} finally {
|
|
110
|
+
if (hadPreviousValue) globalRecord[key] = previousValue;
|
|
111
|
+
else delete globalRecord[key];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/vitest/index.ts
|
|
116
|
+
var vitest_exports = /* @__PURE__ */ __exportAll({ withGlobalTestApi: () => withGlobalTestApi });
|
|
117
|
+
//#endregion
|
|
118
|
+
export { vitest_exports as t, withGlobalTestApi };
|
|
4
119
|
|
|
5
|
-
|
|
120
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["assertMigrationPlanFn","applyAndVerifyMigrationsFn","introspectSchemaFn","seedTableFn","createModelQuerySetFixtureFn","expectQueryResultFn"],"sources":["../../src/vitest/registerVitestTango.ts","../../src/vitest/withGlobalTestApi.ts","../../src/vitest/index.ts"],"sourcesContent":["/**\n * Vitest custom matchers and helpers for Tango.\n *\n * Import this module in your Vitest setup file:\n *\n * ```typescript\n * import '@danceroutine/tango-testing/vitest';\n * ```\n */\nimport { expect, vi } from 'vitest';\nimport { getLogger } from '@danceroutine/tango-core';\nimport {\n TestHarness,\n applyAndVerifyMigrations as applyAndVerifyMigrationsFn,\n assertMigrationPlan as assertMigrationPlanFn,\n createModelQuerySetFixture as createModelQuerySetFixtureFn,\n expectQueryResult as expectQueryResultFn,\n introspectSchema as introspectSchemaFn,\n seedTable as seedTableFn,\n type ApplyAndVerifyMigrationsOptions,\n type AssertMigrationPlanOptions,\n type HarnessStrategyRegistry,\n type IntegrationHarness,\n} from '../integration';\n\ninterface Parseable {\n parse(data: unknown): unknown;\n}\n\nfunction isError(value: unknown): value is Error {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { name?: unknown }).name === 'string' &&\n typeof (value as { message?: unknown }).message === 'string'\n );\n}\n\nlet activeHarness: IntegrationHarness | null = null;\nconst logger = getLogger('tango.testing.vitest');\nlet hasWarnedForCreateQuerySetFixture = false;\n\nasync function resolveHarness(\n input: IntegrationHarness | (() => IntegrationHarness | Promise<IntegrationHarness>)\n): Promise<IntegrationHarness> {\n if (typeof input === 'function') {\n return input();\n }\n return input;\n}\n\nexport interface TangoVitestHelpers {\n useHarness(\n input: IntegrationHarness | (() => IntegrationHarness | Promise<IntegrationHarness>)\n ): Promise<IntegrationHarness>;\n getTestHarness(): IntegrationHarness;\n getRegistry(): HarnessStrategyRegistry;\n assertMigrationPlan(options: AssertMigrationPlanOptions & { harness?: IntegrationHarness }): Promise<string>;\n applyAndVerifyMigrations(\n options: ApplyAndVerifyMigrationsOptions & { harness?: IntegrationHarness }\n ): Promise<{ statuses: { id: string; applied: boolean }[] }>;\n introspectSchema(harness?: IntegrationHarness): Promise<unknown>;\n seedTable<T extends Record<string, unknown>>(table: string, rows: T[], harness?: IntegrationHarness): Promise<void>;\n createModelQuerySetFixture<TModel extends Record<string, unknown>>(options: {\n meta: import('@danceroutine/tango-orm/query').TableMeta;\n harness?: IntegrationHarness;\n }): import('@danceroutine/tango-orm').QuerySet<TModel>;\n /**\n * @deprecated Use `vi.tango.createModelQuerySetFixture(...)` instead.\n */\n createQuerySetFixture<TModel extends Record<string, unknown>>(options: {\n meta: import('@danceroutine/tango-orm/query').TableMeta;\n harness?: IntegrationHarness;\n }): import('@danceroutine/tango-orm').QuerySet<TModel>;\n expectQueryResult<T>(actual: Promise<T> | T, expected: T): Promise<void>;\n}\n\nconst tangoHelpers: TangoVitestHelpers = {\n async useHarness(input): Promise<IntegrationHarness> {\n const harness = await resolveHarness(input);\n await harness.setup();\n activeHarness = harness;\n return harness;\n },\n getTestHarness(): IntegrationHarness {\n if (!activeHarness) {\n throw new Error('No active test harness. Call vi.tango.useHarness(...) in beforeAll first.');\n }\n return activeHarness;\n },\n getRegistry(): HarnessStrategyRegistry {\n return TestHarness.getRegistry();\n },\n async assertMigrationPlan(options): Promise<string> {\n const harness = options.harness ?? tangoHelpers.getTestHarness();\n return assertMigrationPlanFn(harness, {\n migrationsDir: options.migrationsDir,\n expectSqlContains: options.expectSqlContains,\n });\n },\n async applyAndVerifyMigrations(options): Promise<{ statuses: { id: string; applied: boolean }[] }> {\n const harness = options.harness ?? tangoHelpers.getTestHarness();\n return applyAndVerifyMigrationsFn(harness, {\n migrationsDir: options.migrationsDir,\n toId: options.toId,\n expectedAppliedIds: options.expectedAppliedIds,\n });\n },\n async introspectSchema(harness?: IntegrationHarness): Promise<unknown> {\n return introspectSchemaFn(harness ?? tangoHelpers.getTestHarness());\n },\n async seedTable<T extends Record<string, unknown>>(\n table: string,\n rows: T[],\n harness?: IntegrationHarness\n ): Promise<void> {\n await seedTableFn(harness ?? tangoHelpers.getTestHarness(), table, rows);\n },\n createModelQuerySetFixture<TModel extends Record<string, unknown>>(options: {\n meta: import('@danceroutine/tango-orm/query').TableMeta;\n harness?: IntegrationHarness;\n }): import('@danceroutine/tango-orm').QuerySet<TModel> {\n return createModelQuerySetFixtureFn<TModel>({\n harness: options.harness ?? tangoHelpers.getTestHarness(),\n meta: options.meta,\n });\n },\n createQuerySetFixture<TModel extends Record<string, unknown>>(options: {\n meta: import('@danceroutine/tango-orm/query').TableMeta;\n harness?: IntegrationHarness;\n }): import('@danceroutine/tango-orm').QuerySet<TModel> {\n if (!hasWarnedForCreateQuerySetFixture) {\n hasWarnedForCreateQuerySetFixture = true;\n logger.warn(\n '`vi.tango.createQuerySetFixture(...)` is deprecated. Use `vi.tango.createModelQuerySetFixture(...)` instead.'\n );\n }\n return createModelQuerySetFixtureFn<TModel>({\n harness: options.harness ?? tangoHelpers.getTestHarness(),\n meta: options.meta,\n });\n },\n async expectQueryResult<T>(actual: Promise<T> | T, expected: T): Promise<void> {\n await expectQueryResultFn(actual, expected);\n },\n};\n\nexpect.extend({\n toMatchSchema(received: unknown, schema: Parseable) {\n try {\n schema.parse(received);\n return {\n pass: true,\n message: () => 'expected data not to match schema',\n };\n } catch (error) {\n const detail = isError(error) ? error.message : String(error);\n return {\n pass: false,\n message: () => `expected data to match schema\\n\\n${detail}`,\n };\n }\n },\n});\n\n(vi as unknown as { tango?: TangoVitestHelpers }).tango = tangoHelpers;\n\ndeclare module 'vitest' {\n // oxlint-disable-next-line no-unused-vars\n interface Assertion<T> {\n toMatchSchema(schema: Parseable): void;\n }\n\n interface AsymmetricMatchersContaining {\n toMatchSchema(schema: Parseable): void;\n }\n\n interface VitestUtils {\n tango: TangoVitestHelpers;\n }\n}\n","/**\n * Install a temporary global test API for the duration of one callback.\n *\n * This is useful for module-loading tests that need a stable escape hatch into\n * already-imported symbols without introducing a second copy of the same package.\n */\nexport async function withGlobalTestApi<TValue, TResult>(\n key: string,\n value: TValue,\n work: () => TResult | Promise<TResult>\n): Promise<TResult> {\n const globalRecord = globalThis as Record<string, unknown>;\n const previousValue = globalRecord[key];\n const hadPreviousValue = Object.prototype.hasOwnProperty.call(globalRecord, key);\n\n globalRecord[key] = value;\n try {\n return await work();\n } finally {\n if (hadPreviousValue) {\n globalRecord[key] = previousValue;\n } else {\n delete globalRecord[key];\n }\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport * from './registerVitestTango';\nexport * from './withGlobalTestApi';\n"],"mappings":";;;;;;;;;;;;;;AA6BA,SAAS,QAAQ,OAAgC;CAC7C,OACI,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS,YAC9C,OAAQ,MAAgC,YAAY;AAE5D;AAEA,IAAI,gBAA2C;AAC/C,MAAM,SAAS,UAAU,sBAAsB;AAC/C,IAAI,oCAAoC;AAExC,eAAe,eACX,OAC2B;CAC3B,IAAI,OAAO,UAAU,YACjB,OAAO,MAAM;CAEjB,OAAO;AACX;AA4BA,MAAM,eAAmC;CACrC,MAAM,WAAW,OAAoC;EACjD,MAAM,UAAU,MAAM,eAAe,KAAK;EAC1C,MAAM,QAAQ,MAAM;EACpB,gBAAgB;EAChB,OAAO;CACX;CACA,iBAAqC;EACjC,IAAI,CAAC,eACD,MAAM,IAAI,MAAM,2EAA2E;EAE/F,OAAO;CACX;CACA,cAAuC;EACnC,OAAO,YAAY,YAAY;CACnC;CACA,MAAM,oBAAoB,SAA0B;EAEhD,OAAOA,oBADS,QAAQ,WAAW,aAAa,eAAe,GACzB;GAClC,eAAe,QAAQ;GACvB,mBAAmB,QAAQ;EAC/B,CAAC;CACL;CACA,MAAM,yBAAyB,SAAoE;EAE/F,OAAOC,yBADS,QAAQ,WAAW,aAAa,eAAe,GACpB;GACvC,eAAe,QAAQ;GACvB,MAAM,QAAQ;GACd,oBAAoB,QAAQ;EAChC,CAAC;CACL;CACA,MAAM,iBAAiB,SAAgD;EACnE,OAAOC,iBAAmB,WAAW,aAAa,eAAe,CAAC;CACtE;CACA,MAAM,UACF,OACA,MACA,SACa;EACb,MAAMC,UAAY,WAAW,aAAa,eAAe,GAAG,OAAO,IAAI;CAC3E;CACA,2BAAmE,SAGZ;EACnD,OAAOC,2BAAqC;GACxC,SAAS,QAAQ,WAAW,aAAa,eAAe;GACxD,MAAM,QAAQ;EAClB,CAAC;CACL;CACA,sBAA8D,SAGP;EACnD,IAAI,CAAC,mCAAmC;GACpC,oCAAoC;GACpC,OAAO,KACH,8GACJ;EACJ;EACA,OAAOA,2BAAqC;GACxC,SAAS,QAAQ,WAAW,aAAa,eAAe;GACxD,MAAM,QAAQ;EAClB,CAAC;CACL;CACA,MAAM,kBAAqB,QAAwB,UAA4B;EAC3E,MAAMC,kBAAoB,QAAQ,QAAQ;CAC9C;AACJ;AAEA,OAAO,OAAO,EACV,cAAc,UAAmB,QAAmB;CAChD,IAAI;EACA,OAAO,MAAM,QAAQ;EACrB,OAAO;GACH,MAAM;GACN,eAAe;EACnB;CACJ,SAAS,OAAO;EACZ,MAAM,SAAS,QAAQ,KAAK,IAAI,MAAM,UAAU,OAAO,KAAK;EAC5D,OAAO;GACH,MAAM;GACN,eAAe,oCAAoC;EACvD;CACJ;AACJ,EACJ,CAAC;AAED,GAAkD,QAAQ;;;;;;;;;AC/J1D,eAAsB,kBAClB,KACA,OACA,MACgB;CAChB,MAAM,eAAe;CACrB,MAAM,gBAAgB,aAAa;CACnC,MAAM,mBAAmB,OAAO,UAAU,eAAe,KAAK,cAAc,GAAG;CAE/E,aAAa,OAAO;CACpB,IAAI;EACA,OAAO,MAAM,KAAK;CACtB,UAAU;EACN,IAAI,kBACA,aAAa,OAAO;OAEpB,OAAO,aAAa;CAE5B;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danceroutine/tango-testing",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Testing utilities for Tango",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"directory": "packages/testing"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@danceroutine/tango-
|
|
56
|
-
"@danceroutine/tango-migrations": "1.11.
|
|
57
|
-
"@danceroutine/tango-
|
|
58
|
-
"@danceroutine/tango-
|
|
59
|
-
"@danceroutine/tango-resources": "1.11.
|
|
55
|
+
"@danceroutine/tango-core": "1.11.2",
|
|
56
|
+
"@danceroutine/tango-migrations": "1.11.2",
|
|
57
|
+
"@danceroutine/tango-orm": "1.11.2",
|
|
58
|
+
"@danceroutine/tango-config": "1.11.2",
|
|
59
|
+
"@danceroutine/tango-resources": "1.11.2"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@types/express": "^5.0.0",
|
|
@@ -73,9 +73,9 @@
|
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@types/express": "^5.0.0",
|
|
75
75
|
"@types/node": "^22.9.0",
|
|
76
|
-
"tsdown": "^0.
|
|
76
|
+
"tsdown": "^0.22.1",
|
|
77
77
|
"typescript": "^5.6.3",
|
|
78
|
-
"vitest": "^4.
|
|
78
|
+
"vitest": "^4.1.7",
|
|
79
79
|
"zod": "^4.0.0"
|
|
80
80
|
},
|
|
81
81
|
"scripts": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"aDBClient-CH-ZcOaP.js","names":["overrides: AdapterOverrides","dialect: Dialect","overrides: DBClientOverrides","_sql: string","_params?: readonly unknown[]","_name: string","client: DBClient","sql: string","params?: readonly unknown[]","name: string"],"sources":["../src/mocks/anAdapter.ts","../src/mocks/aDBClient.ts"],"sourcesContent":["import { PostgresAdapter, SqliteAdapter, type Adapter } from '@danceroutine/tango-orm';\nimport type { Dialect } from '@danceroutine/tango-orm/query';\n\nexport type AdapterOverrides = {\n dialect?: Dialect;\n};\n\n/**\n * Create a real built-in `Adapter` instance for unit tests that need one.\n *\n * Defaults to a Postgres adapter; pass `{ dialect: 'sqlite' }` to obtain a\n * SQLite adapter. The returned adapter carries the matching placeholder\n * formatter so compilers exercised under test emit dialect-accurate SQL.\n */\nexport function anAdapter(overrides: AdapterOverrides = {}): Adapter {\n const dialect: Dialect = overrides.dialect ?? 'postgres';\n switch (dialect) {\n case 'postgres':\n return new PostgresAdapter();\n case 'sqlite':\n return new SqliteAdapter();\n default:\n throw new Error(`Unsupported dialect: ${dialect}`);\n }\n}\n","import { vi } from 'vitest';\nimport type { DBClient } from './DBClient';\n\n/**\n * Looser override type for `aDBClient` that accepts concrete-typed query mocks.\n * Consumers should not need to cast their mocks to satisfy `DBClient['query']`'s generic.\n */\ntype DBClientOverrides = {\n // oxlint-disable-next-line typescript/no-explicit-any\n query?: (sql: string, params?: readonly unknown[]) => Promise<{ rows: any[] }>;\n begin?: () => Promise<void>;\n commit?: () => Promise<void>;\n rollback?: () => Promise<void>;\n close?: () => Promise<void>;\n createSavepoint?: (name: string) => Promise<void>;\n releaseSavepoint?: (name: string) => Promise<void>;\n rollbackToSavepoint?: (name: string) => Promise<void>;\n};\n\n/**\n * Create a lightweight `DBClient` test double with optional behavior overrides.\n * The `query` override accepts any function returning `Promise<{ rows: any[] }>`,\n * so concrete-typed Vitest mocks do not require a cast at the call site.\n */\nexport function aDBClient(overrides: DBClientOverrides = {}): DBClient {\n const queryImpl =\n // oxlint-disable-next-line typescript/no-explicit-any\n overrides.query ?? (async (_sql: string, _params?: readonly unknown[]) => ({ rows: [] as any[] }));\n const beginImpl = overrides.begin ?? (async () => {});\n const commitImpl = overrides.commit ?? (async () => {});\n const rollbackImpl = overrides.rollback ?? (async () => {});\n const closeImpl = overrides.close ?? (async () => {});\n const createSavepointImpl = overrides.createSavepoint ?? (async (_name: string) => {});\n const releaseSavepointImpl = overrides.releaseSavepoint ?? (async (_name: string) => {});\n const rollbackToSavepointImpl = overrides.rollbackToSavepoint ?? (async (_name: string) => {});\n\n const client: DBClient = {\n query: vi.fn((sql: string, params?: readonly unknown[]) => queryImpl(sql, params)) as DBClient['query'],\n begin: vi.fn(() => beginImpl()),\n commit: vi.fn(() => commitImpl()),\n rollback: vi.fn(() => rollbackImpl()),\n close: vi.fn(() => closeImpl()),\n createSavepoint: vi.fn((name: string) => createSavepointImpl(name)),\n releaseSavepoint: vi.fn((name: string) => releaseSavepointImpl(name)),\n rollbackToSavepoint: vi.fn((name: string) => rollbackToSavepointImpl(name)),\n };\n\n return client;\n}\n"],"mappings":";;;;AAcO,SAAS,UAAUA,YAA8B,CAAE,GAAW;CACjE,MAAMC,UAAmB,UAAU,WAAW;AAC9C,SAAQ,SAAR;AACI,OAAK,WACD,QAAO,IAAI;AACf,OAAK,SACD,QAAO,IAAI;AACf,UACI,OAAM,IAAI,OAAO,uBAAuB,QAAQ;CACvD;AACJ;;;;ACAM,SAAS,UAAUC,YAA+B,CAAE,GAAY;CACnE,MAAM,YAEF,UAAU,UAAU,OAAOC,MAAcC,aAAkC,EAAE,MAAM,CAAE,EAAW;CACpG,MAAM,YAAY,UAAU,UAAU,YAAY,CAAE;CACpD,MAAM,aAAa,UAAU,WAAW,YAAY,CAAE;CACtD,MAAM,eAAe,UAAU,aAAa,YAAY,CAAE;CAC1D,MAAM,YAAY,UAAU,UAAU,YAAY,CAAE;CACpD,MAAM,sBAAsB,UAAU,oBAAoB,OAAOC,UAAkB,CAAE;CACrF,MAAM,uBAAuB,UAAU,qBAAqB,OAAOA,UAAkB,CAAE;CACvF,MAAM,0BAA0B,UAAU,wBAAwB,OAAOA,UAAkB,CAAE;CAE7F,MAAMC,SAAmB;EACrB,OAAO,GAAG,GAAG,CAACC,KAAaC,WAAgC,UAAU,KAAK,OAAO,CAAC;EAClF,OAAO,GAAG,GAAG,MAAM,WAAW,CAAC;EAC/B,QAAQ,GAAG,GAAG,MAAM,YAAY,CAAC;EACjC,UAAU,GAAG,GAAG,MAAM,cAAc,CAAC;EACrC,OAAO,GAAG,GAAG,MAAM,WAAW,CAAC;EAC/B,iBAAiB,GAAG,GAAG,CAACC,SAAiB,oBAAoB,KAAK,CAAC;EACnE,kBAAkB,GAAG,GAAG,CAACA,SAAiB,qBAAqB,KAAK,CAAC;EACrE,qBAAqB,GAAG,GAAG,CAACA,SAAiB,wBAAwB,KAAK,CAAC;CAC9E;AAED,QAAO;AACV"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { GenericModelFactory } from '../factories';
|
|
2
|
-
/**
|
|
3
|
-
* Assertion helpers for Tango models.
|
|
4
|
-
*/
|
|
5
|
-
export declare const assertions: {
|
|
6
|
-
matchesSchema<TModel extends GenericModelFactory<Record<string, unknown>, unknown>>(model: TModel, data: unknown): asserts data is ReturnType<TModel["parse"]>;
|
|
7
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { __export } from "./chunk-BkvOhyD0.js";
|
|
2
|
-
|
|
3
|
-
//#region src/assertions/assertions.ts
|
|
4
|
-
const assertions = { matchesSchema(model, data) {
|
|
5
|
-
model.parse(data);
|
|
6
|
-
} };
|
|
7
|
-
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/assertions/index.ts
|
|
10
|
-
var assertions_exports = {};
|
|
11
|
-
__export(assertions_exports, { assertions: () => assertions });
|
|
12
|
-
|
|
13
|
-
//#endregion
|
|
14
|
-
export { assertions, assertions_exports };
|
|
15
|
-
//# sourceMappingURL=assertions-CCFZ53Y-.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assertions-CCFZ53Y-.js","names":["model: TModel","data: unknown"],"sources":["../src/assertions/assertions.ts","../src/assertions/index.ts"],"sourcesContent":["import type { GenericModelFactory } from '../factories';\n\n/**\n * Assertion helpers for Tango models.\n */\nexport const assertions = {\n matchesSchema<TModel extends GenericModelFactory<Record<string, unknown>, unknown>>(\n model: TModel,\n data: unknown\n ): asserts data is ReturnType<TModel['parse']> {\n model.parse(data);\n },\n};\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { assertions } from './assertions';\n"],"mappings":";;;MAKa,aAAa,EACtB,cACIA,OACAC,MAC2C;AAC3C,OAAM,MAAM,KAAK;AACpB,EACJ"}
|
package/dist/chunk-BkvOhyD0.js
DELETED