@medusajs/test-utils
Version:
Test utils for Medusa
248 lines • 9.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.medusaIntegrationTestRunner = medusaIntegrationTestRunner;
const utils_1 = require("@medusajs/framework/utils");
const awilix_1 = require("awilix");
const logger_1 = require("@medusajs/framework/logger");
const database_1 = require("./database");
const medusa_test_runner_utils_1 = require("./medusa-test-runner-utils");
const wait_workflow_executions_1 = require("./medusa-test-runner-utils/wait-workflow-executions");
class MedusaTestRunner {
constructor(config) {
this.globalContainer = null;
this.apiUtils = null;
this.loadedApplication = null;
this.shutdown = async () => void 0;
this.isFirstTime = true;
const tempName = parseInt(process.env.JEST_WORKER_ID || "1");
const moduleName = config.moduleName ?? Math.random().toString(36).substring(7);
this.dbName =
config.dbName ??
`medusa-${moduleName.toLowerCase()}-integration-${tempName}`;
this.schema = config.schema ?? "public";
this.cwd = config.medusaConfigFile ?? process.cwd();
this.env = config.env ?? {};
this.debug = config.debug ?? false;
this.inApp = config.inApp ?? false;
this.dbUtils = (0, database_1.dbTestUtilFactory)();
this.dbConfig = {
dbName: this.dbName,
clientUrl: (0, database_1.getDatabaseURL)(this.dbName),
schema: this.schema,
debug: this.debug,
};
this.setupProcessHandlers();
}
setupProcessHandlers() {
process.on("SIGTERM", async () => {
await this.cleanup();
process.exit(0);
});
process.on("SIGINT", async () => {
await this.cleanup();
process.exit(0);
});
}
createApiProxy() {
return new Proxy({}, {
get: (target, prop) => {
return this.apiUtils?.[prop];
},
});
}
createDbConnectionProxy() {
return new Proxy({}, {
get: (target, prop) => {
return this.dbUtils.pgConnection_?.[prop];
},
});
}
async initializeDatabase() {
try {
logger_1.logger.info(`Creating database ${this.dbName}`);
await this.dbUtils.create(this.dbName);
this.dbUtils.pgConnection_ = await (0, medusa_test_runner_utils_1.initDb)();
}
catch (error) {
logger_1.logger.error(`Error initializing database: ${error?.message}`);
await this.cleanup();
throw error;
}
}
async setupApplication() {
const { container, MedusaAppLoader } = await import("@medusajs/framework");
const appLoader = new MedusaAppLoader();
// Load plugins modules
const configModule = container.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
const plugins = await (0, utils_1.getResolvedPlugins)(this.cwd, configModule);
(0, utils_1.mergePluginModules)(configModule, plugins);
container.register({
[utils_1.ContainerRegistrationKeys.LOGGER]: (0, awilix_1.asValue)(logger_1.logger),
});
await this.initializeDatabase();
logger_1.logger.info(`Migrating database with core migrations and links ${this.dbName}`);
await (0, medusa_test_runner_utils_1.migrateDatabase)(appLoader);
await (0, medusa_test_runner_utils_1.syncLinks)(appLoader, this.cwd, container, logger_1.logger);
await (0, medusa_test_runner_utils_1.clearInstances)();
this.loadedApplication = await appLoader.load();
try {
const { shutdown, container: appContainer, port, } = await (0, medusa_test_runner_utils_1.startApp)({
cwd: this.cwd,
env: this.env,
});
this.globalContainer = appContainer;
this.shutdown = async () => {
await shutdown();
if (this.apiUtils?.cancelToken?.source) {
this.apiUtils.cancelToken.source.cancel("Request canceled by shutdown");
}
};
const { default: axios } = (await import("axios"));
const cancelTokenSource = axios.CancelToken.source();
this.apiUtils = axios.create({
baseURL: `http://localhost:${port}`,
cancelToken: cancelTokenSource.token,
});
this.apiUtils.cancelToken = { source: cancelTokenSource };
}
catch (error) {
logger_1.logger.error(`Error starting the app: ${error?.message}`);
await this.cleanup();
throw error;
}
}
async cleanup() {
try {
process.removeAllListeners("SIGTERM");
process.removeAllListeners("SIGINT");
await this.dbUtils.shutdown(this.dbName);
await this.shutdown();
await (0, medusa_test_runner_utils_1.clearInstances)();
if (this.apiUtils?.cancelToken?.source) {
this.apiUtils.cancelToken.source.cancel("Cleanup");
}
if (this.globalContainer?.dispose) {
await this.globalContainer.dispose();
}
this.apiUtils = null;
this.loadedApplication = null;
this.globalContainer = null;
if (global.gc) {
global.gc();
}
}
catch (error) {
logger_1.logger.error("Error during cleanup:", error?.message);
}
}
async beforeAll() {
try {
this.setupProcessHandlers();
await (0, medusa_test_runner_utils_1.configLoaderOverride)(this.cwd, this.dbConfig);
(0, medusa_test_runner_utils_1.applyEnvVarsToProcess)(this.env);
await this.setupApplication();
}
catch (error) {
await this.cleanup();
throw error;
}
}
async beforeEach() {
if (this.isFirstTime) {
this.isFirstTime = false;
return;
}
await this.afterEach();
const container = this.globalContainer;
const copiedContainer = (0, utils_1.createMedusaContainer)({}, container);
try {
const { MedusaAppLoader } = await import("@medusajs/framework");
const medusaAppLoader = new MedusaAppLoader({
container: copiedContainer,
});
await medusaAppLoader.runModulesLoader();
}
catch (error) {
await copiedContainer.dispose?.();
logger_1.logger.error("Error running modules loaders:", error?.message);
throw error;
}
}
async afterEach() {
try {
await (0, wait_workflow_executions_1.waitWorkflowExecutions)(this.globalContainer);
await this.dbUtils.teardown({ schema: this.schema });
}
catch (error) {
logger_1.logger.error("Error tearing down database:", error?.message);
throw error;
}
}
getOptions() {
return {
api: this.createApiProxy(),
dbConnection: this.createDbConnectionProxy(),
getMedusaApp: () => this.loadedApplication,
getContainer: () => this.globalContainer,
dbConfig: {
dbName: this.dbName,
schema: this.schema,
clientUrl: this.dbConfig.clientUrl,
},
dbUtils: this.dbUtils,
utils: {
waitWorkflowExecutions: () => (0, wait_workflow_executions_1.waitWorkflowExecutions)(this.globalContainer),
},
};
}
}
function medusaIntegrationTestRunner({ moduleName, dbName, medusaConfigFile, schema = "public", env = {}, debug = false, inApp = false, testSuite, }) {
const runner = new MedusaTestRunner({
moduleName,
dbName,
medusaConfigFile,
schema,
env,
debug,
inApp,
});
return describe("", () => {
let testOptions;
beforeAll(async () => {
await runner.beforeAll();
testOptions = runner.getOptions();
});
beforeEach(async () => {
await runner.beforeEach();
});
afterEach(async () => {
await runner.afterEach();
});
afterAll(async () => {
// Run main cleanup
await runner.cleanup();
// Clean references to the test options
for (const key in testOptions) {
if (typeof testOptions[key] === "function") {
testOptions[key] = null;
}
else if (typeof testOptions[key] === "object" &&
testOptions[key] !== null) {
Object.keys(testOptions[key]).forEach((k) => {
testOptions[key][k] = null;
});
testOptions[key] = null;
}
}
// Encourage garbage collection
// @ts-ignore
testOptions = null;
if (global.gc) {
global.gc();
}
});
// Run test suite with options
testSuite(runner.getOptions());
});
}
//# sourceMappingURL=medusa-test-runner.js.map