Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(create-medusa-app): add unit tests #7714

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
17 changes: 17 additions & 0 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ jobs:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
21 changes: 21 additions & 0 deletions packages/cli/create-medusa-app/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
transform: {
"^.+\\.[jt]s?$": [
"ts-jest",
{
tsconfig: "tsconfig.spec.json",
isolatedModules: false,
useESM: true,
}
],
},
preset: 'ts-jest',
testEnvironment: `node`,
moduleFileExtensions: [`js`, `jsx`, `ts`, `tsx`, `json`],
extensionsToTreatAsEsm: [".ts"],
moduleNameMapper: {
'(.+)\\.js': '$1'
},
testTimeout: 300000
}
6 changes: 5 additions & 1 deletion packages/cli/create-medusa-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"bin": "dist/index.js",
"license": "MIT",
"scripts": {
"dev": "ts-node --esm src/index.ts",
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --passWithNoTests src",
"dev": "node --loader ts-node/esm src/index.ts",
"start": "node dist/index.js",
"build": "tsc",
"watch": "tsc --watch",
Expand Down Expand Up @@ -45,11 +46,14 @@
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"configstore": "^6.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.40.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.7.0",
"prettier": "^2.8.8",
"ts-jest": "^29.1.4",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
},
Expand Down
5 changes: 2 additions & 3 deletions packages/cli/create-medusa-app/src/commands/create.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import inquirer from "inquirer"
import slugifyType from "slugify"
import chalk from "chalk"
import { getDbClientAndCredentials, runCreateDb } from "../utils/create-db.js"
import runCreateDb, { getDbClientAndCredentials } from "../utils/create-db.js"
import prepareProject from "../utils/prepare-project.js"
import startMedusa from "../utils/start-medusa.js"
import open from "open"
import waitOn from "wait-on"
import ora, { Ora } from "ora"
import fs from "fs"
import path from "path"
import isEmailImported from "validator/lib/isEmail.js"
import logMessage from "../utils/log-message.js"
import createAbortController, {
isAbortError,
Expand All @@ -21,7 +20,7 @@ import ProcessManager from "../utils/process-manager.js"
import { nanoid } from "nanoid"
import { displayFactBox, FactBoxOptions } from "../utils/facts.js"
import { EOL } from "os"
import { runCloneRepo } from "../utils/clone-repo.js"
import runCloneRepo from "../utils/clone-repo.js"
import {
askForNextjsStarter,
installNextjsStarter,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import runCloneRepo from "../clone-repo.js"
import path from "path"
import { rm, stat } from "fs/promises"
import ora, { Ora } from "ora"
import { tmpdir } from "os"

const projectName = "test-store"
const projectPath = path.join(tmpdir(), projectName)
const abortController = new AbortController()
const spinner: Ora = ora()

describe("clone-repo", () => {
afterAll(async () => {
// delete project
await rm(projectPath, {
force: true,
recursive: true
})
})

it("should clone the repo", async () => {
expect.assertions(1)
await runCloneRepo({
projectName: projectPath,
abortController,
spinner
})

return expect((async () => {
await stat(projectPath)
})()).resolves.toBeUndefined()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import ora, { Ora } from "ora"
import runCreateDb from "../create-db.js"
import pg from "pg"
import { nanoid } from "nanoid"
import formatConnectionString from "../format-connection-string.js"

const dbName = `medusa-${nanoid(4)}`
const spinner: Ora = ora()

describe("create-db", () => {
afterEach(async () => {
const client = new pg.Client({
user: process.env.POSTGRES_USER || "postgres",
password: process.env.POSTGRES_PASSWORD || ""
})

await client.connect()

await client.query(`DROP DATABASE IF EXISTS "${dbName}"`)

await client.end()
})

it("should create local db", async () => {
expect.assertions(1)
const client = new pg.Client({
user: process.env.POSTGRES_USER || "postgres",
password: process.env.POSTGRES_PASSWORD || "",
host: process.env.POSTGRES_HOST || "localhost",
port: parseInt(process.env.POSTGRES_PORT || "5432")
})
await client.connect()

let newClient = await runCreateDb({
client,
dbName,
spinner
})

const connectionString = formatConnectionString({
user: newClient.user,
password: newClient.password,
host: newClient.host,
db: dbName
})

await newClient.end()

newClient = new pg.Client({
connectionString
})

return expect((async () => {
await newClient.connect()

await newClient.end()
})()).resolves.toBeUndefined()
})

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import formatConnectionString from "../format-connection-string.js"

const CONNECTION_STRING_REGEX = /(postgresql|postgres):\/\/([^:@\s]*(?::[^@\s]*)?@)?(?<server>[^\/\?\s]+)\b/

describe("format-connection-string", () => {
it("should format string correctly", () => {
const connectionString = formatConnectionString({
user: "postgres",
password: "postgres",
host: "localhost",
db: "medusa"
})

expect(connectionString).toMatch(CONNECTION_STRING_REGEX)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import getEnvVariables, { ADMIN_CORS, AUTH_CORS, DEFAULT_REDIS_URL, STORE_CORS } from "../get-env-variables.js"

const envRegex = {
medusaOnboarding: /MEDUSA_ADMIN_ONBOARDING_TYPE=(?<value>.+)/,
storeCors: /STORE_CORS=(?<value>.+)/,
adminCors: /ADMIN_CORS=(?<value>.+)/,
authCors: /AUTH_CORS=(?<value>.+)/,
redisUrl: /REDIS_URL=(?<value>.+)/,
jwtSecret: /JWT_SECRET=(?<value>.+)/,
cookieSecret: /COOKIE_SECRET=(?<value>.+)/,
db: /DATABASE_URL=(?<value>.+)/,
postgresUrl: /POSTGRES_URL=(?<value>.+)/,
onboardingNextjs: /MEDUSA_ADMIN_ONBOARDING_NEXTJS_DIRECTORY=(?<value>.+)/,
}

describe("get-env-variables", () => {
it("should retrieve default environment variables", () => {
const envVariables = getEnvVariables({
// The URL itself doesn't matter here
dbConnectionString: "example-url"
})

const onboardingTypeMatch = envVariables.match(envRegex.medusaOnboarding)
expect(onboardingTypeMatch?.groups?.value).toEqual("default")

const storeCorsMatch = envVariables.match(envRegex.storeCors)
expect(storeCorsMatch?.groups?.value).toEqual(STORE_CORS)

const adminCorsMatch = envVariables.match(envRegex.adminCors)
expect(adminCorsMatch?.groups?.value).toEqual(ADMIN_CORS)

const authCorsMatch = envVariables.match(envRegex.authCors)
expect(authCorsMatch?.groups?.value).toEqual(AUTH_CORS)

const redisUrlMatch = envVariables.match(envRegex.redisUrl)
expect(redisUrlMatch?.groups?.value).toEqual(DEFAULT_REDIS_URL)

const jwtSecretMatch = envVariables.match(envRegex.jwtSecret)
expect(jwtSecretMatch?.groups?.value).toEqual("supersecret")

const cookieSecretMatch = envVariables.match(envRegex.cookieSecret)
expect(cookieSecretMatch?.groups?.value).toEqual("supersecret")

expect(envVariables).toMatch(envRegex.db)
expect(envVariables).toMatch(envRegex.postgresUrl)
expect(envVariables).not.toMatch(envRegex.onboardingNextjs)
})

it("shouldn't retrieve db variables", () => {
const envVariables = getEnvVariables({
dbConnectionString: "example-url",
skipDb: true
})

expect(envVariables).not.toMatch(envRegex.db)
expect(envVariables).not.toMatch(envRegex.postgresUrl)
})

it("should set next.js onboarding env variable", () => {
const envVariables = getEnvVariables({
dbConnectionString: "example-url",
nextjsDirectory: "test"
})

expect(envVariables).toMatch(envRegex.onboardingNextjs)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import postgresClient from "../postgres-client.js"

describe("postgres-client", () => {
it("should retrieve a connected client", async () => {
expect.assertions(1)
return expect((async () => {
const client = await postgresClient({
user: process.env.POSTGRES_USER || "postgres",
password: process.env.POSTGRES_PASSWORD || "",
host: process.env.POSTGRES_HOST || "localhost",
port: parseInt(process.env.POSTGRES_PORT || "5432")
})

await client.end()
})()).resolves.toBeUndefined()
})

it("shouldn't connect to database", async () => {
expect.assertions(1)
return expect((async () => {
await postgresClient({
user: "test",
password: "test"
})
})()).rejects.toThrow()
})
})
6 changes: 3 additions & 3 deletions packages/cli/create-medusa-app/src/utils/clone-repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type CloneRepoOptions = {
const DEFAULT_REPO = "https://github.com/medusajs/medusa-starter-default"
const V2_BRANCH = "feat/v2"

export default async function cloneRepo({
export async function cloneRepo({
directoryName = "",
repoUrl,
abortController,
Expand All @@ -32,15 +32,15 @@ export default async function cloneRepo({
)
}

export async function runCloneRepo({
export default async function runCloneRepo({
projectName,
repoUrl,
abortController,
spinner,
verbose = false,
}: {
projectName: string
repoUrl: string
repoUrl?: string
abortController: AbortController
spinner: Ora
verbose?: boolean
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/create-medusa-app/src/utils/create-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ type CreateDbOptions = {
db: string
}

export default async function createDb({ client, db }: CreateDbOptions) {
export async function createDb({ client, db }: CreateDbOptions) {
await client.query(`CREATE DATABASE "${db}"`)
}

export async function runCreateDb({
export default async function runCreateDb({
client,
dbName,
spinner,
Expand Down
1 change: 0 additions & 1 deletion packages/cli/create-medusa-app/src/utils/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const execute = async (
childProcess.signal &&
["SIGINT", "SIGTERM"].includes(childProcess.signal)
) {
console.log("abortingggg")
throw getAbortError()
}

Expand Down
28 changes: 28 additions & 0 deletions packages/cli/create-medusa-app/src/utils/get-env-variables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { EOL } from "os"
import { PrepareOptions } from "./prepare-project.js"

export const STORE_CORS = "http://localhost:8000,https://docs.medusajs.com,https://medusa-docs-v2-git-docs-v2-medusajs.vercel.app,https://medusa-resources-git-docs-v2-medusajs.vercel.app"
export const ADMIN_CORS = "http://localhost:7000,http://localhost:7001,https://docs.medusajs.com,https://medusa-docs-v2-git-docs-v2-medusajs.vercel.app,https://medusa-resources-git-docs-v2-medusajs.vercel.app"
export const AUTH_CORS = ADMIN_CORS
export const DEFAULT_REDIS_URL = "redis://localhost:6379"

type Options = Pick<PrepareOptions, "onboardingType" | "skipDb" | "dbConnectionString" | "nextjsDirectory">

export default function getEnvVariables({
onboardingType = "default",
skipDb,
dbConnectionString,
nextjsDirectory
}: Options): string {
let env = `MEDUSA_ADMIN_ONBOARDING_TYPE=${onboardingType}${EOL}STORE_CORS=${STORE_CORS}${EOL}ADMIN_CORS=${ADMIN_CORS}${EOL}AUTH_CORS=${AUTH_CORS}${EOL}REDIS_URL=${DEFAULT_REDIS_URL}${EOL}JWT_SECRET=supersecret${EOL}COOKIE_SECRET=supersecret`

if (!skipDb) {
env += `${EOL}DATABASE_URL=${dbConnectionString}${EOL}POSTGRES_URL=${dbConnectionString}`
}

if (nextjsDirectory) {
env += `${EOL}MEDUSA_ADMIN_ONBOARDING_NEXTJS_DIRECTORY=${nextjsDirectory}`
}

return env
}
Loading
Loading