From 132cc21d0fc095603be29bd50e507c5986ccebf3 Mon Sep 17 00:00:00 2001 From: Krzysztof Polak Date: Thu, 26 Feb 2026 11:01:38 +0100 Subject: [PATCH 1/5] test: add Medusa integration test setup --- .changeset/bright-birds-laugh.md | 5 +++ docker-compose.test.yml | 22 +++++++++++ .../http/slack-service.workflow.spec.ts | 39 +++++++++++++++++++ integration-tests/setup.js | 3 ++ jest.config.js | 39 +++++++++++++++++++ medusa-config.ts | 18 +++++++++ package.json | 10 ++++- 7 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 .changeset/bright-birds-laugh.md create mode 100644 docker-compose.test.yml create mode 100644 integration-tests/http/slack-service.workflow.spec.ts create mode 100644 integration-tests/setup.js create mode 100644 jest.config.js create mode 100644 medusa-config.ts diff --git a/.changeset/bright-birds-laugh.md b/.changeset/bright-birds-laugh.md new file mode 100644 index 0000000..c7865c8 --- /dev/null +++ b/.changeset/bright-birds-laugh.md @@ -0,0 +1,5 @@ +--- +"@codee-sh/medusa-plugin-notification-emails": patch +--- + +Add Medusa integration test setup and local Docker DB config for workflow testing. diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..b6d9fc3 --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,22 @@ +version: "3.8" + +services: + postgres-test: + image: postgres:16-alpine + container_name: medusa-plugin-test-db + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - medusa_plugin_test_db:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 10 + +volumes: + medusa_plugin_test_db: diff --git a/integration-tests/http/slack-service.workflow.spec.ts b/integration-tests/http/slack-service.workflow.spec.ts new file mode 100644 index 0000000..4d8948f --- /dev/null +++ b/integration-tests/http/slack-service.workflow.spec.ts @@ -0,0 +1,39 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" +import { slackServiceWorkflow } from "../../src/workflows/mpn-builder-services/slack-service" + +medusaIntegrationTestRunner({ + moduleName: "notification-emails", + medusaConfigFile: process.cwd(), + testSuite: ({ getContainer }) => { + describe("slackServiceWorkflow", () => { + jest.setTimeout(60 * 1000) + + it("renders a system Slack template", async () => { + const { result } = await slackServiceWorkflow( + getContainer() + ).run({ + input: { + template_id: "system_order-placed", + data: { + backendUrl: "http://localhost:9000", + order: { + id: "order_123", + name: "Test Order", + display_id: "123", + }, + }, + options: { + locale: "en", + theme: {}, + translations: {}, + backendUrl: "http://localhost:9000", + }, + }, + }) + + expect(Array.isArray(result.blocks)).toBe(true) + expect(result.blocks.length).toBeGreaterThan(0) + }) + }) + }, +}) diff --git a/integration-tests/setup.js b/integration-tests/setup.js new file mode 100644 index 0000000..a010184 --- /dev/null +++ b/integration-tests/setup.js @@ -0,0 +1,3 @@ +const { MetadataStorage } = require("@mikro-orm/core") + +MetadataStorage.clear() diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5cae14e --- /dev/null +++ b/jest.config.js @@ -0,0 +1,39 @@ +const { loadEnv } = require("@medusajs/framework/utils") + +loadEnv("test", process.cwd()) + +module.exports = { + transform: { + "^.+\\.[jt]sx?$": [ + "@swc/jest", + { + jsc: { + parser: { + syntax: "typescript", + decorators: true, + tsx: true, + }, + target: "es2021", + }, + }, + ], + }, + testEnvironment: "node", + moduleFileExtensions: ["js", "ts", "tsx", "jsx", "json"], + modulePathIgnorePatterns: ["dist/"], + setupFiles: ["./integration-tests/setup.js"], +} + +if (process.env.TEST_TYPE === "integration:http") { + module.exports.testMatch = [ + "**/integration-tests/http/*.spec.[jt]s", + ] +} else if (process.env.TEST_TYPE === "integration:modules") { + module.exports.testMatch = [ + "**/src/modules/*/__tests__/**/*.[jt]s", + ] +} else if (process.env.TEST_TYPE === "unit") { + module.exports.testMatch = [ + "**/src/**/__tests__/**/*.unit.spec.[jt]s", + ] +} diff --git a/medusa-config.ts b/medusa-config.ts new file mode 100644 index 0000000..5516922 --- /dev/null +++ b/medusa-config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "@medusajs/framework/utils" + +export default defineConfig({ + projectConfig: { + http: { + adminCors: "", + authCors: "", + storeCors: "", + jwtSecret: "test", + cookieSecret: "test", + }, + }, + modules: { + mpnBuilder: { + resolve: "./modules/mpn-builder", + }, + }, +}) diff --git a/package.json b/package.json index dc0f331..df6258f 100755 --- a/package.json +++ b/package.json @@ -38,6 +38,9 @@ "publish-local": "npx medusa plugin:publish", "publish-package": "dotenv npm publish --access public", "email:dev": "email dev --dir emails-previews", + "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent", + "test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", + "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", "format": "prettier --write \"src/**/*.{ts,tsx}\"", "format:check": "prettier --check \"src/**/*.{ts,tsx}\"", "changeset": "changeset", @@ -77,11 +80,15 @@ "@react-email/preview-server": "^4.3.1", "@react-email/render": "^1.4.0", "@swc/core": "1.5.7", + "@swc/jest": "^0.2.36", + "@types/jest": "^29.5.14", + "@types/lodash": "^4.17.23", "@types/node": "^20.0.0", "@types/react": "^18.3.2", "@types/react-dom": "^18.2.25", "awilix": "^8.0.1", "dotenv": "^17.2.3", + "jest": "^29.7.0", "prettier": "^3.0.0", "prop-types": "^15.8.1", "react": "^18.2.0", @@ -91,8 +98,7 @@ "ts-node": "^10.9.2", "typescript": "^5.6.2", "vite": "^5.2.11", - "yalc": "^1.0.0-pre.53", - "@types/lodash": "^4.17.23" + "yalc": "^1.0.0-pre.53" }, "engines": { "node": ">=20" From 1a846a1d19ba004ae1682c8617bf851e760a48c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Polak Date: Thu, 26 Feb 2026 11:07:29 +0100 Subject: [PATCH 2/5] docs: add tests guide to documentation and update skills references --- .ai/skills/docs/SKILL.md | 1 + AGENTS.md | 8 +-- README.md | 1 + docs/tests.md | 125 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 docs/tests.md diff --git a/.ai/skills/docs/SKILL.md b/.ai/skills/docs/SKILL.md index 204d6af..d4ba4b3 100644 --- a/.ai/skills/docs/SKILL.md +++ b/.ai/skills/docs/SKILL.md @@ -20,6 +20,7 @@ Each file has a strict scope. Do not mix responsibilities between files. | `docs/blocks.md` | Block types, DB model vs final render model, block catalog | Technical reference | | `docs/translations.md` | i18n system, interpolation, custom translations, adding locales | Technical reference | | `docs/admin.md` | Admin panel user guide — what you can do, typical workflow | User-facing, no endpoints | +| `docs/tests.md` | Tests | User-facing, no endpoints | | `docs/contributing/creating-templates.md` | Step-by-step guide for contributors creating new templates | Tutorial | ## Writing Rules diff --git a/AGENTS.md b/AGENTS.md index 0ab3794..cc89dec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -156,6 +156,7 @@ Do not rely on `{{translations.*}}`. - `docs/blocks.md` — block system, DB model, final catalog - `docs/translations.md` — i18n system, interpolation - `docs/admin.md` — admin panel user guide +- `docs/tests.md` — tests guide - `docs/contributing/creating-templates.md` — contributor template guide - `CONTRIBUTING.md` — branch model, PR rules, release process @@ -165,10 +166,7 @@ Project skills are in `.ai/skills/` (symlinked to `.cursor/skills/` and `.codex/ | Skill | When to use | |-------|-------------| -| `plugin-docs-authoring` | Writing or updating documentation | -| `template-blocks-architecture` | Changes to template/block system | -| `release-pr-hygiene` | Preparing release PRs and changesets | -| `medusa-plugin-context` | Quick domain context before any work | +| `docs` | Writing or updating documentation | ## Rules for Agents @@ -176,5 +174,5 @@ Project skills are in `.ai/skills/` (symlinked to `.cursor/skills/` and `.codex/ 2. Follow the branch model: feature work from `develop`, PRs to `develop`. 3. Add a changeset (`yarn changeset`) for any user-facing change. 4. Use consistent terminology: `system`, `db`, `external`, `blocks`, `mpn-builder`, `workflow`. -5. When changing docs, follow the `plugin-docs-authoring` skill. +5. When changing docs, follow the `docs` skill. 6. Do not commit `.env`, `node_modules`, `.medusa/`, or build artifacts. diff --git a/README.md b/README.md index 8d6f4e5..63008a0 100755 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Template IDs are resolved by prefix: - [Blocks](./docs/blocks.md) - [Translations](./docs/translations.md) - [Admin](./docs/admin.md) +- [Tests](./docs/tests.md) - [Creating Templates](./docs/contributing/creating-templates.md) ## Exports diff --git a/docs/tests.md b/docs/tests.md new file mode 100644 index 0000000..39ea0b7 --- /dev/null +++ b/docs/tests.md @@ -0,0 +1,125 @@ +This document explains how to run and create tests for this plugin. + +## What You Can Do + +- Run integration tests for workflows. +- Use a local Docker Postgres for tests. +- Add new test files that follow Medusa’s testing conventions. + +## Prerequisites + +- Node.js 20+ +- Yarn 4 +- Docker Desktop + +## Local Test Database + +Start the Docker Postgres used by integration tests: + +```bash +docker compose -f docker-compose.test.yml up -d +``` + +The container binds to `localhost:5432`. If port `5432` is already in use, +stop the local Postgres process: + +```bash +sudo lsof -nP | grep ":5432" | head -n 20 +``` + +Then stop the process reported by the command: + +```bash +sudo kill +``` + +## Environment Variables + +Integration tests load `.env.test` if present, otherwise `.env`. +Make sure these variables exist for the test database: + +```env +DB_HOST=localhost +DB_USERNAME=postgres +DB_PASSWORD=postgres +``` + +## Run Tests + +Integration HTTP tests: + +```bash +yarn test:integration:http +``` + +Integration module tests: + +```bash +yarn test:integration:modules +``` + +Unit tests: + +```bash +yarn test:unit +``` + +## Create Tests + +Integration HTTP tests go in: + +```text +integration-tests/http/*.spec.ts +``` + +Integration module tests go in: + +```text +src/modules/*/__tests__/**/*.ts +``` + +Unit tests go in: + +```text +src/**/__tests__/**/*.unit.spec.ts +``` + +## Example Workflow Test + +```ts +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" +import { slackServiceWorkflow } from "../../src/workflows/mpn-builder-services/slack-service" + +medusaIntegrationTestRunner({ + moduleName: "notification-emails", + medusaConfigFile: process.cwd(), + testSuite: ({ getContainer }) => { + describe("slackServiceWorkflow", () => { + it("renders a system Slack template", async () => { + const { result } = await slackServiceWorkflow(getContainer()).run({ + input: { + template_id: "system_order-placed", + data: { + backendUrl: "http://localhost:9000", + order: { id: "order_123" }, + }, + options: { + locale: "en", + theme: {}, + translations: {}, + backendUrl: "http://localhost:9000", + }, + }, + }) + + expect(Array.isArray(result.blocks)).toBe(true) + }) + }) + }, +}) +``` + +## See Also + +- [Configuration](./configuration.md) +- [Templates](./templates.md) From 0228f5677e381dd2294329e23233a7fc39ad8737 Mon Sep 17 00:00:00 2001 From: Krzysztof Polak Date: Thu, 26 Feb 2026 11:08:34 +0100 Subject: [PATCH 3/5] docs: enhance tests documentation with database setup and cleanup instructions --- docs/tests.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/tests.md b/docs/tests.md index 39ea0b7..4b421b5 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -44,6 +44,15 @@ DB_USERNAME=postgres DB_PASSWORD=postgres ``` +`medusaIntegrationTestRunner` creates a temporary database for each run, +and overrides `projectConfig.databaseUrl`. The values above are used to +create and drop databases. `DATABASE_URL` is not used for tests. + +The database user must have permission to create and drop databases. + +Port configuration is not supported by the test runner, so tests must +connect through port `5432`. + ## Run Tests Integration HTTP tests: @@ -64,6 +73,14 @@ Unit tests: yarn test:unit ``` +## Cleanup + +Stop and remove the test database container and volume: + +```bash +docker compose -f docker-compose.test.yml down -v +``` + ## Create Tests Integration HTTP tests go in: From 8ee02f0987177386363ddfff4272724e250cff28 Mon Sep 17 00:00:00 2001 From: Krzysztof Polak Date: Thu, 26 Feb 2026 11:11:10 +0100 Subject: [PATCH 4/5] chore: add database management scripts for testing in package.json --- docs/tests.md | 4 ++-- package.json | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/tests.md b/docs/tests.md index 4b421b5..cdad704 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -17,7 +17,7 @@ This document explains how to run and create tests for this plugin. Start the Docker Postgres used by integration tests: ```bash -docker compose -f docker-compose.test.yml up -d +yarn test:db:up ``` The container binds to `localhost:5432`. If port `5432` is already in use, @@ -78,7 +78,7 @@ yarn test:unit Stop and remove the test database container and volume: ```bash -docker compose -f docker-compose.test.yml down -v +yarn test:db:down ``` ## Create Tests diff --git a/package.json b/package.json index df6258f..c0d87c7 100755 --- a/package.json +++ b/package.json @@ -41,6 +41,8 @@ "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent", "test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", + "test:db:up": "docker compose -f docker-compose.test.yml up -d", + "test:db:down": "docker compose -f docker-compose.test.yml down -v", "format": "prettier --write \"src/**/*.{ts,tsx}\"", "format:check": "prettier --check \"src/**/*.{ts,tsx}\"", "changeset": "changeset", From 615c839b93f58babf06f118a09792ab40d355712 Mon Sep 17 00:00:00 2001 From: Krzysztof Polak Date: Thu, 26 Feb 2026 11:18:04 +0100 Subject: [PATCH 5/5] docs: update AGENTS.md with new testing commands and shell script descriptions --- .ai/skills/README.md | 8 +------- AGENTS.md | 12 ++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.ai/skills/README.md b/.ai/skills/README.md index eeb0dbe..75af279 100644 --- a/.ai/skills/README.md +++ b/.ai/skills/README.md @@ -6,13 +6,7 @@ This directory contains project-level skills for AI coding agents. ``` .ai/skills/ - plugin-docs-authoring/ - SKILL.md - template-blocks-architecture/ - SKILL.md - release-pr-hygiene/ - SKILL.md - medusa-plugin-context/ + docs/ SKILL.md ``` diff --git a/AGENTS.md b/AGENTS.md index cc89dec..f6d66a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,8 +23,20 @@ yarn prepublishOnly # build before publish (medusa plugin:build) yarn publish-local # publish locally (npx medusa plugin:publish) yarn publish-package # publish to npm (dotenv npm publish --access public) yarn email:dev # preview email templates (react-email dev server) +yarn test:unit # run unit tests +yarn test:integration:http # run integration HTTP tests +yarn test:integration:modules # run integration module tests +yarn test:db:up # start test Postgres (Docker) +yarn test:db:down # stop and remove test Postgres (Docker) ``` +## Shell Scripts + +Daily workflow helpers in `scripts/`: + +- `scripts/create-pr.sh` — create a PR (used by `yarn pr:create`). +- `scripts/prepare-release.sh` — prepare a release branch (used by `yarn prepare-release`). + ## Code Style - Prettier: 60-char print width, no semicolons, double quotes, trailing commas (es5)