From 6474e4b328855425cae27089f75b87c244357c4c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 18 Jul 2025 16:33:36 +0300 Subject: [PATCH] docs: add inject dependencies section in module tests + improvements (#12993) --- .../modules-tests/module-example/page.mdx | 83 ----------- .../testing-tools/modules-tests/page.mdx | 87 ++++++++++- .../testing-tools/page.mdx | 2 +- www/apps/book/generated/edit-dates.mjs | 5 +- www/apps/book/generated/sidebar.mjs | 13 +- www/apps/book/public/llms-full.txt | 141 +++++++++--------- www/apps/book/sidebar.mjs | 7 - www/apps/book/utils/redirects.mjs | 6 + 8 files changed, 161 insertions(+), 183 deletions(-) delete mode 100644 www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx diff --git a/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx b/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx deleted file mode 100644 index d8ac8fb9af..0000000000 --- a/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx +++ /dev/null @@ -1,83 +0,0 @@ -import { Prerequisites } from "docs-ui" - -export const metadata = { - title: `${pageNumber} Example: Integration Tests for a Module`, -} - -# {metadata.title} - -In this chapter, find an example of writing an integration test for a module using [moduleIntegrationTestRunner](../page.mdx) from Medusa's Testing Framework. - - - -## Write Integration Test for Module - -Consider a `blog` module with a `BlogModuleService` that has a `getMessage` method: - -```ts title="src/modules/blog/service.ts" -import { MedusaService } from "@medusajs/framework/utils" -import MyCustom from "./models/my-custom" - -class BlogModuleService extends MedusaService({ - MyCustom, -}){ - getMessage(): string { - return "Hello, World!" - } -} - -export default BlogModuleService -``` - -To create an integration test for the method, create the file `src/modules/blog/__tests__/service.spec.ts` with the following content: - -```ts title="src/modules/blog/__tests__/service.spec.ts" -import { moduleIntegrationTestRunner } from "@medusajs/test-utils" -import { BLOG_MODULE } from ".." -import BlogModuleService from "../service" -import MyCustom from "../models/my-custom" - -moduleIntegrationTestRunner({ - moduleName: BLOG_MODULE, - moduleModels: [MyCustom], - resolve: "./src/modules/blog", - testSuite: ({ service }) => { - describe("BlogModuleService", () => { - it("says hello world", () => { - const message = service.getMessage() - - expect(message).toEqual("Hello, World!") - }) - }) - }, -}) - -jest.setTimeout(60 * 1000) -``` - -You use the `moduleIntegrationTestRunner` function to add tests for the `blog` module. You have one test that passes if the `getMessage` method returns the `"Hello, World!"` string. - ---- - -## Run Test - -Run the following command to run your module integration tests: - -```bash npm2yarn -npm run test:integration:modules -``` - - - -If you don't have a `test:integration:modules` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands). - - - -This runs your Medusa application and runs the tests available in any `__tests__` directory under the `src/modules` directory. diff --git a/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx b/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx index b3278d9b6e..a9ccc057f2 100644 --- a/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx +++ b/www/apps/book/app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx @@ -19,9 +19,26 @@ In this chapter, you'll learn about `moduleIntegrationTestRunner` from Medusa's ## moduleIntegrationTestRunner Utility -`moduleIntegrationTestRunner` creates integration tests for a module. The integration tests run on a test Medusa application with only the specified module enabled. +`moduleIntegrationTestRunner` creates integration tests for a module's service. The integration tests run on a test Medusa application with only the specified module enabled. -For example, assuming you have a `blog` module, create a test file at `src/modules/blog/__tests__/service.spec.ts`: +For example, consider a Blog Module with a `BlogModuleService` that has a `getMessage` method: + +```ts title="src/modules/blog/service.ts" +import { MedusaService } from "@medusajs/framework/utils" +import Post from "./models/post" + +class BlogModuleService extends MedusaService({ + Post, +}){ + async getMessage(): Promise { + return "Hello, World!" + } +} + +export default BlogModuleService +``` + +To create an integration test for the module's service, create the file `src/modules/blog/__tests__/service.spec.ts` with the following content: ```ts title="src/modules/blog/__tests__/service.spec.ts" import { moduleIntegrationTestRunner } from "@medusajs/test-utils" @@ -34,7 +51,13 @@ moduleIntegrationTestRunner({ moduleModels: [Post], resolve: "./src/modules/blog", testSuite: ({ service }) => { - // TODO write tests + describe("BlogModuleService", () => { + it("says hello world", () => { + const message = service.getMessage() + + expect(message).toEqual("Hello, World!") + }) + }) }, }) @@ -43,10 +66,10 @@ jest.setTimeout(60 * 1000) The `moduleIntegrationTestRunner` function accepts as a parameter an object with the following properties: -- `moduleName`: The name of the module. +- `moduleName`: The registration name of the module. - `moduleModels`: An array of models in the module. Refer to [this section](#write-tests-for-modules-without-data-models) if your module doesn't have data models. - `resolve`: The path to the module's directory. -- `testSuite`: A function that defines the tests to run. +- `testSuite`: A function that defines [Jest](https://jestjs.io/) tests to run. The `testSuite` function accepts as a parameter an object having the `service` property, which is an instance of the module's main service. @@ -96,6 +119,8 @@ moduleIntegrationTestRunner({ }) ``` +`moduleOptions` is an object of key-value pair options that your module's service receives in its constructor. + --- ## Write Tests for Modules without Data Models @@ -123,6 +148,58 @@ jest.setTimeout(60 * 1000) --- +## Inject Dependencies in Module Tests + +Some modules have injected dependencies, such as the [Event Module's service](!resources!/infrastructure-modules/event). When writing tests for those modules, you need to inject the dependencies that the module's service requires to avoid errors. + +You can inject dependencies as mock dependencies that simulate the behavior of the original service. This way you avoid unexpected behavior or results, such as sending real events or making real API calls. + +To inject dependencies, pass the `injectedDependencies` property to the `moduleIntegrationTestRunner` function. + +For example: + +export const mockDependenciesHighlights = [ + ["11", "injectedDependencies", "Inject dependencies into the module's service."], + ["12", "Modules.EVENT_BUS", "The registration name of the dependency."], + ["12", "MockEventBusService", "The mock service to inject."] +] + +```ts title="src/modules/blog/__tests__/service.spec.ts" highlights={mockDependenciesHighlights} +import { MockEventBusService, moduleIntegrationTestRunner } from "@medusajs/test-utils" +import { BLOG_MODULE } from ".." +import BlogModuleService from "../service" +import Post from "../models/post" +import { Modules } from "@medusajs/framework/utils" + +moduleIntegrationTestRunner({ + moduleName: BLOG_MODULE, + moduleModels: [Post], + resolve: "./src/modules/blog", + injectedDependencies: { + [Modules.EVENT_BUS]: new MockEventBusService() + }, + testSuite: ({ service }) => { + describe("BlogModuleService", () => { + it("says hello world", async () => { + const message = await service.getMessage() + + expect(message).toEqual("Hello, World!") + }) + }) + }, +}) + +jest.setTimeout(60 * 1000) +``` + +`injectedDependencies`'s value is an object whose keys are registration names of the dependencies you want to inject, and the values are the mock services. + +In this example, you inject a mock Event Module service into the `BlogModuleService`. Medusa exposes a `MockEventBusService` class that you can use to mock the Event Module's service. + +For other modules, you can create a mock service that implements the same interface as the original service. Make sure to use the same registration name as the original service when injecting it. + +--- + ### Other Options and Inputs Refer to [the Test Tooling Reference](!resources!/test-tools-reference/moduleIntegrationTestRunner) for other available parameter options and inputs of the `testSuite` function. diff --git a/www/apps/book/app/learn/debugging-and-testing/testing-tools/page.mdx b/www/apps/book/app/learn/debugging-and-testing/testing-tools/page.mdx index 8f64553872..b9b39d07f1 100644 --- a/www/apps/book/app/learn/debugging-and-testing/testing-tools/page.mdx +++ b/www/apps/book/app/learn/debugging-and-testing/testing-tools/page.mdx @@ -78,7 +78,7 @@ Finally, add the following scripts to `package.json`: "scripts": { // ... "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 --runInBand --forceExit", + "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit" }, ``` diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index 834fc359d7..3eabaf6fc4 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -53,7 +53,7 @@ export const generatedEditDates = { "app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-03-18T15:06:27.864Z", "app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-12-09T15:52:01.019Z", "app/learn/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2025-02-11T15:56:03.835Z", - "app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-01-31T13:19:02.587Z", + "app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-07-18T12:02:52.835Z", "app/learn/debugging-and-testing/testing-tools/unit-tests/module-example/page.mdx": "2024-09-02T11:04:27.232Z", "app/learn/debugging-and-testing/testing-tools/unit-tests/page.mdx": "2024-09-02T11:03:26.997Z", "app/learn/fundamentals/modules/service-constraints/page.mdx": "2025-03-18T15:12:46.006Z", @@ -61,8 +61,7 @@ export const generatedEditDates = { "app/learn/fundamentals/api-routes/validation/page.mdx": "2025-03-24T06:52:47.896Z", "app/learn/fundamentals/api-routes/errors/page.mdx": "2025-06-19T16:09:08.563Z", "app/learn/fundamentals/admin/constraints/page.mdx": "2024-10-21T13:30:21.366Z", - "app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx": "2025-03-18T15:07:22.640Z", - "app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2025-03-24T06:54:21.249Z", + "app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2025-07-18T12:24:02.385Z", "app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-03-11T13:29:54.752Z", "app/learn/fundamentals/module-links/directions/page.mdx": "2025-03-17T12:52:06.161Z", "app/learn/fundamentals/module-links/page.mdx": "2025-04-17T08:50:17.036Z", diff --git a/www/apps/book/generated/sidebar.mjs b/www/apps/book/generated/sidebar.mjs index 753fc9c7ee..d269a628d7 100644 --- a/www/apps/book/generated/sidebar.mjs +++ b/www/apps/book/generated/sidebar.mjs @@ -1117,18 +1117,7 @@ export const generatedSidebars = [ "type": "link", "path": "/learn/debugging-and-testing/testing-tools/modules-tests", "title": "Modules Tests", - "children": [ - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/learn/debugging-and-testing/testing-tools/modules-tests/module-example", - "title": "Example", - "children": [], - "chapterTitle": "7.3.1. Example", - "number": "7.3.1." - } - ], + "children": [], "chapterTitle": "7.3. Modules Tests", "number": "7.3." }, diff --git a/www/apps/book/public/llms-full.txt b/www/apps/book/public/llms-full.txt index f3a40cba75..e46e202c00 100644 --- a/www/apps/book/public/llms-full.txt +++ b/www/apps/book/public/llms-full.txt @@ -4413,76 +4413,6 @@ The `errors` property contains an array of errors thrown during the execution of If you threw a `MedusaError`, then you can check the error message in `errors[0].error.message`. -# Example: Integration Tests for a Module - -In this chapter, find an example of writing an integration test for a module using [moduleIntegrationTestRunner](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/modules-tests/index.html.md) from Medusa's Testing Framework. - -### Prerequisites - -- [Testing Tools Setup](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/index.html.md) - -## Write Integration Test for Module - -Consider a `blog` module with a `BlogModuleService` that has a `getMessage` method: - -```ts title="src/modules/blog/service.ts" -import { MedusaService } from "@medusajs/framework/utils" -import MyCustom from "./models/my-custom" - -class BlogModuleService extends MedusaService({ - MyCustom, -}){ - getMessage(): string { - return "Hello, World!" - } -} - -export default BlogModuleService -``` - -To create an integration test for the method, create the file `src/modules/blog/__tests__/service.spec.ts` with the following content: - -```ts title="src/modules/blog/__tests__/service.spec.ts" -import { moduleIntegrationTestRunner } from "@medusajs/test-utils" -import { BLOG_MODULE } from ".." -import BlogModuleService from "../service" -import MyCustom from "../models/my-custom" - -moduleIntegrationTestRunner({ - moduleName: BLOG_MODULE, - moduleModels: [MyCustom], - resolve: "./src/modules/blog", - testSuite: ({ service }) => { - describe("BlogModuleService", () => { - it("says hello world", () => { - const message = service.getMessage() - - expect(message).toEqual("Hello, World!") - }) - }) - }, -}) - -jest.setTimeout(60 * 1000) -``` - -You use the `moduleIntegrationTestRunner` function to add tests for the `blog` module. You have one test that passes if the `getMessage` method returns the `"Hello, World!"` string. - -*** - -## Run Test - -Run the following command to run your module integration tests: - -```bash npm2yarn -npm run test:integration:modules -``` - -If you don't have a `test:integration:modules` script in `package.json`, refer to the [Medusa Testing Tools chapter](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools#add-test-commands/index.html.md). - -This runs your Medusa application and runs the tests available in any `__tests__` directory under the `src/modules` directory. - - # Write Tests for Modules In this chapter, you'll learn about `moduleIntegrationTestRunner` from Medusa's Testing Framework and how to use it to write integration tests for a module's main service. @@ -4495,7 +4425,24 @@ In this chapter, you'll learn about `moduleIntegrationTestRunner` from Medusa's `moduleIntegrationTestRunner` creates integration tests for a module. The integration tests run on a test Medusa application with only the specified module enabled. -For example, assuming you have a `blog` module, create a test file at `src/modules/blog/__tests__/service.spec.ts`: +For example, consider a Blog Module with a `BlogModuleService` that has a `getMessage` method: + +```ts title="src/modules/blog/service.ts" +import { MedusaService } from "@medusajs/framework/utils" +import MyCustom from "./models/my-custom" + +class BlogModuleService extends MedusaService({ + MyCustom, +}){ + async getMessage(): Promise { + return "Hello, World!" + } +} + +export default BlogModuleService +``` + +To create an integration test for the module's service, create the file `src/modules/blog/__tests__/service.spec.ts` with the following content: ```ts title="src/modules/blog/__tests__/service.spec.ts" import { moduleIntegrationTestRunner } from "@medusajs/test-utils" @@ -4562,6 +4509,8 @@ moduleIntegrationTestRunner({ }) ``` +`moduleOptions` is an object of key-value pair options that your module's service receives in its constructor. + *** ## Write Tests for Modules without Data Models @@ -4589,6 +4538,54 @@ jest.setTimeout(60 * 1000) *** +## Inject Dependencies in Module Tests + +Some modules have injected dependencies, such as the [Event Module's service](https://docs.medusajs.com/resources/infrastructure-modules/event/index.html.md). + +When writing tests for these modules, you need to inject the dependencies that the module's service requires to avoid errors. You can inject them as mock dependencies. + +For example, if your module's service depends on the Event Module or a module that connects to a third-party service, you can inject a mock service that simulates the behavior of the original service. + +To inject dependencies, pass the `injectedDependencies` property to the `moduleIntegrationTestRunner` function. + +For example: + +```ts title="src/modules/blog/__tests__/service.spec.ts" highlights={mockDependenciesHighlights} +import { MockEventBusService, moduleIntegrationTestRunner } from "@medusajs/test-utils" +import { BLOG_MODULE } from ".." +import BlogModuleService from "../service" +import MyCustom from "../models/my-custom" +import { Modules } from "@medusajs/framework/utils" + +moduleIntegrationTestRunner({ + moduleName: BLOG_MODULE, + moduleModels: [MyCustom], + resolve: "./src/modules/blog", + injectedDependencies: { + [Modules.EVENT_BUS]: new MockEventBusService() + }, + testSuite: ({ service }) => { + describe("BlogModuleService", () => { + it("says hello world", async () => { + const message = await service.getMessage() + + expect(message).toEqual("Hello, World!") + }) + }) + }, +}) + +jest.setTimeout(60 * 1000) +``` + +`injectedDependencies`'s value is an object whose keys are registration names of the dependencies you want to inject, and the values are the mock services. + +In this example, you inject a mock Event Module service into the `BlogModuleService`. Medusa exposes a `MockEventBusService` class that you can use to mock the Event Module service. + +For custom services, you can create a mock service that implements the same interface as the original service. Make sure to use the same registration name as the original service when injecting it. + +*** + ### Other Options and Inputs Refer to [the Test Tooling Reference](https://docs.medusajs.com/resources/test-tools-reference/moduleIntegrationTestRunner/index.html.md) for other available parameter options and inputs of the `testSuite` function. @@ -4678,7 +4675,7 @@ Finally, add the following scripts to `package.json`: "scripts": { // ... "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 --runInBand --forceExit", + "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit", "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit" }, ``` diff --git a/www/apps/book/sidebar.mjs b/www/apps/book/sidebar.mjs index d021d47117..7f2a4c438b 100644 --- a/www/apps/book/sidebar.mjs +++ b/www/apps/book/sidebar.mjs @@ -586,13 +586,6 @@ export const sidebars = [ type: "link", path: "/learn/debugging-and-testing/testing-tools/modules-tests", title: "Modules Tests", - children: [ - { - type: "link", - path: "/learn/debugging-and-testing/testing-tools/modules-tests/module-example", - title: "Example", - }, - ], }, { type: "link", diff --git a/www/apps/book/utils/redirects.mjs b/www/apps/book/utils/redirects.mjs index 814a45b68f..f4c6368396 100644 --- a/www/apps/book/utils/redirects.mjs +++ b/www/apps/book/utils/redirects.mjs @@ -474,6 +474,12 @@ const redirects = async () => { destination: "/resources/js-client/:path*", permanent: true, }, + { + source: + "/learn/debugging-and-testing/testing-tools/modules-tests/module-example", + destination: "/learn/debugging-and-testing/testing-tools/modules-tests", + permanent: true, + }, ] }