@forklaunch/testing 0.0.1
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/LICENSE +21 -0
- package/lib/index.d.mts +215 -0
- package/lib/index.d.ts +215 -0
- package/lib/index.js +441 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +399 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +60 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BlueprintTestHarness: () => BlueprintTestHarness,
|
|
34
|
+
TEST_TOKENS: () => TEST_TOKENS,
|
|
35
|
+
TestContainerManager: () => TestContainerManager,
|
|
36
|
+
clearTestDatabase: () => clearTestDatabase,
|
|
37
|
+
setupTestEnvironment: () => setupTestEnvironment,
|
|
38
|
+
setupTestORM: () => setupTestORM
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
|
|
42
|
+
// src/containers.ts
|
|
43
|
+
var import_testcontainers = require("testcontainers");
|
|
44
|
+
var TestContainerManager = class {
|
|
45
|
+
containers = [];
|
|
46
|
+
/**
|
|
47
|
+
* Setup database container based on type
|
|
48
|
+
*/
|
|
49
|
+
async setupDatabaseContainer(type, config = {}) {
|
|
50
|
+
const normalizedType = this.normalizeDatabaseType(type);
|
|
51
|
+
switch (normalizedType) {
|
|
52
|
+
case "postgres":
|
|
53
|
+
return this.setupPostgresContainer(config);
|
|
54
|
+
case "mysql":
|
|
55
|
+
return this.setupMySQLContainer(config);
|
|
56
|
+
case "mongodb":
|
|
57
|
+
return this.setupMongoDBContainer(config);
|
|
58
|
+
case "mssql":
|
|
59
|
+
return this.setupMSSQLContainer(config);
|
|
60
|
+
case "sqlite":
|
|
61
|
+
return null;
|
|
62
|
+
default:
|
|
63
|
+
throw new Error(`Unsupported database type: ${type}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalize database type aliases
|
|
68
|
+
*/
|
|
69
|
+
normalizeDatabaseType(type) {
|
|
70
|
+
switch (type) {
|
|
71
|
+
case "postgres":
|
|
72
|
+
case "postgresql":
|
|
73
|
+
return "postgres";
|
|
74
|
+
case "mysql":
|
|
75
|
+
case "mariadb":
|
|
76
|
+
return "mysql";
|
|
77
|
+
case "mongodb":
|
|
78
|
+
case "mongo":
|
|
79
|
+
return "mongodb";
|
|
80
|
+
case "mssql":
|
|
81
|
+
return "mssql";
|
|
82
|
+
case "sqlite":
|
|
83
|
+
case "better-sqlite":
|
|
84
|
+
case "libsql":
|
|
85
|
+
return "sqlite";
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Unknown database type: ${type}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Setup PostgreSQL test container
|
|
92
|
+
*/
|
|
93
|
+
async setupPostgresContainer(config = {}) {
|
|
94
|
+
const {
|
|
95
|
+
user = "test_user",
|
|
96
|
+
password = "test_password",
|
|
97
|
+
database = "test_db",
|
|
98
|
+
command = ["postgres", "-c", "log_statement=all"]
|
|
99
|
+
} = config;
|
|
100
|
+
const container = await new import_testcontainers.GenericContainer("postgres:latest").withExposedPorts(5432).withEnvironment({
|
|
101
|
+
POSTGRES_USER: user,
|
|
102
|
+
POSTGRES_PASSWORD: password,
|
|
103
|
+
POSTGRES_DB: database
|
|
104
|
+
}).withCommand(command).start();
|
|
105
|
+
this.containers.push(container);
|
|
106
|
+
return container;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Setup MySQL test container
|
|
110
|
+
*/
|
|
111
|
+
async setupMySQLContainer(config = {}) {
|
|
112
|
+
const {
|
|
113
|
+
user = "test_user",
|
|
114
|
+
password = "test_password",
|
|
115
|
+
database = "test_db",
|
|
116
|
+
rootPassword = "root_password"
|
|
117
|
+
} = config;
|
|
118
|
+
const container = await new import_testcontainers.GenericContainer("mysql:8").withExposedPorts(3306).withEnvironment({
|
|
119
|
+
MYSQL_ROOT_PASSWORD: rootPassword,
|
|
120
|
+
MYSQL_DATABASE: database,
|
|
121
|
+
MYSQL_USER: user,
|
|
122
|
+
MYSQL_PASSWORD: password
|
|
123
|
+
}).start();
|
|
124
|
+
this.containers.push(container);
|
|
125
|
+
return container;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Setup MongoDB test container
|
|
129
|
+
*/
|
|
130
|
+
async setupMongoDBContainer(config = {}) {
|
|
131
|
+
const {
|
|
132
|
+
user = "test_user",
|
|
133
|
+
password = "test_password",
|
|
134
|
+
database = "test_db"
|
|
135
|
+
} = config;
|
|
136
|
+
const container = await new import_testcontainers.GenericContainer("mongo:latest").withExposedPorts(27017).withEnvironment({
|
|
137
|
+
MONGO_INITDB_ROOT_USERNAME: user,
|
|
138
|
+
MONGO_INITDB_ROOT_PASSWORD: password,
|
|
139
|
+
MONGO_INITDB_DATABASE: database
|
|
140
|
+
}).start();
|
|
141
|
+
this.containers.push(container);
|
|
142
|
+
return container;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Setup Microsoft SQL Server test container
|
|
146
|
+
*/
|
|
147
|
+
async setupMSSQLContainer(config = {}) {
|
|
148
|
+
const {
|
|
149
|
+
user = "SA",
|
|
150
|
+
password = "Test_Password123!",
|
|
151
|
+
database = "test_db",
|
|
152
|
+
saPassword = "Test_Password123!"
|
|
153
|
+
} = config;
|
|
154
|
+
const container = await new import_testcontainers.GenericContainer(
|
|
155
|
+
"mcr.microsoft.com/mssql/server:2022-latest"
|
|
156
|
+
).withExposedPorts(1433).withEnvironment({
|
|
157
|
+
ACCEPT_EULA: "Y",
|
|
158
|
+
SA_PASSWORD: saPassword,
|
|
159
|
+
MSSQL_PID: "Developer"
|
|
160
|
+
}).start();
|
|
161
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
162
|
+
this.containers.push(container);
|
|
163
|
+
return container;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Setup Redis test container
|
|
167
|
+
*/
|
|
168
|
+
async setupRedisContainer(config = {}) {
|
|
169
|
+
const { command = ["redis-server", "--appendonly", "yes"] } = config;
|
|
170
|
+
const container = await new import_testcontainers.GenericContainer("redis:latest").withExposedPorts(6379).withCommand(command).start();
|
|
171
|
+
this.containers.push(container);
|
|
172
|
+
return container;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Cleanup all containers
|
|
176
|
+
*/
|
|
177
|
+
async cleanup() {
|
|
178
|
+
await Promise.all(
|
|
179
|
+
this.containers.map(
|
|
180
|
+
(container) => container.stop({ remove: true, removeVolumes: true }).catch(() => {
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
);
|
|
184
|
+
this.containers = [];
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/environment.ts
|
|
189
|
+
function getDatabasePort(type) {
|
|
190
|
+
switch (type) {
|
|
191
|
+
case "postgres":
|
|
192
|
+
case "postgresql":
|
|
193
|
+
return 5432;
|
|
194
|
+
case "mysql":
|
|
195
|
+
case "mariadb":
|
|
196
|
+
return 3306;
|
|
197
|
+
case "mongodb":
|
|
198
|
+
case "mongo":
|
|
199
|
+
return 27017;
|
|
200
|
+
case "mssql":
|
|
201
|
+
return 1433;
|
|
202
|
+
case "sqlite":
|
|
203
|
+
case "better-sqlite":
|
|
204
|
+
case "libsql":
|
|
205
|
+
return 0;
|
|
206
|
+
// SQLite is file-based, no port
|
|
207
|
+
default:
|
|
208
|
+
return 5432;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function setupTestEnvironment(config) {
|
|
212
|
+
const {
|
|
213
|
+
database,
|
|
214
|
+
databaseType,
|
|
215
|
+
redis,
|
|
216
|
+
hmacSecret = "test-secret-key",
|
|
217
|
+
customVars = {}
|
|
218
|
+
} = config;
|
|
219
|
+
const dbPort = getDatabasePort(databaseType);
|
|
220
|
+
process.env.DB_NAME = "test_db";
|
|
221
|
+
if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
|
|
222
|
+
process.env.DB_PATH = ":memory:";
|
|
223
|
+
} else if (database) {
|
|
224
|
+
process.env.DB_HOST = database.getHost();
|
|
225
|
+
process.env.DB_USER = databaseType === "mssql" ? "SA" : "test_user";
|
|
226
|
+
process.env.DB_PASSWORD = databaseType === "mssql" ? "Test_Password123!" : "test_password";
|
|
227
|
+
process.env.DB_PORT = database.getMappedPort(dbPort).toString();
|
|
228
|
+
}
|
|
229
|
+
if (redis) {
|
|
230
|
+
process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;
|
|
231
|
+
}
|
|
232
|
+
process.env.HMAC_SECRET_KEY = hmacSecret;
|
|
233
|
+
process.env.JWKS_PUBLIC_KEY_URL = "http://localhost:3000/.well-known/jwks.json";
|
|
234
|
+
process.env.OTEL_SERVICE_NAME = "test-service";
|
|
235
|
+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318";
|
|
236
|
+
process.env.HOST = "localhost";
|
|
237
|
+
process.env.PORT = "3000";
|
|
238
|
+
process.env.NODE_ENV = "test";
|
|
239
|
+
process.env.VERSION = "v1";
|
|
240
|
+
process.env.DOCS_PATH = "/docs";
|
|
241
|
+
process.env.OTEL_LEVEL = "info";
|
|
242
|
+
process.env.DOTENV_FILE_PATH = ".env.test";
|
|
243
|
+
Object.entries(customVars).forEach(([key, value]) => {
|
|
244
|
+
process.env[key] = value;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/database.ts
|
|
249
|
+
var import_core = require("@mikro-orm/core");
|
|
250
|
+
function getDatabasePort2(type) {
|
|
251
|
+
switch (type) {
|
|
252
|
+
case "postgres":
|
|
253
|
+
case "postgresql":
|
|
254
|
+
return 5432;
|
|
255
|
+
case "mysql":
|
|
256
|
+
case "mariadb":
|
|
257
|
+
return 3306;
|
|
258
|
+
case "mongodb":
|
|
259
|
+
case "mongo":
|
|
260
|
+
return 27017;
|
|
261
|
+
case "mssql":
|
|
262
|
+
return 1433;
|
|
263
|
+
case "sqlite":
|
|
264
|
+
case "better-sqlite":
|
|
265
|
+
case "libsql":
|
|
266
|
+
return 0;
|
|
267
|
+
// SQLite is file-based, no port
|
|
268
|
+
default:
|
|
269
|
+
return 5432;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async function setupTestORM(config) {
|
|
273
|
+
const {
|
|
274
|
+
mikroOrmConfigPath,
|
|
275
|
+
databaseType,
|
|
276
|
+
useMigrations = false,
|
|
277
|
+
container
|
|
278
|
+
} = config;
|
|
279
|
+
const { default: mikroOrmConfig } = await import(mikroOrmConfigPath);
|
|
280
|
+
const dbPort = getDatabasePort2(databaseType);
|
|
281
|
+
let ormConfig;
|
|
282
|
+
if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
|
|
283
|
+
ormConfig = {
|
|
284
|
+
...mikroOrmConfig,
|
|
285
|
+
dbName: ":memory:",
|
|
286
|
+
// In-memory SQLite for tests
|
|
287
|
+
debug: false,
|
|
288
|
+
...useMigrations ? {
|
|
289
|
+
migrations: {
|
|
290
|
+
path: config.migrationsPath,
|
|
291
|
+
glob: "!(*.d).{js,ts}",
|
|
292
|
+
dropTables: true
|
|
293
|
+
}
|
|
294
|
+
} : {
|
|
295
|
+
schemaGenerator: {
|
|
296
|
+
createForeignKeyConstraints: false,
|
|
297
|
+
wrap: false
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
} else if (container) {
|
|
302
|
+
ormConfig = {
|
|
303
|
+
...mikroOrmConfig,
|
|
304
|
+
dbName: "test_db",
|
|
305
|
+
host: container.getHost(),
|
|
306
|
+
user: databaseType === "mssql" ? "SA" : "test_user",
|
|
307
|
+
password: databaseType === "mssql" ? "Test_Password123!" : "test_password",
|
|
308
|
+
port: container.getMappedPort(dbPort),
|
|
309
|
+
debug: false,
|
|
310
|
+
...useMigrations ? {
|
|
311
|
+
migrations: {
|
|
312
|
+
path: config.migrationsPath,
|
|
313
|
+
glob: "!(*.d).{js,ts}",
|
|
314
|
+
dropTables: true
|
|
315
|
+
}
|
|
316
|
+
} : {
|
|
317
|
+
schemaGenerator: {
|
|
318
|
+
createForeignKeyConstraints: false,
|
|
319
|
+
wrap: false
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const orm = await import_core.MikroORM.init(ormConfig);
|
|
325
|
+
if (useMigrations) {
|
|
326
|
+
await orm.getMigrator().up();
|
|
327
|
+
} else {
|
|
328
|
+
await orm.getSchemaGenerator().createSchema();
|
|
329
|
+
}
|
|
330
|
+
return orm;
|
|
331
|
+
}
|
|
332
|
+
async function clearTestDatabase(orm, redis) {
|
|
333
|
+
if (redis) {
|
|
334
|
+
await redis.flushall();
|
|
335
|
+
}
|
|
336
|
+
const em = orm.em.fork();
|
|
337
|
+
const entities = Object.values(orm.getMetadata().getAll());
|
|
338
|
+
for (const entity of entities.reverse()) {
|
|
339
|
+
try {
|
|
340
|
+
await em.nativeDelete(entity.class, {});
|
|
341
|
+
} catch (error) {
|
|
342
|
+
if (!error.message?.includes("does not exist")) {
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
await em.flush();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/harness.ts
|
|
351
|
+
var import_ioredis = __toESM(require("ioredis"));
|
|
352
|
+
var BlueprintTestHarness = class {
|
|
353
|
+
constructor(config) {
|
|
354
|
+
this.config = config;
|
|
355
|
+
this.containers = new TestContainerManager();
|
|
356
|
+
}
|
|
357
|
+
containers;
|
|
358
|
+
result;
|
|
359
|
+
/**
|
|
360
|
+
* Setup all test infrastructure (containers, ORM, Redis)
|
|
361
|
+
*/
|
|
362
|
+
async setup() {
|
|
363
|
+
const databaseType = this.config.databaseType || "postgres";
|
|
364
|
+
const container = await this.containers.setupDatabaseContainer(databaseType);
|
|
365
|
+
const redisContainer = this.config.needsRedis ? await this.containers.setupRedisContainer() : void 0;
|
|
366
|
+
setupTestEnvironment({
|
|
367
|
+
database: container,
|
|
368
|
+
databaseType,
|
|
369
|
+
redis: redisContainer,
|
|
370
|
+
customVars: this.config.customEnvVars
|
|
371
|
+
});
|
|
372
|
+
const orm = await setupTestORM({
|
|
373
|
+
mikroOrmConfigPath: this.config.mikroOrmConfigPath,
|
|
374
|
+
databaseType,
|
|
375
|
+
useMigrations: this.config.useMigrations,
|
|
376
|
+
migrationsPath: this.config.migrationsPath,
|
|
377
|
+
container
|
|
378
|
+
});
|
|
379
|
+
let redis;
|
|
380
|
+
if (redisContainer) {
|
|
381
|
+
redis = new import_ioredis.default({
|
|
382
|
+
host: redisContainer.getHost(),
|
|
383
|
+
port: redisContainer.getMappedPort(6379),
|
|
384
|
+
maxRetriesPerRequest: 3
|
|
385
|
+
});
|
|
386
|
+
await redis.ping();
|
|
387
|
+
}
|
|
388
|
+
this.result = { container, redisContainer, orm, redis };
|
|
389
|
+
if (this.config.onSetup) {
|
|
390
|
+
await this.config.onSetup(this.result);
|
|
391
|
+
}
|
|
392
|
+
return this.result;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Cleanup all test infrastructure
|
|
396
|
+
*/
|
|
397
|
+
async cleanup() {
|
|
398
|
+
if (this.result?.redis) {
|
|
399
|
+
await this.result.redis.quit();
|
|
400
|
+
}
|
|
401
|
+
if (this.result?.orm) {
|
|
402
|
+
await this.result.orm.close();
|
|
403
|
+
}
|
|
404
|
+
await this.containers.cleanup();
|
|
405
|
+
this.result = void 0;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Clear all data from the database
|
|
409
|
+
*/
|
|
410
|
+
async clearDatabase() {
|
|
411
|
+
if (this.result) {
|
|
412
|
+
await clearTestDatabase(this.result.orm, this.result.redis);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/tokens.ts
|
|
418
|
+
var TEST_TOKENS = {
|
|
419
|
+
/**
|
|
420
|
+
* Mock Bearer token for testing
|
|
421
|
+
*/
|
|
422
|
+
AUTH: "Bearer test-token",
|
|
423
|
+
/**
|
|
424
|
+
* Mock valid HMAC token for testing
|
|
425
|
+
*/
|
|
426
|
+
HMAC: "HMAC keyId=test-key ts=1234567890 nonce=test-nonce signature=test-signature",
|
|
427
|
+
/**
|
|
428
|
+
* Mock invalid HMAC token for testing authentication failures
|
|
429
|
+
*/
|
|
430
|
+
HMAC_INVALID: "HMAC keyId=invalid-key ts=1234567890 nonce=invalid-nonce signature=invalid-signature"
|
|
431
|
+
};
|
|
432
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
433
|
+
0 && (module.exports = {
|
|
434
|
+
BlueprintTestHarness,
|
|
435
|
+
TEST_TOKENS,
|
|
436
|
+
TestContainerManager,
|
|
437
|
+
clearTestDatabase,
|
|
438
|
+
setupTestEnvironment,
|
|
439
|
+
setupTestORM
|
|
440
|
+
});
|
|
441
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/containers.ts","../src/environment.ts","../src/database.ts","../src/harness.ts","../src/tokens.ts"],"sourcesContent":["/**\n * @forklaunch/testing\n *\n * Testing utilities for forklaunch-js blueprints\n *\n * @packageDocumentation\n */\n\n// Container management\nexport {\n DatabaseConfig,\n DatabaseType,\n MongoDBConfig,\n MSSQLConfig,\n MySQLConfig,\n PostgresConfig,\n RedisConfig,\n SQLiteConfig,\n TestContainerManager\n} from './containers';\n\nexport { setupTestEnvironment, TestEnvConfig } from './environment';\n\nexport {\n clearTestDatabase,\n MikroOrmTestConfig,\n setupTestORM\n} from './database';\n\nexport {\n BlueprintTestConfig,\n BlueprintTestHarness,\n TestSetupResult\n} from './harness';\n\nexport { TEST_TOKENS } from './tokens';\n","import { GenericContainer, StartedTestContainer } from 'testcontainers';\n\nexport type DatabaseType =\n | 'postgres'\n | 'postgresql'\n | 'mysql'\n | 'mariadb'\n | 'mongodb'\n | 'mongo'\n | 'mssql'\n | 'libsql'\n | 'sqlite'\n | 'better-sqlite';\n\nexport interface PostgresConfig {\n user?: string;\n password?: string;\n database?: string;\n command?: string[];\n}\n\nexport interface MySQLConfig {\n user?: string;\n password?: string;\n database?: string;\n rootPassword?: string;\n}\n\nexport interface MongoDBConfig {\n user?: string;\n password?: string;\n database?: string;\n}\n\nexport interface MSSQLConfig {\n user?: string;\n password?: string;\n database?: string;\n saPassword?: string;\n}\n\nexport interface SQLiteConfig {\n database?: string;\n}\n\nexport interface RedisConfig {\n command?: string[];\n}\n\nexport type DatabaseConfig =\n | PostgresConfig\n | MySQLConfig\n | MongoDBConfig\n | MSSQLConfig\n | SQLiteConfig;\n\n/**\n * Manages test containers (PostgreSQL, MySQL, MongoDB, Redis, etc.) for E2E testing\n */\nexport class TestContainerManager {\n private containers: StartedTestContainer[] = [];\n\n /**\n * Setup database container based on type\n */\n async setupDatabaseContainer(\n type: DatabaseType,\n config: DatabaseConfig = {}\n ): Promise<StartedTestContainer | null> {\n const normalizedType = this.normalizeDatabaseType(type);\n\n switch (normalizedType) {\n case 'postgres':\n return this.setupPostgresContainer(config as PostgresConfig);\n case 'mysql':\n return this.setupMySQLContainer(config as MySQLConfig);\n case 'mongodb':\n return this.setupMongoDBContainer(config as MongoDBConfig);\n case 'mssql':\n return this.setupMSSQLContainer(config as MSSQLConfig);\n case 'sqlite':\n // SQLite doesn't need a container (file-based)\n return null;\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n }\n\n /**\n * Normalize database type aliases\n */\n private normalizeDatabaseType(\n type: DatabaseType\n ): 'postgres' | 'mysql' | 'mongodb' | 'mssql' | 'sqlite' {\n switch (type) {\n case 'postgres':\n case 'postgresql':\n return 'postgres';\n case 'mysql':\n case 'mariadb':\n return 'mysql';\n case 'mongodb':\n case 'mongo':\n return 'mongodb';\n case 'mssql':\n return 'mssql';\n case 'sqlite':\n case 'better-sqlite':\n case 'libsql':\n return 'sqlite';\n default:\n throw new Error(`Unknown database type: ${type}`);\n }\n }\n\n /**\n * Setup PostgreSQL test container\n */\n async setupPostgresContainer(\n config: PostgresConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n user = 'test_user',\n password = 'test_password',\n database = 'test_db',\n command = ['postgres', '-c', 'log_statement=all']\n } = config;\n\n const container = await new GenericContainer('postgres:latest')\n .withExposedPorts(5432)\n .withEnvironment({\n POSTGRES_USER: user,\n POSTGRES_PASSWORD: password,\n POSTGRES_DB: database\n })\n .withCommand(command)\n .start();\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MySQL test container\n */\n async setupMySQLContainer(\n config: MySQLConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n user = 'test_user',\n password = 'test_password',\n database = 'test_db',\n rootPassword = 'root_password'\n } = config;\n\n const container = await new GenericContainer('mysql:8')\n .withExposedPorts(3306)\n .withEnvironment({\n MYSQL_ROOT_PASSWORD: rootPassword,\n MYSQL_DATABASE: database,\n MYSQL_USER: user,\n MYSQL_PASSWORD: password\n })\n .start();\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MongoDB test container\n */\n async setupMongoDBContainer(\n config: MongoDBConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n user = 'test_user',\n password = 'test_password',\n database = 'test_db'\n } = config;\n\n const container = await new GenericContainer('mongo:latest')\n .withExposedPorts(27017)\n .withEnvironment({\n MONGO_INITDB_ROOT_USERNAME: user,\n MONGO_INITDB_ROOT_PASSWORD: password,\n MONGO_INITDB_DATABASE: database\n })\n .start();\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup Microsoft SQL Server test container\n */\n async setupMSSQLContainer(\n config: MSSQLConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n user = 'SA',\n password = 'Test_Password123!',\n database = 'test_db',\n saPassword = 'Test_Password123!'\n } = config;\n\n const container = await new GenericContainer(\n 'mcr.microsoft.com/mssql/server:2022-latest'\n )\n .withExposedPorts(1433)\n .withEnvironment({\n ACCEPT_EULA: 'Y',\n SA_PASSWORD: saPassword,\n MSSQL_PID: 'Developer'\n })\n .start();\n\n // Wait a bit for SQL Server to be ready\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup Redis test container\n */\n async setupRedisContainer(\n config: RedisConfig = {}\n ): Promise<StartedTestContainer> {\n const { command = ['redis-server', '--appendonly', 'yes'] } = config;\n\n const container = await new GenericContainer('redis:latest')\n .withExposedPorts(6379)\n .withCommand(command)\n .start();\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Cleanup all containers\n */\n async cleanup(): Promise<void> {\n await Promise.all(\n this.containers.map((container) =>\n container.stop({ remove: true, removeVolumes: true }).catch(() => {\n // Ignore cleanup errors\n })\n )\n );\n this.containers = [];\n }\n}\n","import { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface TestEnvConfig {\n database: StartedTestContainer | null;\n databaseType: DatabaseType;\n redis?: StartedTestContainer;\n hmacSecret?: string;\n customVars?: Record<string, string>;\n}\n\n/**\n * Get the default port for a database type\n */\nfunction getDatabasePort(type: DatabaseType): number {\n switch (type) {\n case 'postgres':\n case 'postgresql':\n return 5432;\n case 'mysql':\n case 'mariadb':\n return 3306;\n case 'mongodb':\n case 'mongo':\n return 27017;\n case 'mssql':\n return 1433;\n case 'sqlite':\n case 'better-sqlite':\n case 'libsql':\n return 0; // SQLite is file-based, no port\n default:\n return 5432;\n }\n}\n\n/**\n * Setup test environment variables for a blueprint test\n */\nexport function setupTestEnvironment(config: TestEnvConfig): void {\n const {\n database,\n databaseType,\n redis,\n hmacSecret = 'test-secret-key',\n customVars = {}\n } = config;\n\n const dbPort = getDatabasePort(databaseType);\n\n // Database environment variables\n process.env.DB_NAME = 'test_db';\n\n // SQLite databases are file-based, no container needed\n if (\n databaseType === 'sqlite' ||\n databaseType === 'better-sqlite' ||\n databaseType === 'libsql'\n ) {\n process.env.DB_PATH = ':memory:'; // In-memory SQLite for tests\n } else if (database) {\n process.env.DB_HOST = database.getHost();\n process.env.DB_USER = databaseType === 'mssql' ? 'SA' : 'test_user';\n process.env.DB_PASSWORD =\n databaseType === 'mssql' ? 'Test_Password123!' : 'test_password';\n process.env.DB_PORT = database.getMappedPort(dbPort).toString();\n }\n\n // Redis environment variables (if provided)\n if (redis) {\n process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;\n }\n\n // Standard test environment variables\n process.env.HMAC_SECRET_KEY = hmacSecret;\n process.env.JWKS_PUBLIC_KEY_URL =\n 'http://localhost:3000/.well-known/jwks.json';\n process.env.OTEL_SERVICE_NAME = 'test-service';\n process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318';\n process.env.HOST = 'localhost';\n process.env.PORT = '3000';\n process.env.NODE_ENV = 'test';\n process.env.VERSION = 'v1';\n process.env.DOCS_PATH = '/docs';\n process.env.OTEL_LEVEL = 'info';\n process.env.DOTENV_FILE_PATH = '.env.test';\n\n // Custom environment variables\n Object.entries(customVars).forEach(([key, value]) => {\n process.env[key] = value;\n });\n}\n","import { MikroORM } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface MikroOrmTestConfig {\n /**\n * Path to the MikroORM config file (e.g., '../mikro-orm.config')\n */\n mikroOrmConfigPath: string;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n */\n databaseType: DatabaseType;\n\n /**\n * Whether to use migrations (true) or schema generation (false)\n * - true: IAM blueprints (uses getMigrator().up())\n * - false: Billing blueprints (uses getSchemaGenerator().createSchema())\n */\n useMigrations?: boolean;\n\n /**\n * Path to migrations directory (required if useMigrations is true)\n */\n migrationsPath?: string;\n\n /**\n * Database container instance (null for file-based databases like SQLite)\n */\n container: StartedTestContainer | null;\n}\n\n/**\n * Get the default port for a database type\n */\nfunction getDatabasePort(type: DatabaseType): number {\n switch (type) {\n case 'postgres':\n case 'postgresql':\n return 5432;\n case 'mysql':\n case 'mariadb':\n return 3306;\n case 'mongodb':\n case 'mongo':\n return 27017;\n case 'mssql':\n return 1433;\n case 'sqlite':\n case 'better-sqlite':\n case 'libsql':\n return 0; // SQLite is file-based, no port\n default:\n return 5432;\n }\n}\n\n/**\n * Setup MikroORM for testing with proper schema/migrations\n */\nexport async function setupTestORM(\n config: MikroOrmTestConfig\n): Promise<MikroORM> {\n const {\n mikroOrmConfigPath,\n databaseType,\n useMigrations = false,\n container\n } = config;\n\n // Dynamically import the MikroORM config\n const { default: mikroOrmConfig } = await import(mikroOrmConfigPath);\n\n const dbPort = getDatabasePort(databaseType);\n\n // SQLite databases are file-based\n let ormConfig: any;\n if (\n databaseType === 'sqlite' ||\n databaseType === 'better-sqlite' ||\n databaseType === 'libsql'\n ) {\n ormConfig = {\n ...mikroOrmConfig,\n dbName: ':memory:', // In-memory SQLite for tests\n debug: false,\n ...(useMigrations\n ? {\n migrations: {\n path: config.migrationsPath,\n glob: '!(*.d).{js,ts}',\n dropTables: true\n }\n }\n : {\n schemaGenerator: {\n createForeignKeyConstraints: false,\n wrap: false\n }\n })\n };\n } else if (container) {\n // Container-based databases\n ormConfig = {\n ...mikroOrmConfig,\n dbName: 'test_db',\n host: container.getHost(),\n user: databaseType === 'mssql' ? 'SA' : 'test_user',\n password:\n databaseType === 'mssql' ? 'Test_Password123!' : 'test_password',\n port: container.getMappedPort(dbPort),\n debug: false,\n ...(useMigrations\n ? {\n migrations: {\n path: config.migrationsPath,\n glob: '!(*.d).{js,ts}',\n dropTables: true\n }\n }\n : {\n schemaGenerator: {\n createForeignKeyConstraints: false,\n wrap: false\n }\n })\n };\n }\n\n const orm = await MikroORM.init(ormConfig);\n\n // Initialize database schema\n if (useMigrations) {\n await orm.getMigrator().up();\n } else {\n await orm.getSchemaGenerator().createSchema();\n }\n\n return orm;\n}\n\n/**\n * Clear all data from the test database\n */\nexport async function clearTestDatabase(\n orm: MikroORM,\n redis?: Redis\n): Promise<void> {\n // Clear Redis if provided\n if (redis) {\n await redis.flushall();\n }\n\n // Clear all database entities\n const em = orm.em.fork();\n const entities = Object.values(orm.getMetadata().getAll());\n\n // Delete in reverse order to avoid foreign key constraints\n for (const entity of entities.reverse()) {\n try {\n await em.nativeDelete(entity.class, {});\n } catch (error) {\n // Ignore \"table does not exist\" errors\n if (!(error as Error).message?.includes('does not exist')) {\n throw error;\n }\n }\n }\n\n await em.flush();\n}\n","import { MikroORM } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType, TestContainerManager } from './containers';\nimport { clearTestDatabase, setupTestORM } from './database';\nimport { setupTestEnvironment } from './environment';\n\nexport interface BlueprintTestConfig {\n /**\n * Path to the MikroORM config file (e.g., '../mikro-orm.config')\n */\n mikroOrmConfigPath: string;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n * @default 'postgres'\n */\n databaseType?: DatabaseType;\n\n /**\n * Whether to use migrations (true) or schema generation (false)\n */\n useMigrations?: boolean;\n\n /**\n * Path to migrations directory (required if useMigrations is true)\n */\n migrationsPath?: string;\n\n /**\n * Whether the blueprint needs Redis\n */\n needsRedis?: boolean;\n\n /**\n * Custom environment variables to set\n */\n customEnvVars?: Record<string, string>;\n\n /**\n * Custom setup hook called after containers and ORM are initialized\n */\n onSetup?: (setup: TestSetupResult) => Promise<void>;\n}\n\nexport interface TestSetupResult {\n container: StartedTestContainer | null;\n redisContainer?: StartedTestContainer;\n orm: MikroORM;\n redis?: Redis;\n}\n\n/**\n * Complete test harness for blueprint E2E testing\n *\n * Handles container setup, environment configuration, and database initialization\n *\n * @example\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * mikroOrmConfigPath: '../mikro-orm.config',\n * useMigrations: false,\n * needsRedis: true,\n * customEnvVars: {\n * STRIPE_API_KEY: 'sk_test_...'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // ... run tests\n * await harness.cleanup();\n * ```\n */\nexport class BlueprintTestHarness {\n private containers: TestContainerManager;\n private result?: TestSetupResult;\n\n constructor(private config: BlueprintTestConfig) {\n this.containers = new TestContainerManager();\n }\n\n /**\n * Setup all test infrastructure (containers, ORM, Redis)\n */\n async setup(): Promise<TestSetupResult> {\n const databaseType = this.config.databaseType || 'postgres';\n\n // Setup database container\n const container =\n await this.containers.setupDatabaseContainer(databaseType);\n\n // Setup Redis container if needed\n const redisContainer = this.config.needsRedis\n ? await this.containers.setupRedisContainer()\n : undefined;\n\n // Setup environment variables\n setupTestEnvironment({\n database: container,\n databaseType,\n redis: redisContainer,\n customVars: this.config.customEnvVars\n });\n\n // Setup ORM\n const orm = await setupTestORM({\n mikroOrmConfigPath: this.config.mikroOrmConfigPath,\n databaseType,\n useMigrations: this.config.useMigrations,\n migrationsPath: this.config.migrationsPath,\n container\n });\n\n // Setup Redis client if needed\n let redis: Redis | undefined;\n if (redisContainer) {\n redis = new Redis({\n host: redisContainer.getHost(),\n port: redisContainer.getMappedPort(6379),\n maxRetriesPerRequest: 3\n });\n await redis.ping();\n }\n\n this.result = { container, redisContainer, orm, redis };\n\n // Call custom setup hook\n if (this.config.onSetup) {\n await this.config.onSetup(this.result);\n }\n\n return this.result;\n }\n\n /**\n * Cleanup all test infrastructure\n */\n async cleanup(): Promise<void> {\n if (this.result?.redis) {\n await this.result.redis.quit();\n }\n if (this.result?.orm) {\n await this.result.orm.close();\n }\n await this.containers.cleanup();\n this.result = undefined;\n }\n\n /**\n * Clear all data from the database\n */\n async clearDatabase(): Promise<void> {\n if (this.result) {\n await clearTestDatabase(this.result.orm, this.result.redis);\n }\n }\n}\n","/**\n * Standard mock authentication tokens for testing\n */\nexport const TEST_TOKENS = {\n /**\n * Mock Bearer token for testing\n */\n AUTH: 'Bearer test-token',\n\n /**\n * Mock valid HMAC token for testing\n */\n HMAC: 'HMAC keyId=test-key ts=1234567890 nonce=test-nonce signature=test-signature',\n\n /**\n * Mock invalid HMAC token for testing authentication failures\n */\n HMAC_INVALID:\n 'HMAC keyId=invalid-key ts=1234567890 nonce=invalid-nonce signature=invalid-signature'\n} as const;\n\n"],"mappings":"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","names":["getDatabasePort","Redis"]}
|