From 12b035cb1898e3eff5a69f0854ce06c56a21d765 Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Thu, 7 Mar 2024 09:05:43 +0100 Subject: [PATCH] chore(tests): Try to use the api integration tests for v2 (#6588) Few things to keep in mind: 1. You need to set MEDUSA_FF_MEDUSA_V2 to true before running the tests to run with the v2 API 2. You can use the `breaking` function to differentiate between v1 and v2 differences. This can help us identify what was breaking pretty quickly afterwards 3. You will need to run specific tests for now instead of all if you want to target v2. I think that's fine though, as we don't really need these to run on every PR until we have feature parity (and by then, all tests would be both v1 and v2 compatible) **note: Adrien** - add a new way to load modules only to run their loaders comparable to the way to run the migrations only - improve tests runner to cleanup the data properly as well as re running all loaders and core defaults Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com> --- .../admin/__snapshots__/store.js.snap | 8 - .../api/__tests__/admin/store.js | 434 +++++++++--------- integration-tests/api/medusa-config.js | 62 ++- integration-tests/api/package.json | 17 +- integration-tests/helpers/breaking.ts | 10 + .../helpers/create-admin-user.ts | 35 ++ .../__tests__/api-key/admin/api-key.spec.ts | 2 +- .../__tests__/currency/admin/currency.spec.ts | 2 +- .../admin/batch-add-customers.ts | 2 +- .../admin/batch-remove-customers.ts | 2 +- .../admin/create-customer-group.ts | 2 +- .../admin/delete-customer-group.ts | 2 +- .../admin/list-customer-group-customers.ts | 2 +- .../admin/list-customer-groups.spec.ts | 2 +- .../admin/retrieve-customer-group.ts | 2 +- .../admin/update-customer-group.ts | 2 +- .../admin/create-customer-addresses.ts | 2 +- .../customer/admin/create-customer.ts | 2 +- .../admin/delete-customer-address.spec.ts | 2 +- .../customer/admin/delete-customer.ts | 2 +- .../customer/admin/list-customer-addresses.ts | 2 +- .../customer/admin/list-customers.spec.ts | 2 +- .../admin/update-customer-address.spec.ts | 2 +- .../customer/admin/update-customer.ts | 2 +- .../__tests__/invites/accept-invite.spec.ts | 2 +- .../__tests__/invites/create-invite.spec.ts | 2 +- .../__tests__/invites/delete-invite.spec.ts | 2 +- .../__tests__/invites/list-invites.spec.ts | 2 +- .../__tests__/invites/resend-invite.spec.ts | 2 +- .../__tests__/invites/retrieve-invite.spec.ts | 2 +- .../modules/__tests__/link-modules/index.ts | 17 +- .../product/admin/create-product.spec.ts | 2 +- .../promotion/admin/create-campaign.spec.ts | 2 +- .../promotion/admin/create-promotion.spec.ts | 2 +- .../promotion/admin/delete-campaign.spec.ts | 2 +- .../promotion/admin/delete-promotion.spec.ts | 2 +- .../promotion/admin/list-campaigns.spec.ts | 2 +- .../promotion/admin/list-promotions.spec.ts | 2 +- .../promotion/admin/retrieve-campaign.spec.ts | 2 +- .../admin/retrieve-promotion.spec.ts | 2 +- .../promotion/admin/update-campaign.spec.ts | 2 +- .../promotion/admin/update-promotion.spec.ts | 2 +- .../__tests__/regions/admin/regions.spec.ts | 8 +- .../__tests__/store/admin/store.spec.ts | 2 +- .../modules/__tests__/tax/admin/tax.spec.ts | 2 +- .../__tests__/tax/workflow/tax.spec.ts | 2 +- .../__tests__/users/create-user.spec.ts | 2 +- .../__tests__/users/delete-user.spec.ts | 2 +- .../modules/__tests__/users/get-me.spec.ts | 2 +- .../__tests__/users/list-users.spec.ts | 2 +- .../__tests__/users/retrieve-user.spec.ts | 2 +- .../__tests__/users/update-user.spec.ts | 2 +- .../__tests__/workflow-engine/tests.ts | 2 +- .../modules/helpers/create-admin-user.ts | 29 -- .../src/medusa-test-runner.ts | 47 +- .../src/api-v2/admin/stores/query-config.ts | 3 + .../medusa/src/api-v2/admin/stores/route.ts | 7 +- .../src/api-v2/admin/stores/validators.ts | 4 + packages/medusa/src/loaders/medusa-app.ts | 68 +++ .../medusajs-modules-sdk-1.12.6.tgz | Bin 28833 -> 0 bytes .../modules-sdk/src/loaders/module-loader.ts | 16 +- .../src/loaders/utils/load-internal.ts | 7 +- packages/modules-sdk/src/medusa-app.ts | 35 +- packages/modules-sdk/src/medusa-module.ts | 31 +- packages/region/mikro-orm.config.dev.ts | 4 + packages/region/src/joiner-config.ts | 2 +- .../RegionModuleSetup20240205173216.ts | 3 +- packages/region/src/models/country.ts | 28 +- .../__tests__/store-module-service.spec.ts | 47 ++ .../migrations/.snapshot-medusa-store.json | 9 + .../migrations/InitialSetup20240227075933.ts | 19 +- packages/store/src/models/store.ts | 3 + .../src/services/store-module-service.ts | 80 ++++ packages/types/src/store/common/store.ts | 3 + packages/types/src/store/mutations/store.ts | 3 + yarn.lock | 15 + 76 files changed, 773 insertions(+), 371 deletions(-) delete mode 100644 integration-tests/api/__tests__/admin/__snapshots__/store.js.snap create mode 100644 integration-tests/helpers/breaking.ts create mode 100644 integration-tests/helpers/create-admin-user.ts delete mode 100644 integration-tests/modules/helpers/create-admin-user.ts delete mode 100644 packages/modules-sdk/medusajs-modules-sdk-1.12.6.tgz diff --git a/integration-tests/api/__tests__/admin/__snapshots__/store.js.snap b/integration-tests/api/__tests__/admin/__snapshots__/store.js.snap deleted file mode 100644 index 0162ad57ef..0000000000 --- a/integration-tests/api/__tests__/admin/__snapshots__/store.js.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`/admin/store POST /admin/store fails to update default currency if not in store currencies 1`] = ` -Object { - "message": "Store does not have currency: eur", - "type": "invalid_data", -} -`; diff --git a/integration-tests/api/__tests__/admin/store.js b/integration-tests/api/__tests__/admin/store.js index 558496c87d..f159b5e4bc 100644 --- a/integration-tests/api/__tests__/admin/store.js +++ b/integration-tests/api/__tests__/admin/store.js @@ -1,242 +1,250 @@ -const { Store } = require("@medusajs/medusa") -const path = require("path") +const { + createAdminUser, + adminHeaders, +} = require("../../../helpers/create-admin-user") +const { breaking } = require("../../../helpers/breaking") +const { ModuleRegistrationName } = require("@medusajs/modules-sdk") +const { medusaIntegrationTestRunner } = require("medusa-test-utils") -const setupServer = require("../../../environment-helpers/setup-server") -const { useApi } = require("../../../environment-helpers/use-api") -const { initDb, useDb } = require("../../../environment-helpers/use-db") +jest.setTimeout(90000) -const adminSeeder = require("../../../helpers/admin-seeder") +medusaIntegrationTestRunner({ + testSuite: ({ dbConnection, getContainer, api }) => { + describe("/admin/store", () => { + let dbStore + let container -jest.setTimeout(30000) + // Note: The tests rely on the loader running and populating clean data before and after the test, so we have to do this in a beforeEach + beforeEach(async () => { + container = getContainer() -describe("/admin/store", () => { - let dbConnection - const cwd = path.resolve(path.join(__dirname, "..", "..")) - - beforeAll(async () => { - dbConnection = await initDb({ cwd }) - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - }) - - describe("Store creation", () => { - let medusaProcess - - beforeEach(async () => { - await adminSeeder(dbConnection) - medusaProcess = await setupServer({ cwd }) - }) - - afterEach(async () => { - const db = useDb() - await db.teardown({ forceDelete: ["store"] }) - await medusaProcess.kill() - }) - - it("has created store with default currency", async () => { - const api = useApi() - - const response = await api.get("/admin/store", { - headers: { "x-medusa-access-token": "test_token " }, + await createAdminUser(dbConnection, adminHeaders, container) + await breaking( + async () => { + const { Store } = require("@medusajs/medusa/dist/models/store") + const manager = dbConnection.manager + dbStore = await manager.findOne(Store, { + where: { name: "Medusa Store" }, + }) + await manager.query( + `INSERT INTO store_currencies (store_id, currency_code) + VALUES ('${dbStore.id}', 'dkk')` + ) + }, + async () => { + const service = container.resolve(ModuleRegistrationName.STORE) + dbStore = await service.create({ + supported_currency_codes: ["usd", "dkk"], + default_currency_code: "usd", + default_sales_channel_id: "sc_12345", + }) + } + ) }) - expect(response.status).toEqual(200) - expect(response.data.store).toEqual( - expect.objectContaining({ - id: expect.any(String), - default_sales_channel_id: expect.any(String), - default_sales_channel: expect.objectContaining({ - id: expect.any(String), - }), - name: "Medusa Store", - currencies: expect.arrayContaining([ + describe("Store creation", () => { + it("has created store with default currency", async () => { + const store = await breaking( + () => + api.get("/admin/store", adminHeaders).then((r) => r.data.store), + () => + api + .get("/admin/stores", adminHeaders) + .then((r) => r.data.stores[0]) + ) + + expect(store).toEqual( expect.objectContaining({ - code: "usd", - }), - ]), - modules: expect.any(Array), - feature_flags: expect.any(Array), - default_currency_code: "usd", - created_at: expect.any(String), - updated_at: expect.any(String), + id: expect.any(String), + name: "Medusa Store", + default_currency_code: "usd", + default_sales_channel_id: expect.any(String), + ...breaking( + () => ({ + default_sales_channel: expect.objectContaining({ + id: expect.any(String), + }), + currencies: expect.arrayContaining([ + expect.objectContaining({ + code: "usd", + }), + ]), + modules: expect.any(Array), + feature_flags: expect.any(Array), + }), + () => ({ + supported_currency_codes: ["usd", "dkk"], + }) + ), + created_at: expect.any(String), + updated_at: expect.any(String), + }) + ) }) - ) - }) - }) - - describe("POST /admin/store", () => { - let medusaProcess - - beforeEach(async () => { - await adminSeeder(dbConnection) - medusaProcess = await setupServer({ cwd }) - - const manager = dbConnection.manager - const store = await manager.findOne(Store, { - where: { name: "Medusa Store" }, }) - await manager.query( - `INSERT INTO store_currencies (store_id, currency_code) VALUES ('${store.id}', 'dkk')` - ) - }) - afterEach(async () => { - const db = useDb() - await db.teardown({ forceDelete: ["store"] }) - await medusaProcess.kill() - }) - - it("fails to update default currency if not in store currencies", async () => { - const api = useApi() - - try { - await api.post( - "/admin/store", - { - default_currency_code: "eur", - }, - { - headers: { "x-medusa-access-token": "test_token " }, + describe("POST /admin/store", () => { + it("fails to update default currency if not in store currencies", async () => { + try { + await api.post( + breaking( + () => "/admin/store", + () => `/admin/stores/${dbStore.id}` + ), + { + default_currency_code: "eur", + }, + adminHeaders + ) + } catch (e) { + expect(e.response.data).toEqual( + expect.objectContaining({ + type: "invalid_data", + message: "Store does not have currency: eur", + }) + ) + expect(e.response.status).toBe(400) } - ) - } catch (e) { - expect(e.response.data).toMatchSnapshot({ - type: "invalid_data", - message: "Store does not have currency: eur", }) - expect(e.response.status).toBe(400) - } - }) - it("fails to remove default currency from currencies without replacing it", async () => { - const api = useApi() - - try { - await api.post( - "/admin/store", - { - currencies: ["usd"], - }, - { - headers: { "x-medusa-access-token": "test_token " }, + it("fails to remove default currency from currencies without replacing it", async () => { + try { + await api.post( + breaking( + () => "/admin/store", + () => `/admin/stores/${dbStore.id}` + ), + breaking( + () => ({ + currencies: ["usd"], + }), + () => ({ supported_currency_codes: ["dkk"] }) + ), + adminHeaders + ) + } catch (e) { + expect(e.response.data).toEqual( + expect.objectContaining({ + type: "invalid_data", + message: + "You are not allowed to remove default currency from store currencies without replacing it as well", + }) + ) + expect(e.response.status).toBe(400) } - ) - } catch (e) { - expect(e.response.data).toMatchSnapshot({ - type: "invalid_data", - message: - "You are not allowed to remove default currency from store currencies without replacing it as well", }) - expect(e.response.status).toBe(400) - } - }) - it("successfully updates default currency code", async () => { - const api = useApi() + it("successfully updates default currency code", async () => { + const response = await api + .post( + breaking( + () => "/admin/store", + () => `/admin/stores/${dbStore.id}` + ), + { + default_currency_code: "dkk", + }, + adminHeaders + ) + .catch((err) => console.log(err)) - const response = await api - .post( - "/admin/store", - { - default_currency_code: "dkk", - }, - { - headers: { "x-medusa-access-token": "test_token " }, - } - ) - .catch((err) => console.log(err)) - - expect(response.status).toEqual(200) - expect(response.data.store).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: "Medusa Store", - default_sales_channel_id: expect.any(String), - currencies: expect.arrayContaining([ + expect(response.status).toEqual(200) + expect(response.data.store).toEqual( expect.objectContaining({ - code: "usd", - }), - expect.objectContaining({ - code: "dkk", - }), - ]), - default_currency_code: "dkk", - created_at: expect.any(String), - updated_at: expect.any(String), + id: expect.any(String), + name: "Medusa Store", + default_currency_code: "dkk", + created_at: expect.any(String), + updated_at: expect.any(String), + }) + ) }) - ) - }) - it("successfully updates default currency and store currencies", async () => { - const api = useApi() + it("successfully updates default currency and store currencies", async () => { + const response = await api.post( + breaking( + () => "/admin/store", + () => `/admin/stores/${dbStore.id}` + ), + { + default_currency_code: "jpy", + ...breaking( + () => ({ currencies: ["jpy", "usd"] }), + () => ({ supported_currency_codes: ["jpy", "usd"] }) + ), + }, + adminHeaders + ) - const response = await api.post( - "/admin/store", - { - default_currency_code: "jpy", - currencies: ["jpy", "usd"], - }, - { - headers: { "x-medusa-access-token": "test_token " }, - } - ) - - expect(response.status).toEqual(200) - expect(response.data.store).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: "Medusa Store", - default_sales_channel_id: expect.any(String), - currencies: expect.arrayContaining([ + expect(response.status).toEqual(200) + expect(response.data.store).toEqual( expect.objectContaining({ - code: "jpy", - }), - expect.objectContaining({ - code: "usd", - }), - ]), - default_currency_code: "jpy", - created_at: expect.any(String), - updated_at: expect.any(String), + id: expect.any(String), + name: "Medusa Store", + default_sales_channel_id: expect.any(String), + ...breaking( + () => ({ + currencies: expect.arrayContaining([ + expect.objectContaining({ + code: "jpy", + }), + expect.objectContaining({ + code: "usd", + }), + ]), + }), + () => ({ supported_currency_codes: ["jpy", "usd"] }) + ), + default_currency_code: "jpy", + created_at: expect.any(String), + updated_at: expect.any(String), + }) + ) }) - ) - }) - it("successfully updates and store currencies", async () => { - const api = useApi() + it("successfully updates and store currencies", async () => { + const response = await api.post( + breaking( + () => "/admin/store", + () => `/admin/stores/${dbStore.id}` + ), + breaking( + () => ({ + currencies: ["jpy", "usd"], + }), + () => ({ + supported_currency_codes: ["jpy", "usd"], + }) + ), + adminHeaders + ) - const response = await api.post( - "/admin/store", - { - currencies: ["jpy", "usd"], - }, - { - headers: { "x-medusa-access-token": "test_token " }, - } - ) - - expect(response.status).toEqual(200) - expect(response.data.store).toEqual( - expect.objectContaining({ - id: expect.any(String), - default_sales_channel_id: expect.any(String), - name: "Medusa Store", - currencies: expect.arrayContaining([ + expect(response.status).toEqual(200) + expect(response.data.store).toEqual( expect.objectContaining({ - code: "jpy", - }), - expect.objectContaining({ - code: "usd", - }), - ]), - default_currency_code: "usd", - created_at: expect.any(String), - updated_at: expect.any(String), + id: expect.any(String), + default_sales_channel_id: expect.any(String), + name: "Medusa Store", + ...breaking( + () => ({ + currencies: expect.arrayContaining([ + expect.objectContaining({ + code: "jpy", + }), + expect.objectContaining({ + code: "usd", + }), + ]), + }), + () => ({ supported_currency_codes: ["jpy", "usd"] }) + ), + default_currency_code: "usd", + created_at: expect.any(String), + updated_at: expect.any(String), + }) + ) }) - ) + }) }) - }) + }, }) diff --git a/integration-tests/api/medusa-config.js b/integration-tests/api/medusa-config.js index e3ff70f29f..ab637f6c06 100644 --- a/integration-tests/api/medusa-config.js +++ b/integration-tests/api/medusa-config.js @@ -1,18 +1,25 @@ +const { Modules } = require("@medusajs/modules-sdk") + const DB_HOST = process.env.DB_HOST const DB_USERNAME = process.env.DB_USERNAME const DB_PASSWORD = process.env.DB_PASSWORD const DB_NAME = process.env.DB_TEMP_NAME +const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}` -const redisUrl = process.env.REDIS_URL || "redis://localhost:6379" +const redisUrl = process.env.REDIS_URL const cacheTTL = process.env.CACHE_TTL ?? 15 const enableResponseCompression = process.env.ENABLE_RESPONSE_COMPRESSION || true +const enableMedusaV2 = process.env.MEDUSA_FF_MEDUSA_V2 == "true" + +process.env.POSTGRES_URL = DB_URL +process.env.LOG_LEVEL = "error" module.exports = { plugins: [], projectConfig: { redis_url: redisUrl, - database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`, + database_url: DB_URL, database_type: "postgres", jwt_secret: "test", cookie_secret: "test", @@ -20,11 +27,62 @@ module.exports = { enabled: enableResponseCompression, }, }, + featureFlags: { + medusa_v2: enableMedusaV2, + }, modules: { cacheService: { resolve: "@medusajs/cache-inmemory", options: { ttl: cacheTTL }, }, workflows: true, + // We don't want to load the modules if v2 is not enabled, as they run data operations and migrations on load. + ...(enableMedusaV2 + ? { + [Modules.AUTH]: { + scope: "internal", + resources: "shared", + resolve: "@medusajs/auth", + options: { + providers: [ + { + name: "emailpass", + scopes: { + admin: {}, + store: {}, + }, + }, + ], + }, + }, + [Modules.USER]: { + scope: "internal", + resources: "shared", + resolve: "@medusajs/user", + options: { + jwt_secret: "test", + }, + }, + [Modules.CACHE]: { + resolve: "@medusajs/cache-inmemory", + options: { ttl: 0 }, // Cache disabled + }, + [Modules.STOCK_LOCATION]: true, + [Modules.INVENTORY]: true, + [Modules.PRODUCT]: true, + [Modules.PRICING]: true, + [Modules.PROMOTION]: true, + [Modules.CUSTOMER]: true, + [Modules.SALES_CHANNEL]: true, + [Modules.CART]: true, + [Modules.WORKFLOW_ENGINE]: true, + [Modules.REGION]: true, + [Modules.API_KEY]: true, + [Modules.STORE]: true, + [Modules.TAX]: true, + [Modules.CURRENCY]: true, + [Modules.PAYMENT]: true, + } + : {}), }, } diff --git a/integration-tests/api/package.json b/integration-tests/api/package.json index c2c76e1ebc..89d4ddc792 100644 --- a/integration-tests/api/package.json +++ b/integration-tests/api/package.json @@ -5,16 +5,31 @@ "license": "MIT", "private": true, "scripts": { - "test:integration": "jest --silent=false --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage", + "test:integration": "jest --silent --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage", "build": "babel src -d dist --extensions \".ts,.js\"" }, "dependencies": { + "@medusajs/api-key": "workspace:^", + "@medusajs/auth": "workspace:*", "@medusajs/cache-inmemory": "workspace:*", + "@medusajs/customer": "workspace:^", "@medusajs/event-bus-local": "workspace:*", + "@medusajs/inventory": "workspace:^", "@medusajs/medusa": "workspace:*", + "@medusajs/modules-sdk": "workspace:^", + "@medusajs/pricing": "workspace:^", + "@medusajs/product": "workspace:^", + "@medusajs/promotion": "workspace:^", + "@medusajs/region": "workspace:^", + "@medusajs/store": "workspace:^", + "@medusajs/tax": "workspace:^", + "@medusajs/user": "workspace:^", + "@medusajs/utils": "workspace:^", "@medusajs/workflow-engine-inmemory": "workspace:*", "faker": "^5.5.3", + "medusa-fulfillment-webshipper": "workspace:*", "medusa-interfaces": "workspace:*", + "medusa-plugin-sendgrid": "workspace:*", "pg": "^8.11.0", "typeorm": "^0.3.16" }, diff --git a/integration-tests/helpers/breaking.ts b/integration-tests/helpers/breaking.ts new file mode 100644 index 0000000000..3da96f1ce2 --- /dev/null +++ b/integration-tests/helpers/breaking.ts @@ -0,0 +1,10 @@ +export const breaking = ( + v1Fn: (() => any) | null, + v2Fn?: (() => any) | null +) => { + if (process.env.MEDUSA_FF_MEDUSA_V2 === "true") { + return v2Fn?.() + } + + return v1Fn?.() +} diff --git a/integration-tests/helpers/create-admin-user.ts b/integration-tests/helpers/create-admin-user.ts new file mode 100644 index 0000000000..b105913b5b --- /dev/null +++ b/integration-tests/helpers/create-admin-user.ts @@ -0,0 +1,35 @@ +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { IAuthModuleService } from "@medusajs/types" +import jwt from "jsonwebtoken" +import { getContainer } from "../environment-helpers/use-container" +import adminSeeder from "./admin-seeder" + +export const adminHeaders = { + headers: { "x-medusa-access-token": "test_token" }, +} + +export const createAdminUser = async ( + dbConnection, + adminHeaders, + container? +) => { + await adminSeeder(dbConnection) + const appContainer = container ?? getContainer()! + + const authModule: IAuthModuleService = appContainer.resolve( + ModuleRegistrationName.AUTH + ) + if (authModule) { + const authUser = await authModule.create({ + provider: "emailpass", + entity_id: "admin@medusa.js", + scope: "admin", + app_metadata: { + user_id: "admin_user", + }, + }) + + const token = jwt.sign(authUser, "test") + adminHeaders.headers["authorization"] = `Bearer ${token}` + } +} diff --git a/integration-tests/modules/__tests__/api-key/admin/api-key.spec.ts b/integration-tests/modules/__tests__/api-key/admin/api-key.spec.ts index 0b2559d44b..3196c79851 100644 --- a/integration-tests/modules/__tests__/api-key/admin/api-key.spec.ts +++ b/integration-tests/modules/__tests__/api-key/admin/api-key.spec.ts @@ -1,7 +1,7 @@ import { ApiKeyType } from "@medusajs/utils" import { IRegionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/currency/admin/currency.spec.ts b/integration-tests/modules/__tests__/currency/admin/currency.spec.ts index 3101f1aac7..2a22543d69 100644 --- a/integration-tests/modules/__tests__/currency/admin/currency.spec.ts +++ b/integration-tests/modules/__tests__/currency/admin/currency.spec.ts @@ -1,4 +1,4 @@ -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts b/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts index 53b58c17be..a93431887a 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts b/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts index 70bf486cdc..7832c3a037 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/create-customer-group.ts b/integration-tests/modules/__tests__/customer-group/admin/create-customer-group.ts index 4027709837..82f747caf6 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/create-customer-group.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/create-customer-group.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/delete-customer-group.ts b/integration-tests/modules/__tests__/customer-group/admin/delete-customer-group.ts index 56d297e9a4..8c9d618076 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/delete-customer-group.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/delete-customer-group.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/list-customer-group-customers.ts b/integration-tests/modules/__tests__/customer-group/admin/list-customer-group-customers.ts index 04d74a99b5..87a953dd40 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/list-customer-group-customers.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/list-customer-group-customers.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/list-customer-groups.spec.ts b/integration-tests/modules/__tests__/customer-group/admin/list-customer-groups.spec.ts index 794e897a71..5a546787fd 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/list-customer-groups.spec.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/list-customer-groups.spec.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/retrieve-customer-group.ts b/integration-tests/modules/__tests__/customer-group/admin/retrieve-customer-group.ts index b300a7892f..24f854159e 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/retrieve-customer-group.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/retrieve-customer-group.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer-group/admin/update-customer-group.ts b/integration-tests/modules/__tests__/customer-group/admin/update-customer-group.ts index 7f915584e5..9970789aba 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/update-customer-group.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/update-customer-group.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/create-customer-addresses.ts b/integration-tests/modules/__tests__/customer/admin/create-customer-addresses.ts index ad25b42557..e8f5609908 100644 --- a/integration-tests/modules/__tests__/customer/admin/create-customer-addresses.ts +++ b/integration-tests/modules/__tests__/customer/admin/create-customer-addresses.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/create-customer.ts b/integration-tests/modules/__tests__/customer/admin/create-customer.ts index abf0dadbcb..60c707abb2 100644 --- a/integration-tests/modules/__tests__/customer/admin/create-customer.ts +++ b/integration-tests/modules/__tests__/customer/admin/create-customer.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/delete-customer-address.spec.ts b/integration-tests/modules/__tests__/customer/admin/delete-customer-address.spec.ts index 6015b31290..25612aaf40 100644 --- a/integration-tests/modules/__tests__/customer/admin/delete-customer-address.spec.ts +++ b/integration-tests/modules/__tests__/customer/admin/delete-customer-address.spec.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/delete-customer.ts b/integration-tests/modules/__tests__/customer/admin/delete-customer.ts index cf2213efaf..1c2ae9e03c 100644 --- a/integration-tests/modules/__tests__/customer/admin/delete-customer.ts +++ b/integration-tests/modules/__tests__/customer/admin/delete-customer.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/list-customer-addresses.ts b/integration-tests/modules/__tests__/customer/admin/list-customer-addresses.ts index d0d35a0e84..433d071d70 100644 --- a/integration-tests/modules/__tests__/customer/admin/list-customer-addresses.ts +++ b/integration-tests/modules/__tests__/customer/admin/list-customer-addresses.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/list-customers.spec.ts b/integration-tests/modules/__tests__/customer/admin/list-customers.spec.ts index 583921c489..c7c1279f90 100644 --- a/integration-tests/modules/__tests__/customer/admin/list-customers.spec.ts +++ b/integration-tests/modules/__tests__/customer/admin/list-customers.spec.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/update-customer-address.spec.ts b/integration-tests/modules/__tests__/customer/admin/update-customer-address.spec.ts index bed711345d..817b0d06be 100644 --- a/integration-tests/modules/__tests__/customer/admin/update-customer-address.spec.ts +++ b/integration-tests/modules/__tests__/customer/admin/update-customer-address.spec.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/customer/admin/update-customer.ts b/integration-tests/modules/__tests__/customer/admin/update-customer.ts index 7a584a8762..c6ffb858f6 100644 --- a/integration-tests/modules/__tests__/customer/admin/update-customer.ts +++ b/integration-tests/modules/__tests__/customer/admin/update-customer.ts @@ -1,6 +1,6 @@ import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/accept-invite.spec.ts b/integration-tests/modules/__tests__/invites/accept-invite.spec.ts index a1f715005c..7eab2d8836 100644 --- a/integration-tests/modules/__tests__/invites/accept-invite.spec.ts +++ b/integration-tests/modules/__tests__/invites/accept-invite.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/create-invite.spec.ts b/integration-tests/modules/__tests__/invites/create-invite.spec.ts index 14fa28b48b..ce2ffb82c6 100644 --- a/integration-tests/modules/__tests__/invites/create-invite.spec.ts +++ b/integration-tests/modules/__tests__/invites/create-invite.spec.ts @@ -1,4 +1,4 @@ -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/delete-invite.spec.ts b/integration-tests/modules/__tests__/invites/delete-invite.spec.ts index b062178eb0..be4a8ce27a 100644 --- a/integration-tests/modules/__tests__/invites/delete-invite.spec.ts +++ b/integration-tests/modules/__tests__/invites/delete-invite.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/list-invites.spec.ts b/integration-tests/modules/__tests__/invites/list-invites.spec.ts index 412ad9573b..238ed3f8da 100644 --- a/integration-tests/modules/__tests__/invites/list-invites.spec.ts +++ b/integration-tests/modules/__tests__/invites/list-invites.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/resend-invite.spec.ts b/integration-tests/modules/__tests__/invites/resend-invite.spec.ts index a17be34635..bbaddd7f9b 100644 --- a/integration-tests/modules/__tests__/invites/resend-invite.spec.ts +++ b/integration-tests/modules/__tests__/invites/resend-invite.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/invites/retrieve-invite.spec.ts b/integration-tests/modules/__tests__/invites/retrieve-invite.spec.ts index bbe30c5306..4966a0d056 100644 --- a/integration-tests/modules/__tests__/invites/retrieve-invite.spec.ts +++ b/integration-tests/modules/__tests__/invites/retrieve-invite.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/link-modules/index.ts b/integration-tests/modules/__tests__/link-modules/index.ts index 511b23e8ee..6d3b2f9715 100644 --- a/integration-tests/modules/__tests__/link-modules/index.ts +++ b/integration-tests/modules/__tests__/link-modules/index.ts @@ -56,7 +56,22 @@ medusaIntegrationTestRunner({ } jest.spyOn(MedusaModule, "getLoadedModules").mockImplementation((() => { - return [{ moduleA: [{}] }, { moduleB: [{}] }] + return [ + { + moduleA: { + __definition: { + key: "moduleA", + }, + }, + }, + { + moduleB: { + __definition: { + key: "moduleB", + }, + }, + }, + ] }) as any) await runMigrations({ options: dbConfig }, linkDefinition) diff --git a/integration-tests/modules/__tests__/product/admin/create-product.spec.ts b/integration-tests/modules/__tests__/product/admin/create-product.spec.ts index a811e90795..93a4fc340b 100644 --- a/integration-tests/modules/__tests__/product/admin/create-product.spec.ts +++ b/integration-tests/modules/__tests__/product/admin/create-product.spec.ts @@ -1,4 +1,4 @@ -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils/dist" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/create-campaign.spec.ts b/integration-tests/modules/__tests__/promotion/admin/create-campaign.spec.ts index dd6ce50958..b2cbb4bfe9 100644 --- a/integration-tests/modules/__tests__/promotion/admin/create-campaign.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/create-campaign.spec.ts @@ -1,6 +1,6 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/create-promotion.spec.ts b/integration-tests/modules/__tests__/promotion/admin/create-promotion.spec.ts index e3c01b4d18..33acf26aad 100644 --- a/integration-tests/modules/__tests__/promotion/admin/create-promotion.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/create-promotion.spec.ts @@ -1,7 +1,7 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { PromotionType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/delete-campaign.spec.ts b/integration-tests/modules/__tests__/promotion/admin/delete-campaign.spec.ts index ab701aecce..bc1a65c7ab 100644 --- a/integration-tests/modules/__tests__/promotion/admin/delete-campaign.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/delete-campaign.spec.ts @@ -1,6 +1,6 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/delete-promotion.spec.ts b/integration-tests/modules/__tests__/promotion/admin/delete-promotion.spec.ts index 24b2a3c8ba..a948a5708d 100644 --- a/integration-tests/modules/__tests__/promotion/admin/delete-promotion.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/delete-promotion.spec.ts @@ -1,6 +1,6 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/list-campaigns.spec.ts b/integration-tests/modules/__tests__/promotion/admin/list-campaigns.spec.ts index 06a69b75ab..331a66bb9e 100644 --- a/integration-tests/modules/__tests__/promotion/admin/list-campaigns.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/list-campaigns.spec.ts @@ -1,7 +1,7 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { IPromotionModuleService } from "@medusajs/types" import { CampaignBudgetType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/list-promotions.spec.ts b/integration-tests/modules/__tests__/promotion/admin/list-promotions.spec.ts index baab7091e0..173c0c594f 100644 --- a/integration-tests/modules/__tests__/promotion/admin/list-promotions.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/list-promotions.spec.ts @@ -1,7 +1,7 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { PromotionType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/retrieve-campaign.spec.ts b/integration-tests/modules/__tests__/promotion/admin/retrieve-campaign.spec.ts index 2be28ab928..73bc6da008 100644 --- a/integration-tests/modules/__tests__/promotion/admin/retrieve-campaign.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/retrieve-campaign.spec.ts @@ -1,7 +1,7 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { IPromotionModuleService } from "@medusajs/types" import { CampaignBudgetType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts b/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts index 91241b3dfd..a9fcf2f159 100644 --- a/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts @@ -1,7 +1,7 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { PromotionType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/update-campaign.spec.ts b/integration-tests/modules/__tests__/promotion/admin/update-campaign.spec.ts index aeb68ef360..2d5e76b3de 100644 --- a/integration-tests/modules/__tests__/promotion/admin/update-campaign.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/update-campaign.spec.ts @@ -1,6 +1,6 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/promotion/admin/update-promotion.spec.ts b/integration-tests/modules/__tests__/promotion/admin/update-promotion.spec.ts index 669bfe22d0..63dcb66fab 100644 --- a/integration-tests/modules/__tests__/promotion/admin/update-promotion.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/update-promotion.spec.ts @@ -1,7 +1,7 @@ import { IPromotionModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { PromotionType } from "@medusajs/utils" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/regions/admin/regions.spec.ts b/integration-tests/modules/__tests__/regions/admin/regions.spec.ts index dfc988f387..db46dad999 100644 --- a/integration-tests/modules/__tests__/regions/admin/regions.spec.ts +++ b/integration-tests/modules/__tests__/regions/admin/regions.spec.ts @@ -1,6 +1,6 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { IRegionModuleService } from "@medusajs/types" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) @@ -26,12 +26,6 @@ medusaIntegrationTestRunner({ await createAdminUser(dbConnection, adminHeaders, appContainer) }) - afterEach(async () => { - // TODO: Once teardown doesn't skip constraint checks and cascades, we can remove this - const existingRegions = await service.list({}) - await service.delete(existingRegions.map((r) => r.id)) - }) - it("should create, update, and delete a region", async () => { const created = await api.post( `/admin/regions`, diff --git a/integration-tests/modules/__tests__/store/admin/store.spec.ts b/integration-tests/modules/__tests__/store/admin/store.spec.ts index b46a304205..149c57144b 100644 --- a/integration-tests/modules/__tests__/store/admin/store.spec.ts +++ b/integration-tests/modules/__tests__/store/admin/store.spec.ts @@ -1,6 +1,6 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { IStoreModuleService } from "@medusajs/types" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/tax/admin/tax.spec.ts b/integration-tests/modules/__tests__/tax/admin/tax.spec.ts index 8112758c36..6172f4da11 100644 --- a/integration-tests/modules/__tests__/tax/admin/tax.spec.ts +++ b/integration-tests/modules/__tests__/tax/admin/tax.spec.ts @@ -1,7 +1,7 @@ import { ITaxModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/tax/workflow/tax.spec.ts b/integration-tests/modules/__tests__/tax/workflow/tax.spec.ts index df3e9f8488..7d906b4524 100644 --- a/integration-tests/modules/__tests__/tax/workflow/tax.spec.ts +++ b/integration-tests/modules/__tests__/tax/workflow/tax.spec.ts @@ -1,7 +1,7 @@ import { ITaxModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../helpers/create-admin-user" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { createTaxRateRulesStepId, updateTaxRatesWorkflow, diff --git a/integration-tests/modules/__tests__/users/create-user.spec.ts b/integration-tests/modules/__tests__/users/create-user.spec.ts index 04a855aa82..fb86248def 100644 --- a/integration-tests/modules/__tests__/users/create-user.spec.ts +++ b/integration-tests/modules/__tests__/users/create-user.spec.ts @@ -1,4 +1,4 @@ -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/users/delete-user.spec.ts b/integration-tests/modules/__tests__/users/delete-user.spec.ts index 5ae237315c..ca270094d3 100644 --- a/integration-tests/modules/__tests__/users/delete-user.spec.ts +++ b/integration-tests/modules/__tests__/users/delete-user.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/users/get-me.spec.ts b/integration-tests/modules/__tests__/users/get-me.spec.ts index 1116a424e0..b8d283c7a0 100644 --- a/integration-tests/modules/__tests__/users/get-me.spec.ts +++ b/integration-tests/modules/__tests__/users/get-me.spec.ts @@ -1,4 +1,4 @@ -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils/dist" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/users/list-users.spec.ts b/integration-tests/modules/__tests__/users/list-users.spec.ts index 17a3311364..85f9cc3c5e 100644 --- a/integration-tests/modules/__tests__/users/list-users.spec.ts +++ b/integration-tests/modules/__tests__/users/list-users.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/users/retrieve-user.spec.ts b/integration-tests/modules/__tests__/users/retrieve-user.spec.ts index d4aacc5aac..4139a09fe6 100644 --- a/integration-tests/modules/__tests__/users/retrieve-user.spec.ts +++ b/integration-tests/modules/__tests__/users/retrieve-user.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/users/update-user.spec.ts b/integration-tests/modules/__tests__/users/update-user.spec.ts index fe75de1530..3ae251ca78 100644 --- a/integration-tests/modules/__tests__/users/update-user.spec.ts +++ b/integration-tests/modules/__tests__/users/update-user.spec.ts @@ -1,6 +1,6 @@ import { IUserModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" jest.setTimeout(50000) diff --git a/integration-tests/modules/__tests__/workflow-engine/tests.ts b/integration-tests/modules/__tests__/workflow-engine/tests.ts index b5aa4608c7..3030853d39 100644 --- a/integration-tests/modules/__tests__/workflow-engine/tests.ts +++ b/integration-tests/modules/__tests__/workflow-engine/tests.ts @@ -4,7 +4,7 @@ import { StepResponse, WorkflowData, } from "@medusajs/workflows-sdk" -import { createAdminUser } from "../../helpers/create-admin-user" +import { createAdminUser } from "../../../helpers/create-admin-user" import { medusaIntegrationTestRunner } from "medusa-test-utils" export const workflowEngineTestSuite = ( diff --git a/integration-tests/modules/helpers/create-admin-user.ts b/integration-tests/modules/helpers/create-admin-user.ts deleted file mode 100644 index cbc90a2970..0000000000 --- a/integration-tests/modules/helpers/create-admin-user.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IAuthModuleService } from "@medusajs/types" -import jwt from "jsonwebtoken" -import { getContainer } from "../../environment-helpers/use-container" -import adminSeeder from "../../helpers/admin-seeder" - -export const createAdminUser = async ( - dbConnection, - adminHeaders, - container? -) => { - await adminSeeder(dbConnection) - const appContainer = container ?? getContainer()! - - const authModule: IAuthModuleService = appContainer.resolve( - ModuleRegistrationName.AUTH - ) - const authUser = await authModule.create({ - provider: "emailpass", - entity_id: "admin@medusa.js", - scope: "admin", - app_metadata: { - user_id: "admin_user", - }, - }) - - const token = jwt.sign(authUser, "test") - adminHeaders.headers["authorization"] = `Bearer ${token}` -} diff --git a/packages/medusa-test-utils/src/medusa-test-runner.ts b/packages/medusa-test-utils/src/medusa-test-runner.ts index b4b5cd0c51..f33df322fe 100644 --- a/packages/medusa-test-utils/src/medusa-test-runner.ts +++ b/packages/medusa-test-utils/src/medusa-test-runner.ts @@ -3,12 +3,13 @@ import { initDb } from "./medusa-test-runner-utils/use-db" import { startBootstrapApp } from "./medusa-test-runner-utils/bootstrap-app" import { createDatabase, dropDatabase } from "pg-god" import { ContainerLike } from "@medusajs/types" +import { createMedusaContainer } from "@medusajs/utils" const axios = require("axios").default const keepTables = [ - "store", - "staged_job", + /*"store",*/ + /* "staged_job", "shipping_profile", "fulfillment_provider", "payment_provider", @@ -16,7 +17,7 @@ const keepTables = [ "region_country", "currency", "migrations", - "mikro_orm_migrations", + "mikro_orm_migrations",*/ ] const DB_HOST = process.env.DB_HOST @@ -45,26 +46,19 @@ const dbTestUtilFactory = (): any => ({ forceDelete, schema, }: { forceDelete?: string[]; schema?: string } = {}) { - forceDelete = forceDelete || [] + forceDelete ??= [] const manager = this.db_.manager + schema ??= "public" + await manager.query(`SET session_replication_role = 'replica';`) const tableNames = await manager.query(`SELECT table_name FROM information_schema.tables - WHERE table_schema = '${ - schema ?? "public" - }';`) + WHERE table_schema = '${schema}';`) for (const { table_name } of tableNames) { - if ( - keepTables.includes(table_name) && - !forceDelete.includes(table_name) - ) { - continue - } - await manager.query(`DELETE - FROM "${table_name}";`) + FROM ${schema}."${table_name}";`) } await manager.query(`SET session_replication_role = 'origin';`) @@ -209,9 +203,29 @@ export function medusaIntegrationTestRunner({ shutdown = shutdown_ } + const beforeEach_ = async () => { + const container = options.getContainer() + const copiedContainer = createMedusaContainer({}, container) + + if (process.env.MEDUSA_FF_MEDUSA_V2 != "true") { + const defaultLoader = + require("@medusajs/medusa/dist/loaders/defaults").default + await defaultLoader({ + container: copiedContainer, + }) + } + + const medusaAppLoaderRunner = + require("@medusajs/medusa/dist/loaders/medusa-app").runModulesLoader + await medusaAppLoaderRunner({ + container: copiedContainer, + configModule: container.resolve("configModule"), + }) + } + const afterEach_ = async () => { try { - await dbUtils.teardown({ forceDelete: [], schema }) + await dbUtils.teardown({ schema }) } catch (error) { console.error("Error tearing down database:", error) } @@ -219,6 +233,7 @@ export function medusaIntegrationTestRunner({ return describe("", () => { beforeAll(beforeAll_) + beforeEach(beforeEach_) afterEach(afterEach_) afterAll(async () => { await dbUtils.shutdown(dbName) diff --git a/packages/medusa/src/api-v2/admin/stores/query-config.ts b/packages/medusa/src/api-v2/admin/stores/query-config.ts index 908cab05a0..dc879e64c5 100644 --- a/packages/medusa/src/api-v2/admin/stores/query-config.ts +++ b/packages/medusa/src/api-v2/admin/stores/query-config.ts @@ -4,10 +4,13 @@ export const defaultAdminStoreFields = [ "id", "name", "supported_currency_codes", + "default_currency_code", "default_sales_channel_id", "default_region_id", "default_location_id", "metadata", + "created_at", + "updated_at", ] export const retrieveTransformQueryConfig = { diff --git a/packages/medusa/src/api-v2/admin/stores/route.ts b/packages/medusa/src/api-v2/admin/stores/route.ts index 0c63f37b9d..5f6750481b 100644 --- a/packages/medusa/src/api-v2/admin/stores/route.ts +++ b/packages/medusa/src/api-v2/admin/stores/route.ts @@ -1,9 +1,12 @@ -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString +} from "@medusajs/utils" import { MedusaRequest, MedusaResponse } from "../../../types/routing" import { defaultAdminStoreFields } from "./query-config" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { - const remoteQuery = req.scope.resolve("remoteQuery") + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const queryObject = remoteQueryObjectFromString({ entryPoint: "store", diff --git a/packages/medusa/src/api-v2/admin/stores/validators.ts b/packages/medusa/src/api-v2/admin/stores/validators.ts index 8a8295d9f8..ab761f3252 100644 --- a/packages/medusa/src/api-v2/admin/stores/validators.ts +++ b/packages/medusa/src/api-v2/admin/stores/validators.ts @@ -51,6 +51,10 @@ export class AdminPostStoresStoreReq { @IsArray() supported_currency_codes?: string[] + @IsOptional() + @IsString() + default_currency_code?: string + @IsOptional() @IsString() default_sales_channel_id?: string diff --git a/packages/medusa/src/loaders/medusa-app.ts b/packages/medusa/src/loaders/medusa-app.ts index 02e852b0d5..95135b93cb 100644 --- a/packages/medusa/src/loaders/medusa-app.ts +++ b/packages/medusa/src/loaders/medusa-app.ts @@ -231,4 +231,72 @@ export const loadMedusaApp = async ( return medusaApp } +/** + * Run the modules loader without taking care of anything else. This is useful for running the loader as a separate action or to re run all modules loaders. + * + * @param configModule + * @param container + */ +export async function runModulesLoader({ + configModule, + container, +}: { + configModule: { + modules?: CommonTypes.ConfigModule["modules"] + projectConfig: CommonTypes.ConfigModule["projectConfig"] + } + container: MedusaContainer +}): Promise { + const featureFlagRouter = container.resolve("featureFlagRouter") + const injectedDependencies = { + [ContainerRegistrationKeys.PG_CONNECTION]: container.resolve( + ContainerRegistrationKeys.PG_CONNECTION + ), + [ContainerRegistrationKeys.LOGGER]: container.resolve( + ContainerRegistrationKeys.LOGGER + ), + } + + const sharedResourcesConfig = { + database: { + clientUrl: configModule.projectConfig.database_url, + driverOptions: configModule.projectConfig.database_extra, + debug: !!(configModule.projectConfig.database_logging ?? false), + }, + } + + const configModules = mergeDefaultModules(configModule.modules) + + // Apply default options to legacy modules + for (const moduleKey of Object.keys(configModules)) { + if (!ModulesDefinition[moduleKey]?.isLegacy) { + continue + } + + if (isObject(configModules[moduleKey])) { + ;( + configModules[moduleKey] as Partial + ).options ??= { + database: { + type: "postgres", + url: configModule.projectConfig.database_url, + extra: configModule.projectConfig.database_extra, + schema: configModule.projectConfig.database_schema, + logging: configModule.projectConfig.database_logging, + }, + } + } + } + + await MedusaApp({ + modulesConfig: configModules, + servicesConfig: joinerConfig, + remoteFetchData: remoteQueryFetchData(container), + sharedContainer: container, + sharedResourcesConfig, + injectedDependencies, + loaderOnly: true, + }) +} + export default loadMedusaApp diff --git a/packages/modules-sdk/medusajs-modules-sdk-1.12.6.tgz b/packages/modules-sdk/medusajs-modules-sdk-1.12.6.tgz deleted file mode 100644 index 968452f2038d62c0156e180aa7807e60320380ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28833 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 diff --git a/packages/modules-sdk/src/loaders/module-loader.ts b/packages/modules-sdk/src/loaders/module-loader.ts index ed11bfdda2..5c84e7f013 100644 --- a/packages/modules-sdk/src/loaders/module-loader.ts +++ b/packages/modules-sdk/src/loaders/module-loader.ts @@ -14,18 +14,21 @@ export const moduleLoader = async ({ moduleResolutions, logger, migrationOnly, + loaderOnly, }: { container: MedusaContainer moduleResolutions: Record logger: Logger migrationOnly?: boolean + loaderOnly?: boolean }): Promise => { for (const resolution of Object.values(moduleResolutions ?? {})) { const registrationResult = await loadModule( container, resolution, logger!, - migrationOnly + migrationOnly, + loaderOnly ) if (registrationResult?.error) { @@ -48,7 +51,8 @@ async function loadModule( container: MedusaContainer, resolution: ModuleResolution, logger: Logger, - migrationOnly?: boolean + migrationOnly?: boolean, + loaderOnly?: boolean ): Promise<{ error?: Error } | void> { const modDefinition = resolution.definition const registrationName = modDefinition.registrationName @@ -85,5 +89,11 @@ async function loadModule( return } - return await loadInternalModule(container, resolution, logger, migrationOnly) + return await loadInternalModule( + container, + resolution, + logger, + migrationOnly, + loaderOnly + ) } diff --git a/packages/modules-sdk/src/loaders/utils/load-internal.ts b/packages/modules-sdk/src/loaders/utils/load-internal.ts index e8f8bdb524..bbe11a5122 100644 --- a/packages/modules-sdk/src/loaders/utils/load-internal.ts +++ b/packages/modules-sdk/src/loaders/utils/load-internal.ts @@ -17,7 +17,8 @@ export async function loadInternalModule( container: MedusaContainer, resolution: ModuleResolution, logger: Logger, - migrationOnly?: boolean + migrationOnly?: boolean, + loaderOnly?: boolean ): Promise<{ error?: Error } | void> { const registrationName = resolution.definition.registrationName @@ -121,6 +122,10 @@ export async function loadInternalModule( } } + if (loaderOnly) { + return + } + const moduleService = loadedModule.service container.register({ [registrationName]: asFunction((cradle) => { diff --git a/packages/modules-sdk/src/medusa-app.ts b/packages/modules-sdk/src/medusa-app.ts index 305626ad52..9e4030fb5a 100644 --- a/packages/modules-sdk/src/medusa-app.ts +++ b/packages/modules-sdk/src/medusa-app.ts @@ -67,10 +67,11 @@ export type SharedResources = { } } -async function loadModules( +export async function loadModules( modulesConfig, sharedContainer, - migrationOnly = false + migrationOnly = false, + loaderOnly = false ) { const allModules = {} @@ -111,8 +112,13 @@ async function loadModules( moduleDefinition: definition as ModuleDefinition, moduleExports, migrationOnly, + loaderOnly, })) as LoadedModule + if (loaderOnly) { + return + } + const service = loaded[moduleName] sharedContainer.register({ [service.__definition.registrationName]: asValue(service), @@ -207,6 +213,10 @@ export type MedusaAppOptions = { remoteFetchData?: RemoteFetchDataCallback injectedDependencies?: any onApplicationStartCb?: () => void + /** + * Forces the modules bootstrapper to only run the modules loaders and return prematurely + */ + loaderOnly?: boolean } async function MedusaApp_({ @@ -221,6 +231,7 @@ async function MedusaApp_({ injectedDependencies = {}, onApplicationStartCb, migrationOnly = false, + loaderOnly = false, }: MedusaAppOptions & { migrationOnly?: boolean } = {}): Promise<{ modules: Record link: RemoteLink | undefined @@ -285,7 +296,25 @@ async function MedusaApp_({ }) } - const allModules = await loadModules(modules, sharedContainer_, migrationOnly) + const allModules = await loadModules( + modules, + sharedContainer_, + migrationOnly, + loaderOnly + ) + + if (loaderOnly) { + return { + modules: allModules, + link: undefined, + query: async () => { + throw new Error("Querying not allowed in loaderOnly mode") + }, + runMigrations: async () => { + throw new Error("Migrations not allowed in loaderOnly mode") + }, + } + } // Share Event bus with link modules injectedDependencies[ModuleRegistrationName.EVENT_BUS] = diff --git a/packages/modules-sdk/src/medusa-module.ts b/packages/modules-sdk/src/medusa-module.ts index 39e6cf96fd..ec8d875437 100644 --- a/packages/modules-sdk/src/medusa-module.ts +++ b/packages/modules-sdk/src/medusa-module.ts @@ -65,6 +65,10 @@ export type ModuleBootstrapOptions = { * Don't forget to clear the instances (MedusaModule.clearInstances()) after the migration are done. */ migrationOnly?: boolean + /** + * Forces the modules bootstrapper to only run the modules loaders and return prematurely + */ + loaderOnly?: boolean } export type LinkModuleBootstrapOptions = { @@ -220,6 +224,7 @@ export class MedusaModule { moduleDefinition, injectedDependencies, migrationOnly, + loaderOnly, }: ModuleBootstrapOptions): Promise<{ [key: string]: T }> { @@ -227,25 +232,28 @@ export class MedusaModule { stringifyCircular({ moduleKey, defaultPath, declaration }) ) - if (MedusaModule.instances_.has(hashKey)) { + if (!loaderOnly && MedusaModule.instances_.has(hashKey)) { return MedusaModule.instances_.get(hashKey)! as { [key: string]: T } } - if (MedusaModule.loading_.has(hashKey)) { + if (!loaderOnly && MedusaModule.loading_.has(hashKey)) { return MedusaModule.loading_.get(hashKey) } let finishLoading: any let errorLoading: any - MedusaModule.loading_.set( - hashKey, - new Promise((resolve, reject) => { - finishLoading = resolve - errorLoading = reject - }) - ) + + if (!loaderOnly) { + MedusaModule.loading_.set( + hashKey, + new Promise((resolve, reject) => { + finishLoading = resolve + errorLoading = reject + }) + ) + } let modDeclaration = declaration ?? @@ -294,6 +302,7 @@ export class MedusaModule { moduleResolutions, logger: logger_, migrationOnly, + loaderOnly }) } catch (err) { errorLoading(err) @@ -302,6 +311,10 @@ export class MedusaModule { const services = {} + if (loaderOnly) { + return services + } + for (const resolution of Object.values( moduleResolutions ) as ModuleResolution[]) { diff --git a/packages/region/mikro-orm.config.dev.ts b/packages/region/mikro-orm.config.dev.ts index e6385291c7..b5f6f37912 100644 --- a/packages/region/mikro-orm.config.dev.ts +++ b/packages/region/mikro-orm.config.dev.ts @@ -1,8 +1,12 @@ import * as entities from "./src/models" +import { TSMigrationGenerator } from "@medusajs/utils" module.exports = { entities: Object.values(entities), schema: "public", clientUrl: "postgres://postgres@localhost/medusa-region", type: "postgresql", + migrations: { + generator: TSMigrationGenerator, + }, } diff --git a/packages/region/src/joiner-config.ts b/packages/region/src/joiner-config.ts index ea3587749c..85f7a7bc59 100644 --- a/packages/region/src/joiner-config.ts +++ b/packages/region/src/joiner-config.ts @@ -5,7 +5,7 @@ import { Country, Region } from "@models" export const LinkableKeys = { region_id: Region.name, - country_id: Region.name, + country_iso: Country.name, } const entityLinkableKeysMap: MapToConfig = {} diff --git a/packages/region/src/migrations/RegionModuleSetup20240205173216.ts b/packages/region/src/migrations/RegionModuleSetup20240205173216.ts index 2eb6b65a09..f350b25095 100644 --- a/packages/region/src/migrations/RegionModuleSetup20240205173216.ts +++ b/packages/region/src/migrations/RegionModuleSetup20240205173216.ts @@ -26,14 +26,13 @@ ${generatePostgresAlterColummnIfExistStatement( CREATE INDEX IF NOT EXISTS "IDX_region_deleted_at" ON "region" ("deleted_at") WHERE "deleted_at" IS NOT NULL; -- Create or update "region_country" table CREATE TABLE IF NOT EXISTS "region_country" ( - "id" text NOT NULL, "iso_2" text NOT NULL, "iso_3" text NOT NULL, "num_code" int NOT NULL, "name" text NOT NULL, "display_name" text NOT NULL, "region_id" text NULL, - CONSTRAINT "region_country_pkey" PRIMARY KEY ("id") + CONSTRAINT "region_country_pkey" PRIMARY KEY ("iso_2") ); CREATE UNIQUE INDEX IF NOT EXISTS "IDX_region_country_region_id_iso_2_unique" ON "region_country" (region_id, iso_2); -- Adjust foreign keys for "region_country" diff --git a/packages/region/src/models/country.ts b/packages/region/src/models/country.ts index 1e1ae59f36..85b640f44a 100644 --- a/packages/region/src/models/country.ts +++ b/packages/region/src/models/country.ts @@ -1,18 +1,6 @@ -import { - BeforeCreate, - Entity, - Unique, - ManyToOne, - OnInit, - PrimaryKey, - Property, - Index, -} from "@mikro-orm/core" +import { Entity, ManyToOne, PrimaryKey, Property } from "@mikro-orm/core" -import { - createPsqlIndexStatementHelper, - generateEntityId, -} from "@medusajs/utils" +import { createPsqlIndexStatementHelper } from "@medusajs/utils" import Region from "./region" // We don't need a partial index on deleted_at here since we don't support soft deletes on countries @@ -28,8 +16,6 @@ RegionIdIsoIndexStatement.MikroORMIndex() @Entity({ tableName: "region_country" }) export default class Country { @PrimaryKey({ columnType: "text" }) - id: string - @Property({ columnType: "text" }) iso_2: string @@ -55,14 +41,4 @@ export default class Country { onDelete: "set null", }) region?: Region | null - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "reg_ctry") - } - - @OnInit() - onInit() { - this.id = generateEntityId(this.id, "reg_ctry") - } } diff --git a/packages/store/integration-tests/__tests__/store-module-service.spec.ts b/packages/store/integration-tests/__tests__/store-module-service.spec.ts index 470f236731..f0c92bb06a 100644 --- a/packages/store/integration-tests/__tests__/store-module-service.spec.ts +++ b/packages/store/integration-tests/__tests__/store-module-service.spec.ts @@ -30,6 +30,14 @@ moduleIntegrationTestRunner({ }) }) + it("should fail to get created if default currency code is not in list of supported currency codes", async function () { + const err = await service + .create({ ...createStoreFixture, default_currency_code: "jpy" }) + .catch((err) => err.message) + + expect(err).toEqual("Store does not have currency: jpy") + }) + describe("upserting a store", () => { it("should get created if it does not exist", async function () { const store = await service.upsert(createStoreFixture) @@ -67,6 +75,45 @@ moduleIntegrationTestRunner({ }) expect(updatedStore.title).toEqual("Updated store") }) + + it("should fail updating default currency code to an unsupported one", async function () { + const createdStore = await service.create(createStoreFixture) + const updateErr = await service + .update(createdStore.id, { + default_currency_code: "jpy", + }) + .catch((err) => err.message) + + expect(updateErr).toEqual("Store does not have currency: jpy") + }) + + it("should fail updating default currency code to an unsupported one if the supported currencies are also updated", async function () { + const createdStore = await service.create(createStoreFixture) + const updateErr = await service + .update(createdStore.id, { + supported_currency_codes: ["mkd"], + default_currency_code: "jpy", + }) + .catch((err) => err.message) + + expect(updateErr).toEqual("Store does not have currency: jpy") + }) + + it("should fail updating supported currencies if one of them is used as a default one", async function () { + const createdStore = await service.create({ + ...createStoreFixture, + default_currency_code: "eur", + }) + const updateErr = await service + .update(createdStore.id, { + supported_currency_codes: ["jpy"], + }) + .catch((err) => err.message) + + expect(updateErr).toEqual( + "You are not allowed to remove default currency from store currencies without replacing it as well" + ) + }) }) describe("deleting a store", () => { diff --git a/packages/store/src/migrations/.snapshot-medusa-store.json b/packages/store/src/migrations/.snapshot-medusa-store.json index 5faa1a6990..8dc9b84d92 100644 --- a/packages/store/src/migrations/.snapshot-medusa-store.json +++ b/packages/store/src/migrations/.snapshot-medusa-store.json @@ -35,6 +35,15 @@ "default": "'{}'", "mappedType": "array" }, + "default_currency_code": { + "name": "default_currency_code", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, "default_sales_channel_id": { "name": "default_sales_channel_id", "type": "text", diff --git a/packages/store/src/migrations/InitialSetup20240227075933.ts b/packages/store/src/migrations/InitialSetup20240227075933.ts index 668c1ab991..d27a4d1b12 100644 --- a/packages/store/src/migrations/InitialSetup20240227075933.ts +++ b/packages/store/src/migrations/InitialSetup20240227075933.ts @@ -13,6 +13,12 @@ export class InitialSetup20240226130829 extends Migration { this.addSql( `alter table "store" alter column "name" SET DEFAULT 'Medusa Store';` ) + this.addSql( + `alter table "store" alter column "default_currency_code" TYPE text;` + ) + this.addSql( + `alter table "store" alter column "default_currency_code" drop not null;` + ) this.addSql( `alter table "store" alter column "default_sales_channel_id" TYPE text;` ) @@ -20,7 +26,9 @@ export class InitialSetup20240226130829 extends Migration { `alter table "store" alter column "default_location_id" TYPE text;` ) - this.addSql(`alter table "store" add column "default_region_id" text;`) + this.addSql( + `alter table "store" add column "default_region_id" text null;` + ) this.addSql( `alter table "store" add column "deleted_at" timestamptz null;` ) @@ -32,6 +40,13 @@ export class InitialSetup20240226130829 extends Migration { 'create index if not exists "IDX_store_deleted_at" on "store" (deleted_at) where deleted_at is not null;' ) + this.addSql( + `alter table "store" drop constraint if exists "FK_61b0f48cccbb5f41c750bac7286";` + ) + this.addSql( + `alter table "store" drop constraint if exists "FK_55beebaa09e947cccca554af222";` + ) + // this.addSql(`alter table "store" drop column "default_currency_code";`) // this.addSql(`alter table "store" drop column "swap_link_template";`) // this.addSql(`alter table "store" drop column "payment_link_template";`) @@ -39,7 +54,7 @@ export class InitialSetup20240226130829 extends Migration { } else { this.addSql(`create table if not exists "store" ("id" text not null, "name" text not null default \'Medusa Store\', "supported_currency_codes" text[] not null default \'{}\', - "default_sales_channel_id" text null, "default_region_id" text null, "default_location_id" text null, + "default_currency_code" text null, "default_sales_channel_id" text null, "default_region_id" text null, "default_location_id" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "store_pkey" primary key ("id"));`) diff --git a/packages/store/src/models/store.ts b/packages/store/src/models/store.ts index 8c9015fac2..ab45877f50 100644 --- a/packages/store/src/models/store.ts +++ b/packages/store/src/models/store.ts @@ -38,6 +38,9 @@ export default class Store { @Property({ type: "array", default: "{}" }) supported_currency_codes: string[] = [] + @Property({ columnType: "text", nullable: true }) + default_currency_code: string | null = null + @Property({ columnType: "text", nullable: true }) default_sales_channel_id: string | null = null diff --git a/packages/store/src/services/store-module-service.ts b/packages/store/src/services/store-module-service.ts index adc269aaa3..0c8d77e716 100644 --- a/packages/store/src/services/store-module-service.ts +++ b/packages/store/src/services/store-module-service.ts @@ -11,6 +11,7 @@ import { InjectManager, InjectTransactionManager, MedusaContext, + MedusaError, ModulesSdkUtils, isString, promiseAll, @@ -83,6 +84,8 @@ export default class StoreModuleService @MedusaContext() sharedContext: Context = {} ): Promise { let normalizedInput = StoreModuleService.normalizeInput(data) + StoreModuleService.validateCreateRequest(normalizedInput) + return await this.storeService_.create(normalizedInput, sharedContext) } @@ -169,6 +172,7 @@ export default class StoreModuleService @MedusaContext() sharedContext: Context = {} ): Promise { const normalizedInput = StoreModuleService.normalizeInput(data) + await this.validateUpdateRequest(normalizedInput) return await this.storeService_.update(normalizedInput, sharedContext) } @@ -182,4 +186,80 @@ export default class StoreModuleService }) ) } + + private static validateCreateRequest(stores: StoreTypes.CreateStoreDTO[]) { + for (const store of stores) { + // If we are setting the default currency code on creating, make sure it is supported + if (store.default_currency_code) { + if ( + !store.supported_currency_codes?.includes( + store.default_currency_code ?? "" + ) + ) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Store does not have currency: ${store.default_currency_code}` + ) + } + } + } + } + + private async validateUpdateRequest(stores: UpdateStoreInput[]) { + const dbStores = await this.storeService_.list( + { id: stores.map((s) => s.id) }, + { take: null } + ) + + const dbStoresMap = new Map( + dbStores.map((dbStore) => [dbStore.id, dbStore]) + ) + + for (const store of stores) { + const dbStore = dbStoresMap.get(store.id) + + // If it is updating both the supported currency codes and the default one, look in that list + if (store.supported_currency_codes && store.default_currency_code) { + if ( + !store.supported_currency_codes.includes( + store.default_currency_code ?? "" + ) + ) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Store does not have currency: ${store.default_currency_code}` + ) + } + return + } + + // If it is updating only the default currency code, look in the db store + if (store.default_currency_code) { + if ( + !dbStore?.supported_currency_codes?.includes( + store.default_currency_code + ) + ) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Store does not have currency: ${store.default_currency_code}` + ) + } + } + + // If it is updating only the supported currency codes, make sure one of them is not set as a default one + if (store.supported_currency_codes) { + if ( + !store.supported_currency_codes.includes( + dbStore?.default_currency_code ?? "" + ) + ) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "You are not allowed to remove default currency from store currencies without replacing it as well" + ) + } + } + } + } } diff --git a/packages/types/src/store/common/store.ts b/packages/types/src/store/common/store.ts index a852771d5f..d255dd6c42 100644 --- a/packages/types/src/store/common/store.ts +++ b/packages/types/src/store/common/store.ts @@ -4,10 +4,13 @@ export interface StoreDTO { id: string name: string supported_currency_codes: string[] + default_currency_code?: string default_sales_channel_id?: string default_region_id?: string default_location_id?: string metadata: Record | null + created_at: string + updated_at: string } export interface FilterableStoreProps extends BaseFilterable { diff --git a/packages/types/src/store/mutations/store.ts b/packages/types/src/store/mutations/store.ts index eaf391b3e0..e7ea565819 100644 --- a/packages/types/src/store/mutations/store.ts +++ b/packages/types/src/store/mutations/store.ts @@ -1,6 +1,7 @@ export interface CreateStoreDTO { name?: string supported_currency_codes?: string[] + default_currency_code?: string default_sales_channel_id?: string default_region_id?: string default_location_id?: string @@ -11,6 +12,7 @@ export interface UpsertStoreDTO { id?: string name?: string supported_currency_codes?: string[] + default_currency_code?: string default_sales_channel_id?: string default_region_id?: string default_location_id?: string @@ -20,6 +22,7 @@ export interface UpsertStoreDTO { export interface UpdateStoreDTO { name?: string supported_currency_codes?: string[] + default_currency_code?: string default_sales_channel_id?: string default_region_id?: string default_location_id?: string diff --git a/yarn.lock b/yarn.lock index 6e89889f4f..0ae66844e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31765,15 +31765,30 @@ __metadata: "@babel/cli": ^7.12.10 "@babel/core": ^7.12.10 "@babel/node": ^7.12.10 + "@medusajs/api-key": "workspace:^" + "@medusajs/auth": "workspace:*" "@medusajs/cache-inmemory": "workspace:*" + "@medusajs/customer": "workspace:^" "@medusajs/event-bus-local": "workspace:*" + "@medusajs/inventory": "workspace:^" "@medusajs/medusa": "workspace:*" + "@medusajs/modules-sdk": "workspace:^" + "@medusajs/pricing": "workspace:^" + "@medusajs/product": "workspace:^" + "@medusajs/promotion": "workspace:^" + "@medusajs/region": "workspace:^" + "@medusajs/store": "workspace:^" + "@medusajs/tax": "workspace:^" + "@medusajs/user": "workspace:^" + "@medusajs/utils": "workspace:^" "@medusajs/workflow-engine-inmemory": "workspace:*" babel-preset-medusa-package: "*" faker: ^5.5.3 jest: ^26.6.3 jest-environment-node: 26.6.2 + medusa-fulfillment-webshipper: "workspace:*" medusa-interfaces: "workspace:*" + medusa-plugin-sendgrid: "workspace:*" pg: ^8.11.0 typeorm: ^0.3.16 languageName: unknown