@forklaunch/testing 0.0.29 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import { StartedTestContainer } from 'testcontainers';
2
2
  import { Options, MikroORM } from '@mikro-orm/core';
3
3
  import Redis from 'ioredis';
4
4
 
5
- type DatabaseType = 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'mongo' | 'mssql' | 'libsql' | 'sqlite' | 'better-sqlite';
5
+ type DatabaseType = 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'mongo' | 'mssql' | 'libsql' | 'sqlite';
6
6
  interface PostgresConfig {
7
7
  user?: string;
8
8
  password?: string;
@@ -125,8 +125,8 @@ interface MikroOrmTestConfig {
125
125
  databaseType: DatabaseType;
126
126
  /**
127
127
  * Whether to use migrations (true) or schema generation (false)
128
- * - true: IAM blueprints (uses getMigrator().up())
129
- * - false: Billing blueprints (uses getSchemaGenerator().createSchema())
128
+ * - true: IAM blueprints (uses orm.migrator.up())
129
+ * - false: Billing blueprints (uses orm.schema.create())
130
130
  */
131
131
  useMigrations?: boolean;
132
132
  /**
package/lib/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { StartedTestContainer } from 'testcontainers';
2
2
  import { Options, MikroORM } from '@mikro-orm/core';
3
3
  import Redis from 'ioredis';
4
4
 
5
- type DatabaseType = 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'mongo' | 'mssql' | 'libsql' | 'sqlite' | 'better-sqlite';
5
+ type DatabaseType = 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'mongo' | 'mssql' | 'libsql' | 'sqlite';
6
6
  interface PostgresConfig {
7
7
  user?: string;
8
8
  password?: string;
@@ -125,8 +125,8 @@ interface MikroOrmTestConfig {
125
125
  databaseType: DatabaseType;
126
126
  /**
127
127
  * Whether to use migrations (true) or schema generation (false)
128
- * - true: IAM blueprints (uses getMigrator().up())
129
- * - false: Billing blueprints (uses getSchemaGenerator().createSchema())
128
+ * - true: IAM blueprints (uses orm.migrator.up())
129
+ * - false: Billing blueprints (uses orm.schema.create())
130
130
  */
131
131
  useMigrations?: boolean;
132
132
  /**
package/lib/index.js CHANGED
@@ -80,7 +80,6 @@ var TestContainerManager = class {
80
80
  case "mssql":
81
81
  return "mssql";
82
82
  case "sqlite":
83
- case "better-sqlite":
84
83
  case "libsql":
85
84
  return "sqlite";
86
85
  default:
@@ -271,7 +270,6 @@ function getDatabasePort(type) {
271
270
  case "mssql":
272
271
  return 1433;
273
272
  case "sqlite":
274
- case "better-sqlite":
275
273
  case "libsql":
276
274
  return 0;
277
275
  // SQLite is file-based, no port
@@ -292,7 +290,7 @@ function setupTestEnvironment(config) {
292
290
  if (databaseType) {
293
291
  const dbPort = getDatabasePort(databaseType);
294
292
  process.env.DB_NAME = "test_db";
295
- if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
293
+ if (databaseType === "sqlite" || databaseType === "libsql") {
296
294
  process.env.DB_PATH = ":memory:";
297
295
  } else if (database) {
298
296
  process.env.DB_HOST = database.getHost();
@@ -352,7 +350,6 @@ function getDatabasePort2(type) {
352
350
  case "mssql":
353
351
  return 1433;
354
352
  case "sqlite":
355
- case "better-sqlite":
356
353
  case "libsql":
357
354
  return 0;
358
355
  // SQLite is file-based, no port
@@ -369,7 +366,7 @@ async function setupTestORM(config) {
369
366
  } = config;
370
367
  const dbPort = getDatabasePort2(databaseType);
371
368
  let ormConfig = {};
372
- if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
369
+ if (databaseType === "sqlite" || databaseType === "libsql") {
373
370
  ormConfig = {
374
371
  ...mikroOrmConfig,
375
372
  dbName: ":memory:",
@@ -411,9 +408,9 @@ async function setupTestORM(config) {
411
408
  }
412
409
  const orm = await import_core.MikroORM.init(ormConfig);
413
410
  if (useMigrations) {
414
- await orm.getMigrator().up();
411
+ await orm.migrator.up();
415
412
  } else {
416
- await orm.getSchemaGenerator().createSchema();
413
+ await orm.schema.create();
417
414
  }
418
415
  return orm;
419
416
  }
package/lib/index.js.map CHANGED
@@ -1 +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 KafkaConfig,\n MongoDBConfig,\n MSSQLConfig,\n MySQLConfig,\n PostgresConfig,\n RedisConfig,\n S3Config,\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 interface KafkaConfig {\n /** Kafka cluster ID */\n clusterId?: string;\n /** Number of partitions */\n numPartitions?: number;\n /** Replication factor */\n replicationFactor?: number;\n /** Additional environment variables */\n env?: Record<string, string>;\n}\n\nexport interface S3Config {\n /** MinIO root user (access key) */\n rootUser?: string;\n /** MinIO root password (secret key) */\n rootPassword?: string;\n /** Default bucket to create */\n defaultBucket?: string;\n /** Region */\n region?: 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 // eslint-disable-next-line @typescript-eslint/no-unused-vars\n user = 'SA',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n password = 'Test_Password123!',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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 * Setup Kafka test container\n */\n async setupKafkaContainer(\n config: KafkaConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n clusterId = 'test-cluster',\n numPartitions = 1,\n replicationFactor = 1,\n env = {}\n } = config;\n\n const container = await new GenericContainer('confluentinc/cp-kafka:latest')\n .withExposedPorts(9092, 9093)\n .withEnvironment({\n KAFKA_BROKER_ID: '1',\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:\n 'PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT',\n KAFKA_ADVERTISED_LISTENERS:\n 'PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092',\n KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: replicationFactor.toString(),\n KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: '1',\n KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: '1',\n KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: '0',\n KAFKA_NUM_PARTITIONS: numPartitions.toString(),\n KAFKA_CLUSTER_ID: clusterId,\n KAFKA_PROCESS_ROLES: 'broker,controller',\n KAFKA_NODE_ID: '1',\n KAFKA_CONTROLLER_QUORUM_VOTERS: '1@localhost:9093',\n KAFKA_LISTENERS:\n 'PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:9092',\n KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT',\n KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER',\n KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs',\n ...env\n })\n .start();\n\n // Wait for Kafka to be ready\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MinIO (S3-compatible) test container\n */\n async setupS3Container(config: S3Config = {}): Promise<StartedTestContainer> {\n const {\n rootUser = 'minioadmin',\n rootPassword = 'minioadmin',\n defaultBucket = 'test-bucket',\n region = 'us-east-1'\n } = config;\n\n const container = await new GenericContainer('minio/minio:latest')\n .withExposedPorts(9000, 9001)\n .withEnvironment({\n MINIO_ROOT_USER: rootUser,\n MINIO_ROOT_PASSWORD: rootPassword,\n MINIO_REGION: region\n })\n .withCommand(['server', '/data', '--console-address', ':9001'])\n .start();\n\n // Wait for MinIO to be ready\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Create default bucket if specified\n if (defaultBucket) {\n try {\n // Using MinIO client command via exec\n await container.exec([\n 'mc',\n 'alias',\n 'set',\n 'local',\n 'http://localhost:9000',\n rootUser,\n rootPassword\n ]);\n await container.exec(['mc', 'mb', `local/${defaultBucket}`]);\n } catch (error) {\n // Bucket creation might fail, but container is still usable\n console.warn('Could not create default bucket:', error);\n }\n }\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 kafka?: StartedTestContainer;\n s3?: 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 kafka,\n s3,\n hmacSecret = 'test-secret-key',\n customVars = {}\n } = config;\n\n if (databaseType) {\n const dbPort = getDatabasePort(databaseType);\n\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\n if (redis) {\n process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;\n process.env.REDIS_HOST = redis.getHost();\n process.env.REDIS_PORT = redis.getMappedPort(6379).toString();\n }\n\n if (kafka) {\n const kafkaBroker = `${kafka.getHost()}:${kafka.getMappedPort(9092)}`;\n process.env.KAFKA_BROKERS = kafkaBroker;\n process.env.KAFKA_CLIENT_ID = 'test-client';\n process.env.KAFKA_GROUP_ID = 'test-group';\n }\n\n if (s3) {\n process.env.S3_ENDPOINT = `http://${s3.getHost()}:${s3.getMappedPort(9000)}`;\n process.env.S3_ACCESS_KEY_ID = 'minioadmin';\n process.env.S3_SECRET_ACCESS_KEY = 'minioadmin';\n process.env.S3_REGION = 'us-east-1';\n process.env.S3_BUCKET = 'test-bucket';\n process.env.S3_FORCE_PATH_STYLE = 'true'; // Required for MinIO\n }\n\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, Options } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface MikroOrmTestConfig {\n /**\n * MikroORM config object (imported from mikro-orm.config)\n */\n mikroOrmConfig: Options;\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 mikroOrmConfig,\n databaseType,\n useMigrations = false,\n container\n } = config;\n\n const dbPort = getDatabasePort(databaseType);\n\n // SQLite databases are file-based\n let ormConfig: Options = {};\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 }\n })\n };\n } else if (container) {\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 }\n })\n };\n }\n\n const orm = await MikroORM.init(ormConfig);\n\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 and/or cache\n */\nexport async function clearTestDatabase(options?: {\n orm?: MikroORM;\n redis?: Redis;\n}): Promise<void> {\n const { orm, redis } = options || {};\n\n if (redis) {\n await redis.flushall();\n }\n\n if (orm) {\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}\n","import { MikroORM, Options } 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 * Function that imports and returns the MikroORM config\n * This is called AFTER environment variables are set\n * Optional - if not provided, no database will be set up\n */\n getConfig?: () => Promise<Options>;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n * Optional - if not provided, no database will be set up\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 * Whether the blueprint needs Kafka\n */\n needsKafka?: boolean;\n\n /**\n * Whether the blueprint needs S3 (MinIO)\n */\n needsS3?: boolean;\n\n /**\n * S3 bucket name to create (default: 'test-bucket')\n */\n s3Bucket?: string;\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 kafkaContainer?: StartedTestContainer;\n s3Container?: 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 Database with ORM\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\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 with setup.orm and setup.redis\n * await harness.cleanup();\n * ```\n *\n * @example Cache-only (no database)\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * needsRedis: true,\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // ... run tests with setup.redis only (setup.orm is undefined)\n * await harness.cleanup();\n * ```\n *\n * @example With Kafka and S3\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\n * needsKafka: true,\n * needsS3: true,\n * s3Bucket: 'my-test-bucket',\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // Access containers via setup.kafkaContainer and setup.s3Container\n * // Kafka broker: process.env.KAFKA_BROKERS\n * // S3 endpoint: process.env.S3_ENDPOINT\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, Kafka, S3)\n */\n async setup(): Promise<TestSetupResult> {\n // Setup database container only if database is needed\n let container: StartedTestContainer | null = null;\n let orm: MikroORM | undefined;\n let redisContainer: StartedTestContainer | undefined;\n let kafkaContainer: StartedTestContainer | undefined;\n let s3Container: StartedTestContainer | undefined;\n\n // Setup Redis container if needed (for both database and cache-only modes)\n if (this.config.needsRedis) {\n redisContainer = await this.containers.setupRedisContainer();\n }\n\n // Setup Kafka container if needed\n if (this.config.needsKafka) {\n kafkaContainer = await this.containers.setupKafkaContainer();\n }\n\n // Setup S3 container if needed\n if (this.config.needsS3) {\n s3Container = await this.containers.setupS3Container({\n defaultBucket: this.config.s3Bucket\n });\n }\n\n if (this.config.databaseType && this.config.getConfig) {\n const databaseType = this.config.databaseType;\n\n // Setup database container\n container = await this.containers.setupDatabaseContainer(databaseType);\n\n // Setup environment variables\n setupTestEnvironment({\n database: container,\n databaseType,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\n\n // Get the config AFTER environment is set\n const mikroOrmConfig = await this.config.getConfig();\n\n // Setup ORM\n orm = await setupTestORM({\n mikroOrmConfig,\n databaseType,\n useMigrations: this.config.useMigrations,\n migrationsPath: this.config.migrationsPath,\n container\n });\n } else {\n // Cache-only mode: no database\n setupTestEnvironment({\n database: null,\n databaseType: undefined,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\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 = {\n container,\n redisContainer,\n kafkaContainer,\n s3Container,\n orm,\n redis\n };\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 and/or cache\n */\n async clearDatabase(): Promise<void> {\n if (this.result) {\n await clearTestDatabase({\n orm: this.result.orm,\n redis: this.result.redis\n });\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"],"mappings":"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","names":["getDatabasePort","Redis"]}
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 KafkaConfig,\n MongoDBConfig,\n MSSQLConfig,\n MySQLConfig,\n PostgresConfig,\n RedisConfig,\n S3Config,\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\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 interface KafkaConfig {\n /** Kafka cluster ID */\n clusterId?: string;\n /** Number of partitions */\n numPartitions?: number;\n /** Replication factor */\n replicationFactor?: number;\n /** Additional environment variables */\n env?: Record<string, string>;\n}\n\nexport interface S3Config {\n /** MinIO root user (access key) */\n rootUser?: string;\n /** MinIO root password (secret key) */\n rootPassword?: string;\n /** Default bucket to create */\n defaultBucket?: string;\n /** Region */\n region?: 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 '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 // eslint-disable-next-line @typescript-eslint/no-unused-vars\n user = 'SA',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n password = 'Test_Password123!',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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 * Setup Kafka test container\n */\n async setupKafkaContainer(\n config: KafkaConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n clusterId = 'test-cluster',\n numPartitions = 1,\n replicationFactor = 1,\n env = {}\n } = config;\n\n const container = await new GenericContainer('confluentinc/cp-kafka:latest')\n .withExposedPorts(9092, 9093)\n .withEnvironment({\n KAFKA_BROKER_ID: '1',\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:\n 'PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT',\n KAFKA_ADVERTISED_LISTENERS:\n 'PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092',\n KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: replicationFactor.toString(),\n KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: '1',\n KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: '1',\n KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: '0',\n KAFKA_NUM_PARTITIONS: numPartitions.toString(),\n KAFKA_CLUSTER_ID: clusterId,\n KAFKA_PROCESS_ROLES: 'broker,controller',\n KAFKA_NODE_ID: '1',\n KAFKA_CONTROLLER_QUORUM_VOTERS: '1@localhost:9093',\n KAFKA_LISTENERS:\n 'PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:9092',\n KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT',\n KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER',\n KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs',\n ...env\n })\n .start();\n\n // Wait for Kafka to be ready\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MinIO (S3-compatible) test container\n */\n async setupS3Container(config: S3Config = {}): Promise<StartedTestContainer> {\n const {\n rootUser = 'minioadmin',\n rootPassword = 'minioadmin',\n defaultBucket = 'test-bucket',\n region = 'us-east-1'\n } = config;\n\n const container = await new GenericContainer('minio/minio:latest')\n .withExposedPorts(9000, 9001)\n .withEnvironment({\n MINIO_ROOT_USER: rootUser,\n MINIO_ROOT_PASSWORD: rootPassword,\n MINIO_REGION: region\n })\n .withCommand(['server', '/data', '--console-address', ':9001'])\n .start();\n\n // Wait for MinIO to be ready\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Create default bucket if specified\n if (defaultBucket) {\n try {\n // Using MinIO client command via exec\n await container.exec([\n 'mc',\n 'alias',\n 'set',\n 'local',\n 'http://localhost:9000',\n rootUser,\n rootPassword\n ]);\n await container.exec(['mc', 'mb', `local/${defaultBucket}`]);\n } catch (error) {\n // Bucket creation might fail, but container is still usable\n console.warn('Could not create default bucket:', error);\n }\n }\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 kafka?: StartedTestContainer;\n s3?: 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 '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 kafka,\n s3,\n hmacSecret = 'test-secret-key',\n customVars = {}\n } = config;\n\n if (databaseType) {\n const dbPort = getDatabasePort(databaseType);\n\n process.env.DB_NAME = 'test_db';\n\n // SQLite databases are file-based, no container needed\n if (databaseType === 'sqlite' || databaseType === 'libsql') {\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\n if (redis) {\n process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;\n process.env.REDIS_HOST = redis.getHost();\n process.env.REDIS_PORT = redis.getMappedPort(6379).toString();\n }\n\n if (kafka) {\n const kafkaBroker = `${kafka.getHost()}:${kafka.getMappedPort(9092)}`;\n process.env.KAFKA_BROKERS = kafkaBroker;\n process.env.KAFKA_CLIENT_ID = 'test-client';\n process.env.KAFKA_GROUP_ID = 'test-group';\n }\n\n if (s3) {\n process.env.S3_ENDPOINT = `http://${s3.getHost()}:${s3.getMappedPort(9000)}`;\n process.env.S3_ACCESS_KEY_ID = 'minioadmin';\n process.env.S3_SECRET_ACCESS_KEY = 'minioadmin';\n process.env.S3_REGION = 'us-east-1';\n process.env.S3_BUCKET = 'test-bucket';\n process.env.S3_FORCE_PATH_STYLE = 'true'; // Required for MinIO\n }\n\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, Options } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface MikroOrmTestConfig {\n /**\n * MikroORM config object (imported from mikro-orm.config)\n */\n mikroOrmConfig: Options;\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 orm.migrator.up())\n * - false: Billing blueprints (uses orm.schema.create())\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 '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 mikroOrmConfig,\n databaseType,\n useMigrations = false,\n container\n } = config;\n\n const dbPort = getDatabasePort(databaseType);\n\n // SQLite databases are file-based\n let ormConfig = {} as Options;\n if (databaseType === 'sqlite' || databaseType === 'libsql') {\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 }\n })\n };\n } else if (container) {\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 }\n })\n };\n }\n\n const orm = await MikroORM.init(ormConfig);\n\n if (useMigrations) {\n await orm.migrator.up();\n } else {\n await orm.schema.create();\n }\n\n return orm;\n}\n\n/**\n * Clear all data from the test database and/or cache\n */\nexport async function clearTestDatabase(options?: {\n orm?: MikroORM;\n redis?: Redis;\n}): Promise<void> {\n const { orm, redis } = options || {};\n\n if (redis) {\n await redis.flushall();\n }\n\n if (orm) {\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}\n","import { MikroORM, Options } 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 * Function that imports and returns the MikroORM config\n * This is called AFTER environment variables are set\n * Optional - if not provided, no database will be set up\n */\n getConfig?: () => Promise<Options>;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n * Optional - if not provided, no database will be set up\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 * Whether the blueprint needs Kafka\n */\n needsKafka?: boolean;\n\n /**\n * Whether the blueprint needs S3 (MinIO)\n */\n needsS3?: boolean;\n\n /**\n * S3 bucket name to create (default: 'test-bucket')\n */\n s3Bucket?: string;\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 kafkaContainer?: StartedTestContainer;\n s3Container?: 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 Database with ORM\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\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 with setup.orm and setup.redis\n * await harness.cleanup();\n * ```\n *\n * @example Cache-only (no database)\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * needsRedis: true,\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // ... run tests with setup.redis only (setup.orm is undefined)\n * await harness.cleanup();\n * ```\n *\n * @example With Kafka and S3\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\n * needsKafka: true,\n * needsS3: true,\n * s3Bucket: 'my-test-bucket',\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // Access containers via setup.kafkaContainer and setup.s3Container\n * // Kafka broker: process.env.KAFKA_BROKERS\n * // S3 endpoint: process.env.S3_ENDPOINT\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, Kafka, S3)\n */\n async setup(): Promise<TestSetupResult> {\n // Setup database container only if database is needed\n let container: StartedTestContainer | null = null;\n let orm: MikroORM | undefined;\n let redisContainer: StartedTestContainer | undefined;\n let kafkaContainer: StartedTestContainer | undefined;\n let s3Container: StartedTestContainer | undefined;\n\n // Setup Redis container if needed (for both database and cache-only modes)\n if (this.config.needsRedis) {\n redisContainer = await this.containers.setupRedisContainer();\n }\n\n // Setup Kafka container if needed\n if (this.config.needsKafka) {\n kafkaContainer = await this.containers.setupKafkaContainer();\n }\n\n // Setup S3 container if needed\n if (this.config.needsS3) {\n s3Container = await this.containers.setupS3Container({\n defaultBucket: this.config.s3Bucket\n });\n }\n\n if (this.config.databaseType && this.config.getConfig) {\n const databaseType = this.config.databaseType;\n\n // Setup database container\n container = await this.containers.setupDatabaseContainer(databaseType);\n\n // Setup environment variables\n setupTestEnvironment({\n database: container,\n databaseType,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\n\n // Get the config AFTER environment is set\n const mikroOrmConfig = await this.config.getConfig();\n\n // Setup ORM\n orm = await setupTestORM({\n mikroOrmConfig,\n databaseType,\n useMigrations: this.config.useMigrations,\n migrationsPath: this.config.migrationsPath,\n container\n });\n } else {\n // Cache-only mode: no database\n setupTestEnvironment({\n database: null,\n databaseType: undefined,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\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 = {\n container,\n redisContainer,\n kafkaContainer,\n s3Container,\n orm,\n redis\n };\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 and/or cache\n */\n async clearDatabase(): Promise<void> {\n if (this.result) {\n await clearTestDatabase({\n orm: this.result.orm,\n redis: this.result.redis\n });\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,4BAAuD;AAgFhD,IAAM,uBAAN,MAA2B;AAAA,EACxB,aAAqC,CAAC;AAAA;AAAA;AAAA;AAAA,EAK9C,MAAM,uBACJ,MACA,SAAyB,CAAC,GACY;AACtC,UAAM,iBAAiB,KAAK,sBAAsB,IAAI;AAEtD,YAAQ,gBAAgB;AAAA,MACtB,KAAK;AACH,eAAO,KAAK,uBAAuB,MAAwB;AAAA,MAC7D,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAqB;AAAA,MACvD,KAAK;AACH,eAAO,KAAK,sBAAsB,MAAuB;AAAA,MAC3D,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAqB;AAAA,MACvD,KAAK;AAEH,eAAO;AAAA,MACT;AACE,cAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,sBACN,MACuD;AACvD,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT;AACE,cAAM,IAAI,MAAM,0BAA0B,IAAI,EAAE;AAAA,IACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,uBACJ,SAAyB,CAAC,GACK;AAC/B,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU,CAAC,YAAY,MAAM,mBAAmB;AAAA,IAClD,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI,uCAAiB,iBAAiB,EAC3D,iBAAiB,IAAI,EACrB,gBAAgB;AAAA,MACf,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,aAAa;AAAA,IACf,CAAC,EACA,YAAY,OAAO,EACnB,MAAM;AAET,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,SAAsB,CAAC,GACQ;AAC/B,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,WAAW;AAAA,MACX,WAAW;AAAA,MACX,eAAe;AAAA,IACjB,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI,uCAAiB,SAAS,EACnD,iBAAiB,IAAI,EACrB,gBAAgB;AAAA,MACf,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,MAChB,YAAY;AAAA,MACZ,gBAAgB;AAAA,IAClB,CAAC,EACA,MAAM;AAET,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,sBACJ,SAAwB,CAAC,GACM;AAC/B,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,WAAW;AAAA,MACX,WAAW;AAAA,IACb,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI,uCAAiB,cAAc,EACxD,iBAAiB,KAAK,EACtB,gBAAgB;AAAA,MACf,4BAA4B;AAAA,MAC5B,4BAA4B;AAAA,MAC5B,uBAAuB;AAAA,IACzB,CAAC,EACA,MAAM;AAET,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,SAAsB,CAAC,GACQ;AAC/B,UAAM;AAAA;AAAA,MAEJ,OAAO;AAAA;AAAA,MAEP,WAAW;AAAA;AAAA,MAEX,WAAW;AAAA,MACX,aAAa;AAAA,IACf,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI;AAAA,MAC1B;AAAA,IACF,EACG,iBAAiB,IAAI,EACrB,gBAAgB;AAAA,MACf,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC,EACA,MAAM;AAGT,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAExD,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,SAAsB,CAAC,GACQ;AAC/B,UAAM,EAAE,UAAU,CAAC,gBAAgB,gBAAgB,KAAK,EAAE,IAAI;AAE9D,UAAM,YAAY,MAAM,IAAI,uCAAiB,cAAc,EACxD,iBAAiB,IAAI,EACrB,YAAY,OAAO,EACnB,MAAM;AAET,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,SAAsB,CAAC,GACQ;AAC/B,UAAM;AAAA,MACJ,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,MACpB,MAAM,CAAC;AAAA,IACT,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI,uCAAiB,8BAA8B,EACxE,iBAAiB,MAAM,IAAI,EAC3B,gBAAgB;AAAA,MACf,iBAAiB;AAAA,MACjB,sCACE;AAAA,MACF,4BACE;AAAA,MACF,wCAAwC,kBAAkB,SAAS;AAAA,MACnE,qCAAqC;AAAA,MACrC,gDAAgD;AAAA,MAChD,wCAAwC;AAAA,MACxC,sBAAsB,cAAc,SAAS;AAAA,MAC7C,kBAAkB;AAAA,MAClB,qBAAqB;AAAA,MACrB,eAAe;AAAA,MACf,gCAAgC;AAAA,MAChC,iBACE;AAAA,MACF,kCAAkC;AAAA,MAClC,iCAAiC;AAAA,MACjC,gBAAgB;AAAA,MAChB,GAAG;AAAA,IACL,CAAC,EACA,MAAM;AAGT,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAExD,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,SAAmB,CAAC,GAAkC;AAC3E,UAAM;AAAA,MACJ,WAAW;AAAA,MACX,eAAe;AAAA,MACf,gBAAgB;AAAA,MAChB,SAAS;AAAA,IACX,IAAI;AAEJ,UAAM,YAAY,MAAM,IAAI,uCAAiB,oBAAoB,EAC9D,iBAAiB,KAAM,IAAI,EAC3B,gBAAgB;AAAA,MACf,iBAAiB;AAAA,MACjB,qBAAqB;AAAA,MACrB,cAAc;AAAA,IAChB,CAAC,EACA,YAAY,CAAC,UAAU,SAAS,qBAAqB,OAAO,CAAC,EAC7D,MAAM;AAGT,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAGxD,QAAI,eAAe;AACjB,UAAI;AAEF,cAAM,UAAU,KAAK;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AACD,cAAM,UAAU,KAAK,CAAC,MAAM,MAAM,SAAS,aAAa,EAAE,CAAC;AAAA,MAC7D,SAAS,OAAO;AAEd,gBAAQ,KAAK,oCAAoC,KAAK;AAAA,MACxD;AAAA,IACF;AAEA,SAAK,WAAW,KAAK,SAAS;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,UAAM,QAAQ;AAAA,MACZ,KAAK,WAAW;AAAA,QAAI,CAAC,cACnB,UAAU,KAAK,EAAE,QAAQ,MAAM,eAAe,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,QAElE,CAAC;AAAA,MACH;AAAA,IACF;AACA,SAAK,aAAa,CAAC;AAAA,EACrB;AACF;;;ACpWA,SAAS,gBAAgB,MAA4B;AACnD,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,qBAAqB,QAA6B;AAChE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,aAAa,CAAC;AAAA,EAChB,IAAI;AAEJ,MAAI,cAAc;AAChB,UAAM,SAAS,gBAAgB,YAAY;AAE3C,YAAQ,IAAI,UAAU;AAGtB,QAAI,iBAAiB,YAAY,iBAAiB,UAAU;AAC1D,cAAQ,IAAI,UAAU;AAAA,IACxB,WAAW,UAAU;AACnB,cAAQ,IAAI,UAAU,SAAS,QAAQ;AACvC,cAAQ,IAAI,UAAU,iBAAiB,UAAU,OAAO;AACxD,cAAQ,IAAI,cACV,iBAAiB,UAAU,sBAAsB;AACnD,cAAQ,IAAI,UAAU,SAAS,cAAc,MAAM,EAAE,SAAS;AAAA,IAChE;AAAA,EACF;AAEA,MAAI,OAAO;AACT,YAAQ,IAAI,YAAY,WAAW,MAAM,QAAQ,CAAC,IAAI,MAAM,cAAc,IAAI,CAAC;AAC/E,YAAQ,IAAI,aAAa,MAAM,QAAQ;AACvC,YAAQ,IAAI,aAAa,MAAM,cAAc,IAAI,EAAE,SAAS;AAAA,EAC9D;AAEA,MAAI,OAAO;AACT,UAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,IAAI,MAAM,cAAc,IAAI,CAAC;AACnE,YAAQ,IAAI,gBAAgB;AAC5B,YAAQ,IAAI,kBAAkB;AAC9B,YAAQ,IAAI,iBAAiB;AAAA,EAC/B;AAEA,MAAI,IAAI;AACN,YAAQ,IAAI,cAAc,UAAU,GAAG,QAAQ,CAAC,IAAI,GAAG,cAAc,GAAI,CAAC;AAC1E,YAAQ,IAAI,mBAAmB;AAC/B,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI,YAAY;AACxB,YAAQ,IAAI,YAAY;AACxB,YAAQ,IAAI,sBAAsB;AAAA,EACpC;AAEA,UAAQ,IAAI,kBAAkB;AAC9B,UAAQ,IAAI,sBACV;AACF,UAAQ,IAAI,oBAAoB;AAChC,UAAQ,IAAI,8BAA8B;AAC1C,UAAQ,IAAI,OAAO;AACnB,UAAQ,IAAI,OAAO;AACnB,UAAQ,IAAI,WAAW;AACvB,UAAQ,IAAI,UAAU;AACtB,UAAQ,IAAI,YAAY;AACxB,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI,mBAAmB;AAG/B,SAAO,QAAQ,UAAU,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACnD,YAAQ,IAAI,GAAG,IAAI;AAAA,EACrB,CAAC;AACH;;;AC3GA,kBAAkC;AAqClC,SAASA,iBAAgB,MAA4B;AACnD,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,eAAsB,aACpB,QACmB;AACnB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,EACF,IAAI;AAEJ,QAAM,SAASA,iBAAgB,YAAY;AAG3C,MAAI,YAAY,CAAC;AACjB,MAAI,iBAAiB,YAAY,iBAAiB,UAAU;AAC1D,gBAAY;AAAA,MACV,GAAG;AAAA,MACH,QAAQ;AAAA;AAAA,MACR,OAAO;AAAA,MACP,GAAI,gBACA;AAAA,QACE,YAAY;AAAA,UACV,MAAM,OAAO;AAAA,UACb,MAAM;AAAA,UACN,YAAY;AAAA,QACd;AAAA,MACF,IACA;AAAA,QACE,iBAAiB;AAAA,UACf,6BAA6B;AAAA,QAC/B;AAAA,MACF;AAAA,IACN;AAAA,EACF,WAAW,WAAW;AACpB,gBAAY;AAAA,MACV,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,MAAM,UAAU,QAAQ;AAAA,MACxB,MAAM,iBAAiB,UAAU,OAAO;AAAA,MACxC,UACE,iBAAiB,UAAU,sBAAsB;AAAA,MACnD,MAAM,UAAU,cAAc,MAAM;AAAA,MACpC,OAAO;AAAA,MACP,GAAI,gBACA;AAAA,QACE,YAAY;AAAA,UACV,MAAM,OAAO;AAAA,UACb,MAAM;AAAA,UACN,YAAY;AAAA,QACd;AAAA,MACF,IACA;AAAA,QACE,iBAAiB;AAAA,UACf,6BAA6B;AAAA,QAC/B;AAAA,MACF;AAAA,IACN;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,qBAAS,KAAK,SAAS;AAEzC,MAAI,eAAe;AACjB,UAAM,IAAI,SAAS,GAAG;AAAA,EACxB,OAAO;AACL,UAAM,IAAI,OAAO,OAAO;AAAA,EAC1B;AAEA,SAAO;AACT;AAKA,eAAsB,kBAAkB,SAGtB;AAChB,QAAM,EAAE,KAAK,MAAM,IAAI,WAAW,CAAC;AAEnC,MAAI,OAAO;AACT,UAAM,MAAM,SAAS;AAAA,EACvB;AAEA,MAAI,KAAK;AACP,UAAM,KAAK,IAAI,GAAG,KAAK;AACvB,UAAM,WAAW,OAAO,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC;AAGzD,eAAW,UAAU,SAAS,QAAQ,GAAG;AACvC,UAAI;AACF,cAAM,GAAG,aAAa,OAAO,OAAO,CAAC,CAAC;AAAA,MACxC,SAAS,OAAO;AAEd,YAAI,CAAE,MAAgB,SAAS,SAAS,gBAAgB,GAAG;AACzD,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,GAAG,MAAM;AAAA,EACjB;AACF;;;ACjKA,qBAAkB;AAoIX,IAAM,uBAAN,MAA2B;AAAA,EAIhC,YAAoB,QAA6B;AAA7B;AAClB,SAAK,aAAa,IAAI,qBAAqB;AAAA,EAC7C;AAAA,EALQ;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EASR,MAAM,QAAkC;AAEtC,QAAI,YAAyC;AAC7C,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AAGJ,QAAI,KAAK,OAAO,YAAY;AAC1B,uBAAiB,MAAM,KAAK,WAAW,oBAAoB;AAAA,IAC7D;AAGA,QAAI,KAAK,OAAO,YAAY;AAC1B,uBAAiB,MAAM,KAAK,WAAW,oBAAoB;AAAA,IAC7D;AAGA,QAAI,KAAK,OAAO,SAAS;AACvB,oBAAc,MAAM,KAAK,WAAW,iBAAiB;AAAA,QACnD,eAAe,KAAK,OAAO;AAAA,MAC7B,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,OAAO,gBAAgB,KAAK,OAAO,WAAW;AACrD,YAAM,eAAe,KAAK,OAAO;AAGjC,kBAAY,MAAM,KAAK,WAAW,uBAAuB,YAAY;AAGrE,2BAAqB;AAAA,QACnB,UAAU;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,IAAI;AAAA,QACJ,YAAY,KAAK,OAAO;AAAA,MAC1B,CAAC;AAGD,YAAM,iBAAiB,MAAM,KAAK,OAAO,UAAU;AAGnD,YAAM,MAAM,aAAa;AAAA,QACvB;AAAA,QACA;AAAA,QACA,eAAe,KAAK,OAAO;AAAA,QAC3B,gBAAgB,KAAK,OAAO;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AAEL,2BAAqB;AAAA,QACnB,UAAU;AAAA,QACV,cAAc;AAAA,QACd,OAAO;AAAA,QACP,OAAO;AAAA,QACP,IAAI;AAAA,QACJ,YAAY,KAAK,OAAO;AAAA,MAC1B,CAAC;AAAA,IACH;AAGA,QAAI;AACJ,QAAI,gBAAgB;AAClB,cAAQ,IAAI,eAAAC,QAAM;AAAA,QAChB,MAAM,eAAe,QAAQ;AAAA,QAC7B,MAAM,eAAe,cAAc,IAAI;AAAA,QACvC,sBAAsB;AAAA,MACxB,CAAC;AACD,YAAM,MAAM,KAAK;AAAA,IACnB;AAEA,SAAK,SAAS;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,QAAI,KAAK,OAAO,SAAS;AACvB,YAAM,KAAK,OAAO,QAAQ,KAAK,MAAM;AAAA,IACvC;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,QAAI,KAAK,QAAQ,OAAO;AACtB,YAAM,KAAK,OAAO,MAAM,KAAK;AAAA,IAC/B;AACA,QAAI,KAAK,QAAQ,KAAK;AACpB,YAAM,KAAK,OAAO,IAAI,MAAM;AAAA,IAC9B;AACA,UAAM,KAAK,WAAW,QAAQ;AAC9B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAA+B;AACnC,QAAI,KAAK,QAAQ;AACf,YAAM,kBAAkB;AAAA,QACtB,KAAK,KAAK,OAAO;AAAA,QACjB,OAAO,KAAK,OAAO;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AClQO,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA,EAIzB,MAAM;AAAA;AAAA;AAAA;AAAA,EAKN,MAAM;AAAA;AAAA;AAAA;AAAA,EAKN,cACE;AACJ;","names":["getDatabasePort","Redis"]}
package/lib/index.mjs CHANGED
@@ -39,7 +39,6 @@ var TestContainerManager = class {
39
39
  case "mssql":
40
40
  return "mssql";
41
41
  case "sqlite":
42
- case "better-sqlite":
43
42
  case "libsql":
44
43
  return "sqlite";
45
44
  default:
@@ -230,7 +229,6 @@ function getDatabasePort(type) {
230
229
  case "mssql":
231
230
  return 1433;
232
231
  case "sqlite":
233
- case "better-sqlite":
234
232
  case "libsql":
235
233
  return 0;
236
234
  // SQLite is file-based, no port
@@ -251,7 +249,7 @@ function setupTestEnvironment(config) {
251
249
  if (databaseType) {
252
250
  const dbPort = getDatabasePort(databaseType);
253
251
  process.env.DB_NAME = "test_db";
254
- if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
252
+ if (databaseType === "sqlite" || databaseType === "libsql") {
255
253
  process.env.DB_PATH = ":memory:";
256
254
  } else if (database) {
257
255
  process.env.DB_HOST = database.getHost();
@@ -311,7 +309,6 @@ function getDatabasePort2(type) {
311
309
  case "mssql":
312
310
  return 1433;
313
311
  case "sqlite":
314
- case "better-sqlite":
315
312
  case "libsql":
316
313
  return 0;
317
314
  // SQLite is file-based, no port
@@ -328,7 +325,7 @@ async function setupTestORM(config) {
328
325
  } = config;
329
326
  const dbPort = getDatabasePort2(databaseType);
330
327
  let ormConfig = {};
331
- if (databaseType === "sqlite" || databaseType === "better-sqlite" || databaseType === "libsql") {
328
+ if (databaseType === "sqlite" || databaseType === "libsql") {
332
329
  ormConfig = {
333
330
  ...mikroOrmConfig,
334
331
  dbName: ":memory:",
@@ -370,9 +367,9 @@ async function setupTestORM(config) {
370
367
  }
371
368
  const orm = await MikroORM.init(ormConfig);
372
369
  if (useMigrations) {
373
- await orm.getMigrator().up();
370
+ await orm.migrator.up();
374
371
  } else {
375
- await orm.getSchemaGenerator().createSchema();
372
+ await orm.schema.create();
376
373
  }
377
374
  return orm;
378
375
  }
package/lib/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/containers.ts","../src/environment.ts","../src/database.ts","../src/harness.ts","../src/tokens.ts"],"sourcesContent":["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 interface KafkaConfig {\n /** Kafka cluster ID */\n clusterId?: string;\n /** Number of partitions */\n numPartitions?: number;\n /** Replication factor */\n replicationFactor?: number;\n /** Additional environment variables */\n env?: Record<string, string>;\n}\n\nexport interface S3Config {\n /** MinIO root user (access key) */\n rootUser?: string;\n /** MinIO root password (secret key) */\n rootPassword?: string;\n /** Default bucket to create */\n defaultBucket?: string;\n /** Region */\n region?: 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 // eslint-disable-next-line @typescript-eslint/no-unused-vars\n user = 'SA',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n password = 'Test_Password123!',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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 * Setup Kafka test container\n */\n async setupKafkaContainer(\n config: KafkaConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n clusterId = 'test-cluster',\n numPartitions = 1,\n replicationFactor = 1,\n env = {}\n } = config;\n\n const container = await new GenericContainer('confluentinc/cp-kafka:latest')\n .withExposedPorts(9092, 9093)\n .withEnvironment({\n KAFKA_BROKER_ID: '1',\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:\n 'PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT',\n KAFKA_ADVERTISED_LISTENERS:\n 'PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092',\n KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: replicationFactor.toString(),\n KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: '1',\n KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: '1',\n KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: '0',\n KAFKA_NUM_PARTITIONS: numPartitions.toString(),\n KAFKA_CLUSTER_ID: clusterId,\n KAFKA_PROCESS_ROLES: 'broker,controller',\n KAFKA_NODE_ID: '1',\n KAFKA_CONTROLLER_QUORUM_VOTERS: '1@localhost:9093',\n KAFKA_LISTENERS:\n 'PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:9092',\n KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT',\n KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER',\n KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs',\n ...env\n })\n .start();\n\n // Wait for Kafka to be ready\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MinIO (S3-compatible) test container\n */\n async setupS3Container(config: S3Config = {}): Promise<StartedTestContainer> {\n const {\n rootUser = 'minioadmin',\n rootPassword = 'minioadmin',\n defaultBucket = 'test-bucket',\n region = 'us-east-1'\n } = config;\n\n const container = await new GenericContainer('minio/minio:latest')\n .withExposedPorts(9000, 9001)\n .withEnvironment({\n MINIO_ROOT_USER: rootUser,\n MINIO_ROOT_PASSWORD: rootPassword,\n MINIO_REGION: region\n })\n .withCommand(['server', '/data', '--console-address', ':9001'])\n .start();\n\n // Wait for MinIO to be ready\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Create default bucket if specified\n if (defaultBucket) {\n try {\n // Using MinIO client command via exec\n await container.exec([\n 'mc',\n 'alias',\n 'set',\n 'local',\n 'http://localhost:9000',\n rootUser,\n rootPassword\n ]);\n await container.exec(['mc', 'mb', `local/${defaultBucket}`]);\n } catch (error) {\n // Bucket creation might fail, but container is still usable\n console.warn('Could not create default bucket:', error);\n }\n }\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 kafka?: StartedTestContainer;\n s3?: 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 kafka,\n s3,\n hmacSecret = 'test-secret-key',\n customVars = {}\n } = config;\n\n if (databaseType) {\n const dbPort = getDatabasePort(databaseType);\n\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\n if (redis) {\n process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;\n process.env.REDIS_HOST = redis.getHost();\n process.env.REDIS_PORT = redis.getMappedPort(6379).toString();\n }\n\n if (kafka) {\n const kafkaBroker = `${kafka.getHost()}:${kafka.getMappedPort(9092)}`;\n process.env.KAFKA_BROKERS = kafkaBroker;\n process.env.KAFKA_CLIENT_ID = 'test-client';\n process.env.KAFKA_GROUP_ID = 'test-group';\n }\n\n if (s3) {\n process.env.S3_ENDPOINT = `http://${s3.getHost()}:${s3.getMappedPort(9000)}`;\n process.env.S3_ACCESS_KEY_ID = 'minioadmin';\n process.env.S3_SECRET_ACCESS_KEY = 'minioadmin';\n process.env.S3_REGION = 'us-east-1';\n process.env.S3_BUCKET = 'test-bucket';\n process.env.S3_FORCE_PATH_STYLE = 'true'; // Required for MinIO\n }\n\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, Options } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface MikroOrmTestConfig {\n /**\n * MikroORM config object (imported from mikro-orm.config)\n */\n mikroOrmConfig: Options;\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 mikroOrmConfig,\n databaseType,\n useMigrations = false,\n container\n } = config;\n\n const dbPort = getDatabasePort(databaseType);\n\n // SQLite databases are file-based\n let ormConfig: Options = {};\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 }\n })\n };\n } else if (container) {\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 }\n })\n };\n }\n\n const orm = await MikroORM.init(ormConfig);\n\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 and/or cache\n */\nexport async function clearTestDatabase(options?: {\n orm?: MikroORM;\n redis?: Redis;\n}): Promise<void> {\n const { orm, redis } = options || {};\n\n if (redis) {\n await redis.flushall();\n }\n\n if (orm) {\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}\n","import { MikroORM, Options } 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 * Function that imports and returns the MikroORM config\n * This is called AFTER environment variables are set\n * Optional - if not provided, no database will be set up\n */\n getConfig?: () => Promise<Options>;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n * Optional - if not provided, no database will be set up\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 * Whether the blueprint needs Kafka\n */\n needsKafka?: boolean;\n\n /**\n * Whether the blueprint needs S3 (MinIO)\n */\n needsS3?: boolean;\n\n /**\n * S3 bucket name to create (default: 'test-bucket')\n */\n s3Bucket?: string;\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 kafkaContainer?: StartedTestContainer;\n s3Container?: 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 Database with ORM\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\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 with setup.orm and setup.redis\n * await harness.cleanup();\n * ```\n *\n * @example Cache-only (no database)\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * needsRedis: true,\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // ... run tests with setup.redis only (setup.orm is undefined)\n * await harness.cleanup();\n * ```\n *\n * @example With Kafka and S3\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\n * needsKafka: true,\n * needsS3: true,\n * s3Bucket: 'my-test-bucket',\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // Access containers via setup.kafkaContainer and setup.s3Container\n * // Kafka broker: process.env.KAFKA_BROKERS\n * // S3 endpoint: process.env.S3_ENDPOINT\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, Kafka, S3)\n */\n async setup(): Promise<TestSetupResult> {\n // Setup database container only if database is needed\n let container: StartedTestContainer | null = null;\n let orm: MikroORM | undefined;\n let redisContainer: StartedTestContainer | undefined;\n let kafkaContainer: StartedTestContainer | undefined;\n let s3Container: StartedTestContainer | undefined;\n\n // Setup Redis container if needed (for both database and cache-only modes)\n if (this.config.needsRedis) {\n redisContainer = await this.containers.setupRedisContainer();\n }\n\n // Setup Kafka container if needed\n if (this.config.needsKafka) {\n kafkaContainer = await this.containers.setupKafkaContainer();\n }\n\n // Setup S3 container if needed\n if (this.config.needsS3) {\n s3Container = await this.containers.setupS3Container({\n defaultBucket: this.config.s3Bucket\n });\n }\n\n if (this.config.databaseType && this.config.getConfig) {\n const databaseType = this.config.databaseType;\n\n // Setup database container\n container = await this.containers.setupDatabaseContainer(databaseType);\n\n // Setup environment variables\n setupTestEnvironment({\n database: container,\n databaseType,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\n\n // Get the config AFTER environment is set\n const mikroOrmConfig = await this.config.getConfig();\n\n // Setup ORM\n orm = await setupTestORM({\n mikroOrmConfig,\n databaseType,\n useMigrations: this.config.useMigrations,\n migrationsPath: this.config.migrationsPath,\n container\n });\n } else {\n // Cache-only mode: no database\n setupTestEnvironment({\n database: null,\n databaseType: undefined,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\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 = {\n container,\n redisContainer,\n kafkaContainer,\n s3Container,\n orm,\n redis\n };\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 and/or cache\n */\n async clearDatabase(): Promise<void> {\n if (this.result) {\n await clearTestDatabase({\n orm: this.result.orm,\n redis: this.result.redis\n });\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"],"mappings":"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","names":["getDatabasePort"]}
1
+ {"version":3,"sources":["../src/containers.ts","../src/environment.ts","../src/database.ts","../src/harness.ts","../src/tokens.ts"],"sourcesContent":["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\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 interface KafkaConfig {\n /** Kafka cluster ID */\n clusterId?: string;\n /** Number of partitions */\n numPartitions?: number;\n /** Replication factor */\n replicationFactor?: number;\n /** Additional environment variables */\n env?: Record<string, string>;\n}\n\nexport interface S3Config {\n /** MinIO root user (access key) */\n rootUser?: string;\n /** MinIO root password (secret key) */\n rootPassword?: string;\n /** Default bucket to create */\n defaultBucket?: string;\n /** Region */\n region?: 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 '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 // eslint-disable-next-line @typescript-eslint/no-unused-vars\n user = 'SA',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n password = 'Test_Password123!',\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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 * Setup Kafka test container\n */\n async setupKafkaContainer(\n config: KafkaConfig = {}\n ): Promise<StartedTestContainer> {\n const {\n clusterId = 'test-cluster',\n numPartitions = 1,\n replicationFactor = 1,\n env = {}\n } = config;\n\n const container = await new GenericContainer('confluentinc/cp-kafka:latest')\n .withExposedPorts(9092, 9093)\n .withEnvironment({\n KAFKA_BROKER_ID: '1',\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:\n 'PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT',\n KAFKA_ADVERTISED_LISTENERS:\n 'PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092',\n KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: replicationFactor.toString(),\n KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: '1',\n KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: '1',\n KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: '0',\n KAFKA_NUM_PARTITIONS: numPartitions.toString(),\n KAFKA_CLUSTER_ID: clusterId,\n KAFKA_PROCESS_ROLES: 'broker,controller',\n KAFKA_NODE_ID: '1',\n KAFKA_CONTROLLER_QUORUM_VOTERS: '1@localhost:9093',\n KAFKA_LISTENERS:\n 'PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:9092',\n KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT',\n KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER',\n KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs',\n ...env\n })\n .start();\n\n // Wait for Kafka to be ready\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n this.containers.push(container);\n return container;\n }\n\n /**\n * Setup MinIO (S3-compatible) test container\n */\n async setupS3Container(config: S3Config = {}): Promise<StartedTestContainer> {\n const {\n rootUser = 'minioadmin',\n rootPassword = 'minioadmin',\n defaultBucket = 'test-bucket',\n region = 'us-east-1'\n } = config;\n\n const container = await new GenericContainer('minio/minio:latest')\n .withExposedPorts(9000, 9001)\n .withEnvironment({\n MINIO_ROOT_USER: rootUser,\n MINIO_ROOT_PASSWORD: rootPassword,\n MINIO_REGION: region\n })\n .withCommand(['server', '/data', '--console-address', ':9001'])\n .start();\n\n // Wait for MinIO to be ready\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Create default bucket if specified\n if (defaultBucket) {\n try {\n // Using MinIO client command via exec\n await container.exec([\n 'mc',\n 'alias',\n 'set',\n 'local',\n 'http://localhost:9000',\n rootUser,\n rootPassword\n ]);\n await container.exec(['mc', 'mb', `local/${defaultBucket}`]);\n } catch (error) {\n // Bucket creation might fail, but container is still usable\n console.warn('Could not create default bucket:', error);\n }\n }\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 kafka?: StartedTestContainer;\n s3?: 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 '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 kafka,\n s3,\n hmacSecret = 'test-secret-key',\n customVars = {}\n } = config;\n\n if (databaseType) {\n const dbPort = getDatabasePort(databaseType);\n\n process.env.DB_NAME = 'test_db';\n\n // SQLite databases are file-based, no container needed\n if (databaseType === 'sqlite' || databaseType === 'libsql') {\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\n if (redis) {\n process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getMappedPort(6379)}`;\n process.env.REDIS_HOST = redis.getHost();\n process.env.REDIS_PORT = redis.getMappedPort(6379).toString();\n }\n\n if (kafka) {\n const kafkaBroker = `${kafka.getHost()}:${kafka.getMappedPort(9092)}`;\n process.env.KAFKA_BROKERS = kafkaBroker;\n process.env.KAFKA_CLIENT_ID = 'test-client';\n process.env.KAFKA_GROUP_ID = 'test-group';\n }\n\n if (s3) {\n process.env.S3_ENDPOINT = `http://${s3.getHost()}:${s3.getMappedPort(9000)}`;\n process.env.S3_ACCESS_KEY_ID = 'minioadmin';\n process.env.S3_SECRET_ACCESS_KEY = 'minioadmin';\n process.env.S3_REGION = 'us-east-1';\n process.env.S3_BUCKET = 'test-bucket';\n process.env.S3_FORCE_PATH_STYLE = 'true'; // Required for MinIO\n }\n\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, Options } from '@mikro-orm/core';\nimport Redis from 'ioredis';\nimport { StartedTestContainer } from 'testcontainers';\nimport { DatabaseType } from './containers';\n\nexport interface MikroOrmTestConfig {\n /**\n * MikroORM config object (imported from mikro-orm.config)\n */\n mikroOrmConfig: Options;\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 orm.migrator.up())\n * - false: Billing blueprints (uses orm.schema.create())\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 '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 mikroOrmConfig,\n databaseType,\n useMigrations = false,\n container\n } = config;\n\n const dbPort = getDatabasePort(databaseType);\n\n // SQLite databases are file-based\n let ormConfig = {} as Options;\n if (databaseType === 'sqlite' || databaseType === 'libsql') {\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 }\n })\n };\n } else if (container) {\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 }\n })\n };\n }\n\n const orm = await MikroORM.init(ormConfig);\n\n if (useMigrations) {\n await orm.migrator.up();\n } else {\n await orm.schema.create();\n }\n\n return orm;\n}\n\n/**\n * Clear all data from the test database and/or cache\n */\nexport async function clearTestDatabase(options?: {\n orm?: MikroORM;\n redis?: Redis;\n}): Promise<void> {\n const { orm, redis } = options || {};\n\n if (redis) {\n await redis.flushall();\n }\n\n if (orm) {\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}\n","import { MikroORM, Options } 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 * Function that imports and returns the MikroORM config\n * This is called AFTER environment variables are set\n * Optional - if not provided, no database will be set up\n */\n getConfig?: () => Promise<Options>;\n\n /**\n * Database type (postgres, mysql, mongodb, etc.)\n * Optional - if not provided, no database will be set up\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 * Whether the blueprint needs Kafka\n */\n needsKafka?: boolean;\n\n /**\n * Whether the blueprint needs S3 (MinIO)\n */\n needsS3?: boolean;\n\n /**\n * S3 bucket name to create (default: 'test-bucket')\n */\n s3Bucket?: string;\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 kafkaContainer?: StartedTestContainer;\n s3Container?: 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 Database with ORM\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\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 with setup.orm and setup.redis\n * await harness.cleanup();\n * ```\n *\n * @example Cache-only (no database)\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * needsRedis: true,\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // ... run tests with setup.redis only (setup.orm is undefined)\n * await harness.cleanup();\n * ```\n *\n * @example With Kafka and S3\n * ```typescript\n * const harness = new BlueprintTestHarness({\n * getConfig: async () => {\n * const { default: config } = await import('../mikro-orm.config');\n * return config;\n * },\n * databaseType: 'postgres',\n * needsKafka: true,\n * needsS3: true,\n * s3Bucket: 'my-test-bucket',\n * customEnvVars: {\n * API_KEY: 'test_key'\n * }\n * });\n *\n * const setup = await harness.setup();\n * // Access containers via setup.kafkaContainer and setup.s3Container\n * // Kafka broker: process.env.KAFKA_BROKERS\n * // S3 endpoint: process.env.S3_ENDPOINT\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, Kafka, S3)\n */\n async setup(): Promise<TestSetupResult> {\n // Setup database container only if database is needed\n let container: StartedTestContainer | null = null;\n let orm: MikroORM | undefined;\n let redisContainer: StartedTestContainer | undefined;\n let kafkaContainer: StartedTestContainer | undefined;\n let s3Container: StartedTestContainer | undefined;\n\n // Setup Redis container if needed (for both database and cache-only modes)\n if (this.config.needsRedis) {\n redisContainer = await this.containers.setupRedisContainer();\n }\n\n // Setup Kafka container if needed\n if (this.config.needsKafka) {\n kafkaContainer = await this.containers.setupKafkaContainer();\n }\n\n // Setup S3 container if needed\n if (this.config.needsS3) {\n s3Container = await this.containers.setupS3Container({\n defaultBucket: this.config.s3Bucket\n });\n }\n\n if (this.config.databaseType && this.config.getConfig) {\n const databaseType = this.config.databaseType;\n\n // Setup database container\n container = await this.containers.setupDatabaseContainer(databaseType);\n\n // Setup environment variables\n setupTestEnvironment({\n database: container,\n databaseType,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\n\n // Get the config AFTER environment is set\n const mikroOrmConfig = await this.config.getConfig();\n\n // Setup ORM\n orm = await setupTestORM({\n mikroOrmConfig,\n databaseType,\n useMigrations: this.config.useMigrations,\n migrationsPath: this.config.migrationsPath,\n container\n });\n } else {\n // Cache-only mode: no database\n setupTestEnvironment({\n database: null,\n databaseType: undefined,\n redis: redisContainer,\n kafka: kafkaContainer,\n s3: s3Container,\n customVars: this.config.customEnvVars\n });\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 = {\n container,\n redisContainer,\n kafkaContainer,\n s3Container,\n orm,\n redis\n };\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 and/or cache\n */\n async clearDatabase(): Promise<void> {\n if (this.result) {\n await clearTestDatabase({\n orm: this.result.orm,\n redis: this.result.redis\n });\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"],"mappings":"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","names":["getDatabasePort"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forklaunch/testing",
3
- "version": "0.0.29",
3
+ "version": "0.1.0",
4
4
  "description": "Testing utilities for forklaunch-js blueprints including testcontainer management",
5
5
  "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
6
6
  "bugs": {
@@ -28,14 +28,14 @@
28
28
  "lib/**"
29
29
  ],
30
30
  "dependencies": {
31
- "@mikro-orm/core": "6.6.9",
31
+ "@mikro-orm/core": "7.0.2",
32
32
  "ioredis": "^5.10.0",
33
33
  "testcontainers": "^11.12.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@eslint/js": "^10.0.1",
37
37
  "@types/node": "^25.5.0",
38
- "@typescript/native-preview": "7.0.0-dev.20260312.1",
38
+ "@typescript/native-preview": "7.0.0-dev.20260314.1",
39
39
  "globals": "^17.4.0",
40
40
  "prettier": "^3.8.1",
41
41
  "ts-node": "^10.9.2",