medusa
medusa copied to clipboard
Trouble with end to end test
My goal is to construct Medusa environment to able write end to end tests.
Trouble i am having is i am unable to apply migrations to medusa instance and there are couple of problems i am having.
- I would like spawn fresh postgres instance every time test is ran. In order to achieve that i have to generate database in test environment. Problem with that approach is I am unable to run
medusa-cli migrate
command since it's actively reading medusa config and I am unable to pass database uri in config at that time.
FAIL __test__/stripe-subscriptions.test.ts (5.534 s)
End to end test for Subscription test
✕
● End to end test for Subscription test ›
EntityPropertyNotFoundError: Property "default_sales_channel" was not found in "Store". Make sure your query is correct.
at ../../src/query-builder/SelectQueryBuilder.ts:3911:23
at Array.forEach (<anonymous>)
at SelectQueryBuilder.buildRelations (../../src/query-builder/SelectQueryBuilder.ts:3903:32)
at SelectQueryBuilder.applyFindOptions (../../src/query-builder/SelectQueryBuilder.ts:3103:22)
at SelectQueryBuilder.setFindOptions (../../src/query-builder/SelectQueryBuilder.ts:105:14)
at EntityManager.findOne (../../src/entity-manager/EntityManager.ts:1189:14)
at Repository.findOne (../../src/repository/Repository.ts:577:29)
at StoreService.<anonymous> (../../node_modules/@medusajs/medusa/src/services/store.ts:91:35)
at step (../../node_modules/@medusajs/medusa/dist/services/store.js:48:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/services/store.js:29:53)
at ../../node_modules/@medusajs/medusa/dist/services/store.js:23:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/services/store.js:19:12)
at StoreService.Object.<anonymous>.StoreService.retrieve (../../node_modules/@medusajs/medusa/dist/services/store.js:173:16)
at SalesChannelService.<anonymous> (../../node_modules/@medusajs/medusa/src/services/sales-channel.ts:262:10)
at step (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:59:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:40:53)
at ../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:34:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:30:12)
at ../../node_modules/@medusajs/medusa/src/services/sales-channel.ts:259:55
at SalesChannelService.<anonymous> (../../node_modules/@medusajs/medusa/src/interfaces/transaction-base-service.ts:83:24)
at step (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:33:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:14:53)
at ../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:8:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:4:12)
at doWork (../../node_modules/@medusajs/medusa/src/interfaces/transaction-base-service.ts:79:45)
at SalesChannelService.<anonymous> (../../node_modules/@medusajs/medusa/src/interfaces/transaction-base-service.ts:97:20)
at step (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:33:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:14:53)
at ../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:8:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:4:12)
at SalesChannelService.Object.<anonymous>.TransactionBaseService.atomicPhase_ (../../node_modules/@medusajs/medusa/dist/interfaces/transaction-base-service.js:81:16)
at SalesChannelService.<anonymous> (../../node_modules/@medusajs/medusa/src/services/sales-channel.ts:259:17)
at step (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:59:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:40:53)
at ../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:34:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:30:12)
at SalesChannelService.Object.<anonymous>.SalesChannelService.createDefault (../../node_modules/@medusajs/medusa/dist/services/sales-channel.js:361:16)
at ../../node_modules/@medusajs/medusa/src/loaders/defaults.ts:148:14
at step (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:33:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:14:53)
at ../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:8:71
at Object.<anonymous>.__awaiter (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:4:12)
at ../../node_modules/@medusajs/medusa/src/loaders/defaults.ts:141:8
at ../../node_modules/@medusajs/medusa/src/loaders/defaults.ts:152:9
at step (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:33:23)
at Object.next (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:14:53)
at fulfilled (../../node_modules/@medusajs/medusa/dist/loaders/defaults.js:5:58)
// stripe-subscriptions.test.ts
import { MedusaContainer } from "@medusajs/medusa";
import * as http from "http";
import { PostgreSqlContainer, StartedPostgreSqlContainer } from "testcontainers";
import { DataSource } from "typeorm";
import { medusaInitialize } from "../src/lib/spawn-medusa";
describe("End to end test for Subscription test", () => {
let dbConnection: DataSource;
let httpServer: http.Server;
let container: MedusaContainer;
let dbContainer: StartedPostgreSqlContainer;
beforeAll(async () => {
dbContainer = await new PostgreSqlContainer()
//
.withUsername("medusa")
.withPassword("medusa")
.withDatabase("medusa")
.start();
const medusa = await medusaInitialize({
databaseUrl: dbContainer.getConnectionUri(),
});
dbConnection = medusa.dbConnection;
httpServer = medusa.httpServer;
container = medusa.container;
}, 30000);
afterAll(async () => {
if (dbConnection?.isInitialized) {
await dbConnection.destroy();
}
if (httpServer?.listening) {
await new Promise((resolve) => httpServer.close(resolve));
}
await dbContainer.stop();
});
it("Test", async () => {});
});
// spawn-medusa.ts
import apiLoader from "@medusajs/medusa/dist/loaders/api";
import databaseLoader, { dataSource } from "@medusajs/medusa/dist/loaders/database";
import defaultsLoader from "@medusajs/medusa/dist/loaders/defaults";
import expressLoader from "@medusajs/medusa/dist/loaders/express";
import featureFlagsLoader from "@medusajs/medusa/dist/loaders/feature-flags";
import Logger from "@medusajs/medusa/dist/loaders/logger";
import modelsLoader from "@medusajs/medusa/dist/loaders/models";
import passportLoader from "@medusajs/medusa/dist/loaders/passport";
import pluginsLoader, { registerPluginModels } from "@medusajs/medusa/dist/loaders/plugins";
import redisLoader from "@medusajs/medusa/dist/loaders/redis";
import repositoriesLoader from "@medusajs/medusa/dist/loaders/repositories";
import searchIndexLoader from "@medusajs/medusa/dist/loaders/search-index";
import servicesLoader from "@medusajs/medusa/dist/loaders/services";
import strategiesLoader from "@medusajs/medusa/dist/loaders/strategies";
import subscribersLoader from "@medusajs/medusa/dist/loaders/subscribers";
import { asValue } from "awilix";
import express, { Express, NextFunction, Request, Response } from "express";
import "reflect-metadata";
import { ConfigModule } from "@medusajs/medusa";
import { moduleLoader, registerModules } from "@medusajs/modules-sdk";
import axios from "axios";
import { createMedusaContainer } from "medusa-core-utils";
export const medusaInitialize = async ({ databaseUrl }: { databaseUrl: string }) => {
const PORT = 9000;
const rootDirectory = process.cwd();
const app: Express = express();
// To mute the logger i override the logger with a dummy logger
const logger = {
info: () => null,
error: () => null,
warn: () => null,
progress: () => null,
} as Logger;
type ExtendedConfigModule = ConfigModule & {
projectConfig: {
stripe: {
success_url: string;
secret_key: string;
webhook_secret: string;
};
};
};
const configModule: ExtendedConfigModule = {
featureFlags: {
product_categories: true,
},
projectConfig: {
database_type: "postgres",
database_url: databaseUrl,
database_logging: false,
store_cors: "/.*/",
admin_cors: "/.*/",
jwt_secret: "SECRET",
cookie_secret: "SECRET",
stripe: {
success_url: process.env.STRIPE_SUCCESS_URL,
secret_key: process.env.STRIPE_SECRET_KEY,
webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
},
},
modules: {
cacheService: {
resolve: "@medusajs/cache-inmemory",
options: {
ttl: 30,
},
},
eventBus: {
resolve: "@medusajs/event-bus-local",
},
},
plugins: [],
};
const container = createMedusaContainer();
container.register("configModule", asValue(configModule));
const featureFlagRouter = featureFlagsLoader(configModule, logger);
container.register({
logger: asValue(logger),
featureFlagRouter: asValue(featureFlagRouter),
});
await redisLoader({ container, configModule, logger });
modelsLoader({ container });
await registerPluginModels({
rootDirectory,
container,
configModule,
});
strategiesLoader({ container, configModule, isTest: false });
await moduleLoader({
container,
moduleResolutions: registerModules(configModule?.modules),
logger: logger,
});
const dbConnection = await databaseLoader({
container,
configModule,
customOptions: {
migrations: ["/home/quiloos39/Documents/work/traumkaffee/node_modules/@medusajs/medusa/dist/migrations/*.js"],
logging: false,
},
});
await dbConnection.runMigrations();
repositoriesLoader({ container });
container.register({ manager: asValue(dataSource.manager) });
servicesLoader({ container, configModule, isTest: false });
await expressLoader({ app: app, configModule });
await passportLoader({ app: app, container, configModule });
// Add the registered services to the request scope
app.use((req: Request, res: Response, next: NextFunction) => {
container.register({ manager: asValue(dataSource.manager) });
(req as any).scope = container.createScope();
next();
});
console.log("Loading plugins");
await pluginsLoader({
container,
rootDirectory,
configModule,
app: app,
activityId: null,
});
console.log("Loading subscribers");
subscribersLoader({ container });
console.log("Loading api");
await apiLoader({ container, app: app, configModule });
console.log("Loading defaults");
await defaultsLoader({ container });
console.log("Loading search index");
await searchIndexLoader({ container });
const httpServer = app.listen(PORT);
// Awaiting until server is ready
await new Promise(async (resolve) => {
let signal: NodeJS.Timeout;
signal = setInterval(async () => {
const response = await axios.get(`http://localhost:${PORT}/health`).catch((e) => null);
if (response) {
clearTimeout(signal);
resolve(true);
}
}, 1000);
});
console.log("Done loading");
return {
container,
dbConnection,
httpServer,
};
};
This is part where i apply migrations it's hard coded path for now but will be changed.
const dbConnection = await databaseLoader({
container,
configModule,
customOptions: {
migrations: ["/home/quiloos39/Documents/work/traumkaffee/node_modules/@medusajs/medusa/dist/migrations/*.js"],
logging: false,
},
});
did you manage to solve that issue?
Any updates?
Hey, thanks for the report! Since v2 brought a lot of architectural and API changes on the backend, we will be closing this ticket since it no longer applies to our new setup, or the issue has already been fixed. If you are still facing issues with v1, please open a new ticket and we will address it as soon as possible. Thanks! 🙏