chore: Move factories and helpers to a better place (#4551)
* chore: Move factories and helpers to a better place * align factory product variant * fix factory cart * add simple store fac * fix tests * fix tests * fix * fix cart seeder
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
const path = require("path")
|
||||
const express = require("express")
|
||||
const getPort = require("get-port")
|
||||
|
||||
module.exports = {
|
||||
bootstrapApp: async ({ cwd } = {}) => {
|
||||
const app = express()
|
||||
|
||||
const loaders = require("@medusajs/medusa/dist/loaders").default
|
||||
|
||||
const { container, dbConnection } = await loaders({
|
||||
directory: path.resolve(cwd || process.cwd()),
|
||||
expressApp: app,
|
||||
isTest: false,
|
||||
})
|
||||
|
||||
const PORT = await getPort()
|
||||
|
||||
return {
|
||||
container,
|
||||
db: dbConnection,
|
||||
app,
|
||||
port: PORT,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
const path = require("path")
|
||||
const { spawn } = require("child_process")
|
||||
const { setPort } = require("./use-api")
|
||||
|
||||
module.exports = ({ cwd, redisUrl, uploadDir, verbose, env }) => {
|
||||
const serverPath = path.join(__dirname, "test-server.js")
|
||||
|
||||
// in order to prevent conflicts in redis, use a different db for each worker
|
||||
// same fix as for databases (works with up to 15)
|
||||
// redis dbs are 0-indexed and jest worker ids are indexed from 1
|
||||
const workerId = parseInt(process.env.JEST_WORKER_ID || "1")
|
||||
const redisUrlWithDatabase = `${redisUrl}/${workerId - 1}`
|
||||
|
||||
verbose = verbose ?? false
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const medusaProcess = spawn("node", [path.resolve(serverPath)], {
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: "development",
|
||||
JWT_SECRET: "test",
|
||||
COOKIE_SECRET: "test",
|
||||
REDIS_URL: redisUrl ? redisUrlWithDatabase : undefined, // If provided, will use a real instance, otherwise a fake instance
|
||||
UPLOAD_DIR: uploadDir, // If provided, will be used for the fake local file service
|
||||
...env,
|
||||
},
|
||||
stdio: verbose
|
||||
? ["inherit", "inherit", "inherit", "ipc"]
|
||||
: ["ignore", "ignore", "ignore", "ipc"],
|
||||
})
|
||||
|
||||
medusaProcess.on("error", (err) => {
|
||||
console.log(err)
|
||||
process.exit()
|
||||
})
|
||||
|
||||
medusaProcess.on("uncaughtException", (err) => {
|
||||
console.log(err)
|
||||
medusaProcess.kill()
|
||||
})
|
||||
|
||||
medusaProcess.on("message", (port) => {
|
||||
setPort(port)
|
||||
resolve(medusaProcess)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
const setupServer = require("./setup-server")
|
||||
const { initDb } = require("./use-db")
|
||||
|
||||
const startServerWithEnvironment = async ({
|
||||
cwd,
|
||||
redisUrl,
|
||||
uploadDir,
|
||||
verbose,
|
||||
env,
|
||||
}) => {
|
||||
if (env) {
|
||||
Object.entries(env).forEach(([key, value]) => {
|
||||
process.env[key] = value
|
||||
})
|
||||
}
|
||||
|
||||
const dbConnection = await initDb({
|
||||
cwd,
|
||||
})
|
||||
|
||||
if (env) {
|
||||
Object.entries(env).forEach(([key]) => {
|
||||
delete process.env[key]
|
||||
})
|
||||
}
|
||||
|
||||
const medusaProcess = await setupServer({
|
||||
cwd,
|
||||
verbose,
|
||||
redisUrl,
|
||||
uploadDir,
|
||||
env,
|
||||
})
|
||||
|
||||
return [medusaProcess, dbConnection]
|
||||
}
|
||||
|
||||
export default startServerWithEnvironment
|
||||
@@ -0,0 +1,11 @@
|
||||
const { bootstrapApp } = require("./bootstrap-app")
|
||||
|
||||
const setup = async () => {
|
||||
const { app, port } = await bootstrapApp()
|
||||
|
||||
app.listen(port, (err) => {
|
||||
process.send(port)
|
||||
})
|
||||
}
|
||||
|
||||
setup()
|
||||
@@ -0,0 +1,21 @@
|
||||
const axios = require("axios").default
|
||||
|
||||
const ServerTestUtil = {
|
||||
port_: null,
|
||||
client_: null,
|
||||
|
||||
setPort: function (port) {
|
||||
this.client_ = axios.create({ baseURL: `http://localhost:${port}` })
|
||||
},
|
||||
}
|
||||
|
||||
const instance = ServerTestUtil
|
||||
|
||||
module.exports = {
|
||||
setPort: function (port) {
|
||||
instance.setPort(port)
|
||||
},
|
||||
useApi: function () {
|
||||
return instance.client_
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
const path = require("path")
|
||||
|
||||
const { getConfigFile } = require("medusa-core-utils")
|
||||
const { dropDatabase } = require("pg-god")
|
||||
const { DataSource } = require("typeorm")
|
||||
const dbFactory = require("./use-template-db")
|
||||
|
||||
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 pgGodCredentials = {
|
||||
user: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
host: DB_HOST,
|
||||
}
|
||||
|
||||
const keepTables = [
|
||||
"store",
|
||||
"staged_job",
|
||||
"shipping_profile",
|
||||
"fulfillment_provider",
|
||||
"payment_provider",
|
||||
"country",
|
||||
"currency",
|
||||
]
|
||||
|
||||
const DbTestUtil = {
|
||||
db_: null,
|
||||
|
||||
setDb: function (dataSource) {
|
||||
this.db_ = dataSource
|
||||
},
|
||||
|
||||
clear: async function () {
|
||||
this.db_.synchronize(true)
|
||||
},
|
||||
|
||||
teardown: async function ({ forceDelete } = {}) {
|
||||
forceDelete = forceDelete || []
|
||||
|
||||
const entities = this.db_.entityMetadatas
|
||||
|
||||
const manager = this.db_.manager
|
||||
|
||||
await manager.query(`SET session_replication_role = 'replica';`)
|
||||
|
||||
for (const entity of entities) {
|
||||
if (
|
||||
keepTables.includes(entity.tableName) &&
|
||||
!forceDelete.includes(entity.tableName)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
await manager.query(`DELETE
|
||||
FROM "${entity.tableName}";`)
|
||||
}
|
||||
|
||||
await manager.query(`SET session_replication_role = 'origin';`)
|
||||
},
|
||||
|
||||
shutdown: async function () {
|
||||
await this.db_.destroy()
|
||||
return await dropDatabase({ DB_NAME }, pgGodCredentials)
|
||||
},
|
||||
}
|
||||
|
||||
const instance = DbTestUtil
|
||||
|
||||
module.exports = {
|
||||
initDb: async function ({ cwd, database_extra }) {
|
||||
const { configModule } = getConfigFile(cwd, `medusa-config`)
|
||||
const { featureFlags } = configModule
|
||||
|
||||
const featureFlagsLoader =
|
||||
require("@medusajs/medusa/dist/loaders/feature-flags").default
|
||||
|
||||
const featureFlagsRouter = featureFlagsLoader({ featureFlags })
|
||||
const modelsLoader = require("@medusajs/medusa/dist/loaders/models").default
|
||||
const entities = modelsLoader({}, { register: false })
|
||||
|
||||
await dbFactory.createFromTemplate(DB_NAME)
|
||||
|
||||
// get migrations with enabled featureflags
|
||||
const migrationDir = path.resolve(
|
||||
path.join(
|
||||
__dirname,
|
||||
`../../`,
|
||||
`node_modules`,
|
||||
`@medusajs`,
|
||||
`medusa`,
|
||||
`dist`,
|
||||
`migrations`,
|
||||
`*.js`
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
getEnabledMigrations,
|
||||
getModuleSharedResources,
|
||||
} = require("@medusajs/medusa/dist/commands/utils/get-migrations")
|
||||
|
||||
const { migrations: moduleMigrations, models: moduleModels } =
|
||||
getModuleSharedResources(configModule, featureFlagsRouter)
|
||||
|
||||
const enabledMigrations = getEnabledMigrations([migrationDir], (flag) =>
|
||||
featureFlagsRouter.isFeatureEnabled(flag)
|
||||
)
|
||||
|
||||
const enabledEntities = entities.filter(
|
||||
(e) => typeof e.isFeatureEnabled === "undefined" || e.isFeatureEnabled()
|
||||
)
|
||||
|
||||
const dbDataSource = new DataSource({
|
||||
type: "postgres",
|
||||
url: DB_URL,
|
||||
entities: enabledEntities.concat(moduleModels),
|
||||
migrations: enabledMigrations.concat(moduleMigrations),
|
||||
extra: database_extra ?? {},
|
||||
name: "integration-tests",
|
||||
})
|
||||
|
||||
await dbDataSource.initialize()
|
||||
|
||||
await dbDataSource.runMigrations()
|
||||
|
||||
instance.setDb(dbDataSource)
|
||||
return dbDataSource
|
||||
},
|
||||
useDb: function () {
|
||||
return instance
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
const ServerTestUtil = {
|
||||
server_: null,
|
||||
app_: null,
|
||||
|
||||
setApp: function (app) {
|
||||
this.app_ = app
|
||||
},
|
||||
|
||||
start: async function () {
|
||||
this.server_ = await new Promise((resolve, reject) => {
|
||||
const s = this.app_.listen(PORT, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
resolve(s)
|
||||
})
|
||||
},
|
||||
|
||||
kill: function () {
|
||||
return new Promise((resolve, _) => {
|
||||
if (this.server_) {
|
||||
this.server_.close(() => resolve())
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
const instance = ServerTestUtil
|
||||
|
||||
module.exports = {
|
||||
setApp: function (app) {
|
||||
instance.setApp(app)
|
||||
return instance
|
||||
},
|
||||
|
||||
useServer: function () {
|
||||
return instance
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
const path = require("path")
|
||||
|
||||
require("dotenv").config({ path: path.join(__dirname, "../.env.test") })
|
||||
|
||||
const { getConfigFile } = require("medusa-core-utils")
|
||||
const { createDatabase, dropDatabase } = require("pg-god")
|
||||
const { DataSource } = require("typeorm")
|
||||
|
||||
const DB_HOST = process.env.DB_HOST
|
||||
const DB_USERNAME = process.env.DB_USERNAME
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
||||
const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}`
|
||||
|
||||
let masterDataSource
|
||||
|
||||
const pgGodCredentials = {
|
||||
user: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
host: DB_HOST,
|
||||
}
|
||||
|
||||
class DatabaseFactory {
|
||||
constructor() {
|
||||
this.dataSource_ = null
|
||||
this.masterDataSourceName = "master"
|
||||
this.templateDbName = "medusa-integration-template"
|
||||
}
|
||||
|
||||
async createTemplateDb_({ cwd }) {
|
||||
const { configModule } = getConfigFile(cwd, `medusa-config`)
|
||||
const dataSource = await this.getMasterDataSource()
|
||||
const migrationDir = path.resolve(
|
||||
path.join(
|
||||
__dirname,
|
||||
`../../`,
|
||||
`node_modules`,
|
||||
`@medusajs`,
|
||||
`medusa`,
|
||||
`dist`,
|
||||
`migrations`,
|
||||
`*.js`
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
getEnabledMigrations,
|
||||
getModuleSharedResources,
|
||||
} = require("@medusajs/medusa/dist/commands/utils/get-migrations")
|
||||
|
||||
// filter migrations to only include those that don't have feature flags
|
||||
const enabledMigrations = getEnabledMigrations(
|
||||
[migrationDir],
|
||||
(flag) => false
|
||||
)
|
||||
|
||||
const { migrations: moduleMigrations } =
|
||||
getModuleSharedResources(configModule)
|
||||
|
||||
await dropDatabase(
|
||||
{
|
||||
databaseName: this.templateDbName,
|
||||
errorIfNonExist: false,
|
||||
},
|
||||
pgGodCredentials
|
||||
)
|
||||
await createDatabase(
|
||||
{ databaseName: this.templateDbName },
|
||||
pgGodCredentials
|
||||
)
|
||||
|
||||
const templateDbDataSource = new DataSource({
|
||||
type: "postgres",
|
||||
name: "templateDataSource",
|
||||
url: `${DB_URL}/${this.templateDbName}`,
|
||||
migrations: enabledMigrations.concat(moduleMigrations),
|
||||
})
|
||||
|
||||
await templateDbDataSource.initialize()
|
||||
|
||||
await templateDbDataSource.runMigrations()
|
||||
|
||||
await templateDbDataSource.destroy()
|
||||
|
||||
return dataSource
|
||||
}
|
||||
|
||||
async getMasterDataSource() {
|
||||
masterDataSource = masterDataSource || (await this.createMasterDataSource())
|
||||
return masterDataSource
|
||||
}
|
||||
|
||||
async createMasterDataSource() {
|
||||
const dataSource = new DataSource({
|
||||
type: "postgres",
|
||||
name: this.masterDataSourceName,
|
||||
url: `${DB_URL}`,
|
||||
})
|
||||
await dataSource.initialize()
|
||||
|
||||
return dataSource
|
||||
}
|
||||
|
||||
async createFromTemplate(dbName) {
|
||||
const dataSource = await this.getMasterDataSource()
|
||||
|
||||
await dataSource.query(`DROP DATABASE IF EXISTS "${dbName}";`)
|
||||
await dataSource.query(
|
||||
`CREATE DATABASE "${dbName}" TEMPLATE "${this.templateDbName}";`
|
||||
)
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
const dataSource = await this.getMasterDataSource()
|
||||
|
||||
await dataSource.query(`DROP DATABASE IF EXISTS "${this.templateDbName}";`)
|
||||
await dataSource.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new DatabaseFactory()
|
||||
Reference in New Issue
Block a user