feature: bundle all modules (#9324)

This commit is contained in:
Harminder Virk
2024-09-30 09:04:03 +02:00
committed by GitHub
parent a4fc9d6e0b
commit a578313db9
81 changed files with 640 additions and 226 deletions
+214
View File
@@ -0,0 +1,214 @@
import { MikroORM, Options, SqlEntityManager } from "@mikro-orm/postgresql"
import { createDatabase, dropDatabase } from "pg-god"
const DB_HOST = process.env.DB_HOST ?? "localhost"
const DB_USERNAME = process.env.DB_USERNAME ?? ""
const DB_PASSWORD = process.env.DB_PASSWORD ?? ""
const pgGodCredentials = {
user: DB_USERNAME,
password: DB_PASSWORD,
host: DB_HOST,
}
export function getDatabaseURL(dbName?: string): string {
const DB_HOST = process.env.DB_HOST ?? "localhost"
const DB_USERNAME = process.env.DB_USERNAME ?? ""
const DB_PASSWORD = process.env.DB_PASSWORD
const DB_NAME = dbName ?? process.env.DB_TEMP_NAME
return `postgres://${DB_USERNAME}${
DB_PASSWORD ? `:${DB_PASSWORD}` : ""
}@${DB_HOST}/${DB_NAME}`
}
export function getMikroOrmConfig({
mikroOrmEntities,
pathToMigrations,
clientUrl,
schema,
}: {
mikroOrmEntities: any[]
pathToMigrations?: string
clientUrl?: string
schema?: string
}): Options {
const DB_URL = clientUrl ?? getDatabaseURL()
return {
type: "postgresql",
clientUrl: DB_URL,
entities: Object.values(mikroOrmEntities),
schema: schema ?? process.env.MEDUSA_DB_SCHEMA,
debug: false,
pool: {
min: 2,
},
migrations: {
pathTs: pathToMigrations,
silent: true,
},
}
}
export interface TestDatabase {
mikroOrmEntities: any[]
pathToMigrations?: string
schema?: string
clientUrl?: string
orm: MikroORM | null
manager: SqlEntityManager | null
setupDatabase(): Promise<void>
clearDatabase(): Promise<void>
getManager(): SqlEntityManager
forkManager(): SqlEntityManager
getOrm(): MikroORM
}
export function getMikroOrmWrapper({
mikroOrmEntities,
pathToMigrations,
clientUrl,
schema,
}: {
mikroOrmEntities: any[]
pathToMigrations?: string
clientUrl?: string
schema?: string
}): TestDatabase {
return {
mikroOrmEntities,
pathToMigrations,
clientUrl: clientUrl ?? getDatabaseURL(),
schema: schema ?? process.env.MEDUSA_DB_SCHEMA,
orm: null,
manager: null,
getManager() {
if (this.manager === null) {
throw new Error("manager entity not available")
}
return this.manager
},
forkManager() {
if (this.manager === null) {
throw new Error("manager entity not available")
}
return this.manager.fork()
},
getOrm() {
if (this.orm === null) {
throw new Error("orm entity not available")
}
return this.orm
},
async setupDatabase() {
const OrmConfig = getMikroOrmConfig({
mikroOrmEntities: this.mikroOrmEntities,
pathToMigrations: this.pathToMigrations,
clientUrl: this.clientUrl,
schema: this.schema,
})
// Initializing the ORM
this.orm = await MikroORM.init(OrmConfig)
this.manager = this.orm.em
try {
await this.orm.getSchemaGenerator().ensureDatabase()
} catch (err) {
console.log(err)
}
await this.manager?.execute(
`CREATE SCHEMA IF NOT EXISTS "${this.schema ?? "public"}";`
)
const pendingMigrations = await this.orm
.getMigrator()
.getPendingMigrations()
if (pendingMigrations && pendingMigrations.length > 0) {
await this.orm
.getMigrator()
.up({ migrations: pendingMigrations.map((m) => m.name!) })
} else {
await this.orm.schema.refreshDatabase() // ensure db exists and is fresh
}
},
async clearDatabase() {
if (this.orm === null) {
throw new Error("ORM not configured")
}
await this.manager?.execute(
`DROP SCHEMA IF EXISTS "${this.schema ?? "public"}" CASCADE;`
)
await this.manager?.execute(
`CREATE SCHEMA IF NOT EXISTS "${this.schema ?? "public"}";`
)
try {
await this.orm.close()
} catch {}
this.orm = null
this.manager = null
},
}
}
export const dbTestUtilFactory = (): any => ({
pgConnection_: null,
create: async function (dbName: string) {
await createDatabase(
{ databaseName: dbName, errorIfExist: false },
pgGodCredentials
)
},
teardown: async function ({ schema }: { schema?: string } = {}) {
if (!this.pgConnection_) {
return
}
const runRawQuery = this.pgConnection_.raw.bind(this.pgConnection_)
schema ??= "public"
await runRawQuery(`SET session_replication_role = 'replica';`)
const { rows: tableNames } = await runRawQuery(`SELECT table_name
FROM information_schema.tables
WHERE table_schema = '${schema}';`)
for (const { table_name } of tableNames) {
await runRawQuery(`DELETE
FROM ${schema}."${table_name}";`)
}
await runRawQuery(`SET session_replication_role = 'origin';`)
},
shutdown: async function (dbName: string) {
await this.pgConnection_?.context?.destroy()
await this.pgConnection_?.destroy()
return await dropDatabase(
{ databaseName: dbName, errorIfNonExist: false },
pgGodCredentials
)
},
})
+47
View File
@@ -0,0 +1,47 @@
import { IEventBusModuleService } from "@medusajs/framework/types"
import { EventEmitter } from "events"
// Allows you to wait for all subscribers to execute for a given event. Only works with the local event bus.
export const waitSubscribersExecution = (
eventName: string,
eventBus: IEventBusModuleService
) => {
const eventEmitter: EventEmitter = (eventBus as any).eventEmitter_
const subscriberPromises: Promise<any>[] = []
const originalListeners = eventEmitter.listeners(eventName)
// If there are no existing listeners, resolve once the event happens. Otherwise, wrap the existing subscribers in a promise and resolve once they are done.
if (!eventEmitter.listeners(eventName).length) {
let ok
const promise = new Promise((resolve) => {
ok = resolve
})
subscriberPromises.push(promise)
eventEmitter.on(eventName, ok)
} else {
eventEmitter.listeners(eventName).forEach((listener: any) => {
eventEmitter.removeListener(eventName, listener)
let ok, nok
const promise = new Promise((resolve, reject) => {
ok = resolve
nok = reject
})
subscriberPromises.push(promise)
const newListener = async (...args2) => {
return await listener.apply(eventBus, args2).then(ok).catch(nok)
}
eventEmitter.on(eventName, newListener)
})
}
return Promise.all(subscriberPromises).finally(() => {
eventEmitter.removeAllListeners(eventName)
originalListeners.forEach((listener) => {
eventEmitter.on(eventName, listener as (...args: any) => void)
})
})
}
+19
View File
@@ -0,0 +1,19 @@
import randomize from "randomatic"
class IdMap {
ids = {}
getId(key, prefix = "", length = 10) {
if (this.ids[key]) {
return this.ids[key]
}
const id = `${prefix && prefix + "_"}${randomize("Aa0", length)}`
this.ids[key] = id
return id
}
}
const instance = new IdMap()
export default instance
+9
View File
@@ -0,0 +1,9 @@
export * as TestDatabaseUtils from "./database"
export * as TestEventUtils from "./events"
export { default as IdMap } from "./id-map"
export * from "./init-modules"
export * as JestUtils from "./jest"
export * from "./medusa-test-runner"
export * from "./medusa-test-runner-utils"
export { default as MockEventBusService } from "./mock-event-bus-service"
export * from "./module-test-runner"
@@ -0,0 +1,84 @@
import {
ExternalModuleDeclaration,
InternalModuleDeclaration,
ModuleJoinerConfig,
} from "@medusajs/framework/types"
import {
ContainerRegistrationKeys,
createPgConnection,
promiseAll,
} from "@medusajs/framework/utils"
export interface InitModulesOptions {
injectedDependencies?: Record<string, unknown>
databaseConfig: {
clientUrl: string
schema?: string
}
modulesConfig: {
[key: string]:
| string
| boolean
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
}
joinerConfig?: ModuleJoinerConfig[]
preventConnectionDestroyWarning?: boolean
}
export async function initModules({
injectedDependencies,
databaseConfig,
modulesConfig,
joinerConfig,
preventConnectionDestroyWarning = false,
}: InitModulesOptions) {
const moduleSdkImports = require("@medusajs/framework/modules-sdk")
injectedDependencies ??= {}
let sharedPgConnection =
injectedDependencies?.[ContainerRegistrationKeys.PG_CONNECTION]
let shouldDestroyConnectionAutomatically = !sharedPgConnection
if (!sharedPgConnection) {
sharedPgConnection = createPgConnection({
clientUrl: databaseConfig.clientUrl,
schema: databaseConfig.schema,
})
injectedDependencies[ContainerRegistrationKeys.PG_CONNECTION] =
sharedPgConnection
}
const medusaApp = await moduleSdkImports.MedusaApp({
modulesConfig,
servicesConfig: joinerConfig,
injectedDependencies,
})
await medusaApp.onApplicationStart()
async function shutdown() {
if (shouldDestroyConnectionAutomatically) {
await medusaApp.onApplicationPrepareShutdown()
await promiseAll([
(sharedPgConnection as any).context?.destroy(),
(sharedPgConnection as any).destroy(),
medusaApp.onApplicationShutdown(),
])
} else {
if (!preventConnectionDestroyWarning) {
console.info(
`You are using a custom shared connection. The connection won't be destroyed automatically.`
)
}
}
moduleSdkImports.MedusaModule.clearInstances()
}
return {
medusaApp,
shutdown,
}
}
+24
View File
@@ -0,0 +1,24 @@
import { dropDatabase } from "pg-god"
export function afterAllHookDropDatabase() {
const DB_HOST = process.env.DB_HOST ?? "localhost"
const DB_USERNAME = process.env.DB_USERNAME ?? "postgres"
const DB_PASSWORD = process.env.DB_PASSWORD ?? ""
const DB_NAME = process.env.DB_TEMP_NAME || ""
const pgGodCredentials = {
user: DB_USERNAME,
password: DB_PASSWORD,
host: DB_HOST,
}
afterAll(async () => {
try {
await dropDatabase({ databaseName: DB_NAME }, pgGodCredentials)
} catch (e) {
console.error(
`This might fail if it is run during the unit tests since there is no database to drop. Otherwise, please check what is the issue. ${e.message}`
)
}
})
}
@@ -0,0 +1,80 @@
import express from "express"
import getPort from "get-port"
import { resolve } from "path"
import { MedusaContainer } from "@medusajs/framework/types"
import { applyEnvVarsToProcess } from "./utils"
import { promiseAll, GracefulShutdownServer } from "@medusajs/framework/utils"
async function bootstrapApp({
cwd,
env = {},
}: { cwd?: string; env?: Record<any, any> } = {}) {
const app = express()
applyEnvVarsToProcess(env)
const loaders = require("@medusajs/medusa/loaders/index").default
const { container, shutdown } = await loaders({
directory: resolve(cwd || process.cwd()),
expressApp: app,
})
const PORT = process.env.PORT ? parseInt(process.env.PORT) : await getPort()
return {
shutdown,
container,
app,
port: PORT,
}
}
export async function startApp({
cwd,
env = {},
}: { cwd?: string; env?: Record<any, any> } = {}): Promise<{
shutdown: () => Promise<void>
container: MedusaContainer
port: number
}> {
const {
app,
port,
container,
shutdown: medusaShutdown,
} = await bootstrapApp({
cwd,
env,
})
let expressServer
const shutdown = async () => {
await promiseAll([expressServer?.shutdown(), medusaShutdown()])
if (typeof global !== "undefined" && global?.gc) {
global.gc()
}
}
return await new Promise((resolve, reject) => {
const server = app
.listen(port)
.on("error", async (err) => {
await shutdown()
return reject(err)
})
.on("listening", () => {
process.send?.(port)
resolve({
shutdown,
container,
port,
})
})
// TODO: fix that once we find the appropriate place to put this util
expressServer = GracefulShutdownServer.create(server)
})
}
@@ -0,0 +1,10 @@
/**
* cleanup temporary created resources for the migrations
* @internal I didnt find a god place to put that, should we eventually add a close function
* to the planner to handle that part? so that you would do planner.close() and it will handle the cleanup
* automatically just like we usually do for the classic migrations actions
*/
export async function clearInstances() {
const { MedusaModule } = require("@medusajs/framework/modules-sdk")
MedusaModule.clearInstances()
}
@@ -0,0 +1,33 @@
import { getConfigFile } from "@medusajs/framework/utils"
export async function configLoaderOverride(
entryDirectory: string,
override: { clientUrl: string; debug?: boolean }
) {
const { configManager } = await import("@medusajs/framework/config")
const { configModule, error } = getConfigFile<
ReturnType<typeof configManager.loadConfig>
>(entryDirectory, "medusa-config.js")
if (error) {
throw new Error(error.message || "Error during config loading")
}
configModule.projectConfig.databaseDriverOptions
configModule.projectConfig.databaseUrl = override.clientUrl
configModule.projectConfig.databaseLogging = !!override.debug
configModule.projectConfig.databaseDriverOptions =
override.clientUrl.includes("localhost")
? {}
: {
connection: {
ssl: { rejectUnauthorized: false },
},
idle_in_transaction_session_timeout: 20000,
}
configManager.loadConfig({
projectConfig: configModule,
baseDir: entryDirectory,
})
}
@@ -0,0 +1,5 @@
export * from "./bootstrap-app"
export * from "./clear-instances"
export * from "./config"
export * from "./use-db"
export * from "./utils"
@@ -0,0 +1,71 @@
import type { MedusaAppLoader } from "@medusajs/framework"
import { join } from "path"
import { MedusaContainer } from "@medusajs/framework/types"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
/**
* Initiates the database connection
*/
export async function initDb() {
const { pgConnectionLoader, featureFlagsLoader } = await import(
"@medusajs/framework"
)
const pgConnection = pgConnectionLoader()
await featureFlagsLoader()
return pgConnection
}
/**
* Migrates the database
*/
export async function migrateDatabase(appLoader: MedusaAppLoader) {
try {
await appLoader.runModulesMigrations()
} catch (err) {
console.error("Something went wrong while running the migrations")
throw err
}
}
/**
* Syncs links with the databse
*/
export async function syncLinks(
appLoader: MedusaAppLoader,
directory: string,
container: MedusaContainer
) {
try {
await loadCustomLinks(directory, container)
const planner = await appLoader.getLinksExecutionPlanner()
const actionPlan = await planner.createPlan()
actionPlan.forEach((action) => {
console.log(`Sync links: "${action.action}" ${action.tableName}`)
})
await planner.executePlan(actionPlan)
} catch (err) {
console.error("Something went wrong while syncing links")
throw err
}
}
async function loadCustomLinks(directory: string, container: MedusaContainer) {
// TODO: move to framework once settle down
const {
getResolvedPlugins,
} = require("@medusajs/medusa/loaders/helpers/resolve-plugins")
const configModule = container.resolve(
ContainerRegistrationKeys.CONFIG_MODULE
)
const plugins = getResolvedPlugins(directory, configModule, true) || []
const linksSourcePaths = plugins.map((plugin) =>
join(plugin.resolve, "links")
)
const { LinkLoader } = await import("@medusajs/framework")
await new LinkLoader(linksSourcePaths).load()
}
@@ -0,0 +1,7 @@
import { isObject } from "@medusajs/framework/utils"
export function applyEnvVarsToProcess(env?: Record<any, any>) {
if (isObject(env)) {
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
}
}
@@ -0,0 +1,223 @@
import { MedusaAppOutput } from "@medusajs/framework/modules-sdk"
import { ContainerLike, MedusaContainer } from "@medusajs/framework/types"
import {
ContainerRegistrationKeys,
createMedusaContainer,
} from "@medusajs/framework/utils"
import { asValue } from "awilix"
import { dbTestUtilFactory, getDatabaseURL } from "./database"
import {
applyEnvVarsToProcess,
clearInstances,
configLoaderOverride,
initDb,
migrateDatabase,
startApp,
syncLinks,
} from "./medusa-test-runner-utils"
export interface MedusaSuiteOptions {
dbConnection: any // knex instance
getContainer: () => MedusaContainer
api: any
dbUtils: {
create: (dbName: string) => Promise<void>
teardown: (options: { schema?: string }) => Promise<void>
shutdown: (dbName: string) => Promise<void>
}
dbConfig: {
dbName: string
schema: string
clientUrl: string
}
getMedusaApp: () => MedusaAppOutput
}
export function medusaIntegrationTestRunner({
moduleName,
dbName,
medusaConfigFile,
schema = "public",
env = {},
debug = false,
inApp = false,
testSuite,
}: {
moduleName?: string
env?: Record<string, any>
dbName?: string
medusaConfigFile?: string
schema?: string
debug?: boolean
inApp?: boolean
testSuite: (options: MedusaSuiteOptions) => void
}) {
const tempName = parseInt(process.env.JEST_WORKER_ID || "1")
moduleName = moduleName ?? Math.random().toString(36).substring(7)
dbName ??= `medusa-${moduleName.toLowerCase()}-integration-${tempName}`
let dbConfig = {
dbName,
clientUrl: getDatabaseURL(dbName),
schema,
debug,
}
const cwd = medusaConfigFile ?? process.cwd()
let shutdown = async () => void 0
const dbUtils = dbTestUtilFactory()
let globalContainer: ContainerLike
let apiUtils: any
let loadedApplication: any
let options = {
api: new Proxy(
{},
{
get: (target, prop) => {
return apiUtils[prop]
},
}
),
dbConnection: new Proxy(
{},
{
get: (target, prop) => {
return dbUtils.pgConnection_[prop]
},
}
),
getMedusaApp: () => loadedApplication,
getContainer: () => globalContainer,
dbConfig: {
dbName,
schema,
clientUrl: dbConfig.clientUrl,
},
dbUtils,
} as MedusaSuiteOptions
let isFirstTime = true
const beforeAll_ = async () => {
await configLoaderOverride(cwd, dbConfig)
applyEnvVarsToProcess(env)
const { logger, container, MedusaAppLoader } = await import(
"@medusajs/framework"
)
const appLoader = new MedusaAppLoader()
container.register({
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
})
try {
console.log(`Creating database ${dbName}`)
await dbUtils.create(dbName)
dbUtils.pgConnection_ = await initDb()
} catch (error) {
console.error("Error initializing database", error?.message)
throw error
}
console.log(`Migrating database with core migrations and links ${dbName}`)
await migrateDatabase(appLoader)
await syncLinks(appLoader, cwd, container)
await clearInstances()
let containerRes: MedusaContainer = container
let serverShutdownRes: () => any
let portRes: number
loadedApplication = await appLoader.load()
try {
const {
shutdown = () => void 0,
container: appContainer,
port,
} = await startApp({
cwd,
env,
})
containerRes = appContainer
serverShutdownRes = shutdown
portRes = port
} catch (error) {
console.error("Error starting the app", error?.message)
throw error
}
/**
* Run application migrations and sync links when inside
* an application
*/
if (inApp) {
console.log(`Migrating database with core migrations and links ${dbName}`)
await migrateDatabase(appLoader)
await syncLinks(appLoader, cwd, containerRes)
}
const { default: axios } = (await import("axios")) as any
const cancelTokenSource = axios.CancelToken.source()
globalContainer = containerRes
shutdown = async () => {
await serverShutdownRes()
cancelTokenSource.cancel("Request canceled by shutdown")
}
apiUtils = axios.create({
baseURL: `http://localhost:${portRes}`,
cancelToken: cancelTokenSource.token,
})
}
const beforeEach_ = async () => {
// The beforeAll already run everything, so lets not re run the loaders for the first iteration
if (isFirstTime) {
isFirstTime = false
return
}
const container = options.getContainer()
const copiedContainer = createMedusaContainer({}, container)
try {
const { MedusaAppLoader } = await import("@medusajs/framework")
const medusaAppLoader = new MedusaAppLoader({
container: copiedContainer,
})
await medusaAppLoader.runModulesLoader()
} catch (error) {
console.error("Error runner modules loaders", error?.message)
throw error
}
}
const afterEach_ = async () => {
try {
await dbUtils.teardown({ schema })
} catch (error) {
console.error("Error tearing down database:", error?.message)
throw error
}
}
return describe("", () => {
beforeAll(beforeAll_)
beforeEach(beforeEach_)
afterEach(afterEach_)
afterAll(async () => {
await dbUtils.shutdown(dbName)
await shutdown()
})
testSuite(options!)
})
}
@@ -0,0 +1,33 @@
import {
EventBusTypes,
IEventBusModuleService,
Message,
Subscriber,
} from "@medusajs/framework/types"
export default class EventBusService implements IEventBusModuleService {
async emit<T>(
data: Message<T> | Message<T>[],
options: Record<string, unknown>
): Promise<void> {}
subscribe(event: string | symbol, subscriber: Subscriber): this {
return this
}
unsubscribe(
event: string | symbol,
subscriber: Subscriber,
context?: EventBusTypes.SubscriberContext
): this {
return this
}
releaseGroupedEvents(eventGroupId: string): Promise<void> {
return Promise.resolve()
}
clearGroupedEvents(eventGroupId: string): Promise<void> {
return Promise.resolve()
}
}
@@ -0,0 +1,195 @@
import {
ContainerRegistrationKeys,
DmlEntity,
loadModels,
Modules,
ModulesSdkUtils,
normalizeImportPathWithSource,
toMikroOrmEntities,
} from "@medusajs/framework/utils"
import * as fs from "fs"
import { getDatabaseURL, getMikroOrmWrapper, TestDatabase } from "./database"
import { initModules, InitModulesOptions } from "./init-modules"
import { default as MockEventBusService } from "./mock-event-bus-service"
export interface SuiteOptions<TService = unknown> {
MikroOrmWrapper: TestDatabase
medusaApp: any
service: TService
dbConfig: {
schema: string
clientUrl: string
}
}
function createMikroOrmWrapper(options: {
moduleModels?: (Function | DmlEntity<any, any>)[]
resolve?: string
dbConfig: any
}): {
MikroOrmWrapper: TestDatabase
models: (Function | DmlEntity<any, any>)[]
} {
let moduleModels: (Function | DmlEntity<any, any>)[] =
options.moduleModels ?? []
if (!options.moduleModels) {
const basePath = normalizeImportPathWithSource(
options.resolve ?? process.cwd()
)
const modelsPath = fs.existsSync(`${basePath}/dist/models`)
? "/dist/models"
: fs.existsSync(`${basePath}/models`)
? "/models"
: ""
if (modelsPath) {
moduleModels = loadModels(`${basePath}${modelsPath}`)
} else {
moduleModels = []
}
}
moduleModels = toMikroOrmEntities(moduleModels)
const MikroOrmWrapper = getMikroOrmWrapper({
mikroOrmEntities: moduleModels,
clientUrl: options.dbConfig.clientUrl,
schema: options.dbConfig.schema,
})
return { MikroOrmWrapper, models: moduleModels }
}
export function moduleIntegrationTestRunner<TService = any>({
moduleName,
moduleModels,
moduleOptions = {},
moduleDependencies,
joinerConfig = [],
schema = "public",
debug = false,
testSuite,
resolve,
injectedDependencies = {},
}: {
moduleName: string
moduleModels?: any[]
moduleOptions?: Record<string, any>
moduleDependencies?: string[]
joinerConfig?: any[]
schema?: string
dbName?: string
injectedDependencies?: Record<string, any>
resolve?: string
debug?: boolean
testSuite: (options: SuiteOptions<TService>) => void
}) {
const moduleSdkImports = require("@medusajs/framework/modules-sdk")
process.env.LOG_LEVEL = "error"
const tempName = parseInt(process.env.JEST_WORKER_ID || "1")
const dbName = `medusa-${moduleName.toLowerCase()}-integration-${tempName}`
const dbConfig = {
clientUrl: getDatabaseURL(dbName),
schema,
debug,
}
// Use a unique connection for all the entire suite
const connection = ModulesSdkUtils.createPgConnection(dbConfig)
const { MikroOrmWrapper, models } = createMikroOrmWrapper({
moduleModels,
resolve,
dbConfig,
})
moduleModels = models
const modulesConfig_ = {
[moduleName]: {
definition: moduleSdkImports.ModulesDefinition[moduleName],
resolve,
dependencies: moduleDependencies,
options: {
database: dbConfig,
...moduleOptions,
},
},
}
const moduleOptions_: InitModulesOptions = {
injectedDependencies: {
[ContainerRegistrationKeys.PG_CONNECTION]: connection,
[Modules.EVENT_BUS]: new MockEventBusService(),
[ContainerRegistrationKeys.LOGGER]: console,
...injectedDependencies,
},
modulesConfig: modulesConfig_,
databaseConfig: dbConfig,
joinerConfig,
preventConnectionDestroyWarning: true,
}
let shutdown: () => Promise<void>
let moduleService
let medusaApp = {}
const options = {
MikroOrmWrapper,
medusaApp: new Proxy(
{},
{
get: (target, prop) => {
return medusaApp[prop]
},
}
),
service: new Proxy(
{},
{
get: (target, prop) => {
return moduleService[prop]
},
}
),
dbConfig: {
schema,
clientUrl: dbConfig.clientUrl,
},
} as SuiteOptions<TService>
const beforeEach_ = async () => {
if (moduleModels.length) {
await MikroOrmWrapper.setupDatabase()
}
const output = await initModules(moduleOptions_)
shutdown = output.shutdown
medusaApp = output.medusaApp
moduleService = output.medusaApp.modules[moduleName]
}
const afterEach_ = async () => {
if (moduleModels.length) {
await MikroOrmWrapper.clearDatabase()
}
await shutdown()
moduleService = {}
medusaApp = {}
}
return describe("", () => {
beforeEach(beforeEach_)
afterEach(afterEach_)
afterAll(async () => {
await (connection as any).context?.destroy()
await (connection as any).destroy()
})
testSuite(options)
})
}