@forklaunch/testing 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.mts +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js.map +1 -1
- package/lib/index.mjs.map +1 -1
- package/package.json +6 -6
package/lib/index.d.mts
CHANGED
|
@@ -118,7 +118,7 @@ interface MikroOrmTestConfig {
|
|
|
118
118
|
/**
|
|
119
119
|
* MikroORM config object (imported from mikro-orm.config)
|
|
120
120
|
*/
|
|
121
|
-
mikroOrmConfig: Options
|
|
121
|
+
mikroOrmConfig: Partial<Options>;
|
|
122
122
|
/**
|
|
123
123
|
* Database type (postgres, mysql, mongodb, etc.)
|
|
124
124
|
*/
|
|
@@ -156,7 +156,7 @@ interface BlueprintTestConfig {
|
|
|
156
156
|
* This is called AFTER environment variables are set
|
|
157
157
|
* Optional - if not provided, no database will be set up
|
|
158
158
|
*/
|
|
159
|
-
getConfig?: () => Promise<Options
|
|
159
|
+
getConfig?: () => Promise<Partial<Options>>;
|
|
160
160
|
/**
|
|
161
161
|
* Database type (postgres, mysql, mongodb, etc.)
|
|
162
162
|
* Optional - if not provided, no database will be set up
|
package/lib/index.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ interface MikroOrmTestConfig {
|
|
|
118
118
|
/**
|
|
119
119
|
* MikroORM config object (imported from mikro-orm.config)
|
|
120
120
|
*/
|
|
121
|
-
mikroOrmConfig: Options
|
|
121
|
+
mikroOrmConfig: Partial<Options>;
|
|
122
122
|
/**
|
|
123
123
|
* Database type (postgres, mysql, mongodb, etc.)
|
|
124
124
|
*/
|
|
@@ -156,7 +156,7 @@ interface BlueprintTestConfig {
|
|
|
156
156
|
* This is called AFTER environment variables are set
|
|
157
157
|
* Optional - if not provided, no database will be set up
|
|
158
158
|
*/
|
|
159
|
-
getConfig?: () => Promise<Options
|
|
159
|
+
getConfig?: () => Promise<Partial<Options>>;
|
|
160
160
|
/**
|
|
161
161
|
* Database type (postgres, mysql, mongodb, etc.)
|
|
162
162
|
* Optional - if not provided, no database will be set up
|
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\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","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: Partial<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: Partial<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<Partial<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"]}
|
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\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"]}
|
|
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: Partial<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: Partial<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<Partial<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.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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,20 +28,20 @@
|
|
|
28
28
|
"lib/**"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@mikro-orm/core": "7.0.
|
|
32
|
-
"ioredis": "^5.10.
|
|
33
|
-
"testcontainers": "^11.
|
|
31
|
+
"@mikro-orm/core": "7.0.3",
|
|
32
|
+
"ioredis": "^5.10.1",
|
|
33
|
+
"testcontainers": "^11.13.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.
|
|
38
|
+
"@typescript/native-preview": "7.0.0-dev.20260320.1",
|
|
39
39
|
"globals": "^17.4.0",
|
|
40
40
|
"prettier": "^3.8.1",
|
|
41
41
|
"ts-node": "^10.9.2",
|
|
42
42
|
"tsup": "^8.5.1",
|
|
43
43
|
"typescript": "^5.9.3",
|
|
44
|
-
"typescript-eslint": "^8.57.
|
|
44
|
+
"typescript-eslint": "^8.57.1",
|
|
45
45
|
"vitest": "^4.1.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|