docs: add routing page (#9550)

- Add a new homepage to `book` project for the routing page
- Move all main doc pages to be under `/v2/learn` (and added redirects + fixed links across docs)
- Other: add admin components to resources dropdown + fixes to search on mobile.

Closes DX-955

Preview: https://docs-v2-git-docs-router-page-medusajs.vercel.app/v2
This commit is contained in:
Shahed Nasser
2024-10-18 08:24:34 +00:00
committed by GitHub
parent 7a47f5211d
commit 0a37675f0e
223 changed files with 2549 additions and 696 deletions
@@ -0,0 +1,156 @@
import { Prerequisites, TypeList } from "docs-ui"
export const metadata = {
title: `${pageNumber} Configure Instrumentation`,
}
# {metadata.title}
In this chapter, you'll learn about observability in Medusa and how to configure instrumentation with OpenTelemetry.
## Observability with OpenTelemtry
Medusa uses [OpenTelemetry](https://opentelemetry.io/) for instrumentation and reporting. When configured, it reports traces for:
- HTTP requests
- Workflow executions
- Query usages
- Database queries and operations
---
## How to Configure Instrumentation in Medusa?
<Prerequisites
items={[
{
text: "An exporter to visualize your application's traces, such as Zipkin.",
link: "https://zipkin.io/pages/quickstart.html"
}
]}
/>
### Install Dependencies
Start by installing the following OpenTelemetry dependencies in your Medusa project:
```bash npm2yarn
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/sdk-trace-node @opentelemetry/instrumentation-pg
```
Also, install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:
```bash npm2yarn
npm install @opentelemetry/exporter-zipkin
```
### Add instrumentation.ts
Next, create the file `instrumentation.ts` with the following content:
```ts title="instrumentation.ts"
import { registerOtel } from "@medusajs/medusa"
import { ZipkinExporter } from "@opentelemetry/exporter-zipkin"
// If using an exporter other than Zipkin, initialize it here.
const exporter = new ZipkinExporter({
serviceName: "my-medusa-project",
})
export function register() {
registerOtel({
serviceName: "medusajs",
// pass exporter
exporter,
instrument: {
http: true,
workflows: true,
query: true,
},
})
}
```
In the `instrumentation.ts` file, you export a `register` function that uses Medusa's `registerOtel` utility function.
You also initialize an instance of the exporter, such as Zipkin, and pass it to the `registerOtel` function.
The `registerOtel` utility function accepts an object having the following properties:
<TypeList
types={[
{
name: "serviceName",
type: "`string`",
description: "The name of the service traced.",
optional: false
},
{
name: "exporter",
type: "[SpanExporter](https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_sdk_trace_base.SpanExporter.html)",
description: "An instance of an exporter, such as Zipkin."
},
{
name: "instrument",
type: "`object`",
description: "Options specifying what to trace.",
optional: true,
children: [
{
name: "http",
type: "`boolean`",
description: "Whether to trace HTTP requests."
},
{
name: "query",
type: "`boolean`",
description: "Whether to trace Query usages."
},
{
name: "workflows",
type: "`boolean`",
description: "Whether to trace Workflow executions."
},
{
name: "db",
type: "`boolean`",
description: "Whether to trace database queries and operations."
}
]
},
{
name: "instrumentations",
type: "[Instrumentation[]](https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_instrumentation.Instrumentation.html)",
description: "Additional instrumentation options that OpenTelemetry accepts.",
optional: true
}
]}
/>
---
## Test it Out
To test it out, start your exporter, such as Zipkin.
Then, start your Medusa application:
```bash npm2yarn
npm run dev
```
Try to open the Medusa Admin or send a request to an API route.
If you check traces in your exporter, you'll find new traces reported.
### Trace Span Names
Trace span names start with the following keywords based on what it's reporting:
- `{methodName} {URL}` when reporting HTTP requests, where `{methodName}` is the HTTP method, and `{URL}` is the URL the request is sent to.
- `route:` when reporting route handlers running on an HTTP requests.
- `middleware:` when reporting a middleware running on an HTTP request.
- `workflow:` when reporting a workflow execution.
- `step:` when reporting a step in a workflow execution.
- `query.graph:` when reporting Query usages.
- `pg.query:` when reporting database queries and operations.
@@ -0,0 +1,159 @@
export const metadata = {
title: `${pageNumber} Logging`,
}
# {metadata.title}
In this chapter, youll learn how to use Medusas logging utility.
## Logger Class
Medusa provides a `Logger` class with advanced logging functionalities. This includes configuring logging levels or saving logs to a file.
The Medusa application registers the `Logger` class in the Medusa container and each module's container as `logger`.
---
## How to Log a Message
Resolve the `logger` using the Medusa container to log a message in your resource.
For example, create the file `src/jobs/log-message.ts` with the following content:
export const highlights = [
["7", "resolve", "Resolve the `Logger` class."],
["9", "info", "Log a message of level `info`."]
]
```ts title="src/jobs/log-message.ts" highlights={highlights}
import { MedusaContainer } from "@medusajs/framework/types"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
export default async function myCustomJob(
container: MedusaContainer
) {
const logger = container.resolve(ContainerRegistrationKeys.LOGGER)
logger.info("I'm using the logger!")
}
export const config = {
name: "test-logger",
// execute every minute
schedule: "* * * * *",
}
```
This creates a scheduled job that resolves the `logger` from the Medusa container and uses it to log a message.
### Test the Scheduled Job
To test out the above scheduled job, start the Medusa application:
```bash npm2yarn
npm run dev
```
After a minute, you'll see the following message as part of the logged messages:
```text
info: I'm using the logger!
```
---
## Log Levels
The `Logger` class has the following methods:
- `info`: The message is logged with level `info`.
- `warn`: The message is logged with level `warn`.
- `error`: The message is logged with level `error`.
- `debug`: The message is logged with level `debug`.
Each of these methods accepts a string parameter to log in the terminal with the associated level.
---
## Logging Configurations
### Log Level
The available log levels, from lowest to highest levels, are:
1. `silly` (default, meaning messages of all levels are logged)
2. `debug`
3. `info`
4. `warn`
5. `error`
You can change that by setting the `LOG_LEVEL` environment variable to the minimum level you want to be logged.
For example:
```bash
LOG_LEVEL=error
```
This logs `error` messages only.
<Note title="Important">
The environment variable must be set as a system environment variable and not in `.env`.
</Note>
### Save Logs in a File
Aside from showing the logs in the terminal, you can save the logs in a file by setting the `LOG_FILE` environment variable to the path of the file relative to the Medusa servers root directory.
For example:
```bash
LOG_FILE=all.log
```
Your logs are now saved in the `all.log` file at the root of your Medusa application.
<Note title="Important">
The environment variable must be set as a system environment variable and not in `.env`.
</Note>
---
## Show Log with Progress
The `Logger` class has an `activity` method used to log a message of level `info`. If the Medusa application is running in a development environment, a spinner starts to show the activity's progress.
For example:
```ts title="src/jobs/log-message.ts"
import { MedusaContainer } from "@medusajs/framework/types"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
export default async function myCustomJob(
container: MedusaContainer
) {
const logger = container.resolve(ContainerRegistrationKeys.LOGGER)
const activityId = logger.activity("First log message")
logger.progress(activityId, `Second log message`)
logger.success(activityId, "Last log message")
}
```
The `activity` method returns the ID of the started activity. This ID can then be passed to one of the following methods of the `Logger` class:
- `progress`: Log a message of level `info` that indicates progress within that same activity.
- `success`: Log a message of level `info` that indicates that the activity has succeeded. This also ends the associated activity.
- `failure`: Log a message of level `error` that indicates that the activity has failed. This also ends the associated activity.
<Note>
If you configured the `LOG_LEVEL` environment variable to a level higher than those associated with the above methods, their messages wont be logged.
</Note>
@@ -0,0 +1,12 @@
export const metadata = {
title: `${pageNumber} Debugging and Testing`,
}
# {metadata.title}
In the next chapters, youll learn about the tools Medusa provides for testing and debugging your Medusa application.
By the end of this chapter, youll learn:
- How to use Medusa's `medusa-test-utils` test to write integration tests.
- How to use Medusas `Logger` utility to log messages.
@@ -0,0 +1,295 @@
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `${pageNumber} Example: Write Integration Tests for API Routes`,
}
# {metadata.title}
In this chapter, you'll learn how to write integration tests for API routes using the [medusaIntegrationTestRunner utility function](../page.mdx).
<Prerequisites
items={[
{
text: "Testing Tools Setup",
link: "/debugging-and-testing/testing-tools"
}
]}
/>
## Test a GET API Route
Consider the following API route created at `src/api/custom/route.ts`:
```ts title="src/api/custom/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
){
res.json({
message: "Hello, World!",
})
}
```
To write an integration test that tests this API route, create the file `integration-tests/http/custom-routes.spec.ts` with the following content:
export const getHighlights = [
["8", "api.get", "Send a GET request to the `/custom` API route."]
]
```ts title="integration-tests/http/custom-routes.spec.ts" highlights={getHighlights}
import { medusaIntegrationTestRunner } from "medusa-test-utils"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
describe("GET /custom", () => {
it("returns correct message", async () => {
const response = await api.get(
`/custom`
)
expect(response.status).toEqual(200)
expect(response.data).toHaveProperty("message")
expect(response.data.message).toEqual("Hello, World!")
})
})
})
},
})
```
You use the `medusaIntegrationTestRunner` to write your tests.
You add a single test that sends a `GET` request to `/custom` using the `api.get` method. For the test to pass, the response is expected to:
- Have a code status `200`,
- Have a `message` property in the returned data.
- Have the value of the `message` property equal to `Hello, World!`.
### Run Tests
Run the following command to run your tests:
```bash npm2yarn
npm run test:integration
```
<Note title="Tip">
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands).
</Note>
This runs your Medusa application and runs the tests available under the `src/integrations/http` directory.
---
## Test a POST API Route
Suppose you have a `hello` module whose main service extends the service factory, and that has the following model:
```ts title="src/modules/hello/models/my-custom.ts"
import { model } from "@medusajs/framework/utils"
const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(),
name: model.text(),
})
export default MyCustom
```
And consider that the file `src/api/custom/route.ts` defines another route handler for `POST` requests:
```ts title="src/api/custom/route.ts"
// other imports...
import HelloModuleService from "../../../modules/hello/service"
// ...
export async function POST(
req: MedusaRequest,
res: MedusaResponse
) {
const helloModuleService: HelloModuleService = req.scope.resolve(
"helloModuleService"
)
const myCustom = await helloModuleService.createMyCustoms(
req.body
)
res.json({
my_custom: myCustom,
})
}
```
This API route creates a new record of `MyCustom`.
To write tests for this API route, add the following at the end of the `testSuite` function in `integration-tests/http/custom-routes.spec.ts`:
export const postHighlights = [
["14", "api.post", "Send a POST request to the `/custom` API route."]
]
```ts title="integration-tests/http/custom-routes.spec.ts" highlights={postHighlights}
// other imports...
import HelloModuleService from "../../src/modules/hello/service"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
// other tests...
describe("POST /custom", () => {
const id = "1"
it("Creates my custom", async () => {
const response = await api.post(
`/custom`,
{
id,
name: "Test",
}
)
expect(response.status).toEqual(200)
expect(response.data).toHaveProperty("my_custom")
expect(response.data.my_custom).toEqual({
id,
name: "Test",
created_at: expect.any(String),
updated_at: expect.any(String),
})
})
})
})
},
})
```
This adds a test for the `POST /custom` API route. It uses `api.post` to send the POST request. The `api.post` method accepts as a second parameter the data to pass in the request body.
The test passes if the response has:
- Status code `200`.
- A `my_custom` property in its data.
- Its `id` and `name` match the ones provided to the request.
### Tear Down Created Record
To ensure consistency in the database for the rest of the tests after the above test is executed, utilize [Jest's setup and teardown hooks](https://jestjs.io/docs/setup-teardown) to delete the created record.
Use the `getContainer` function passed as a parameter to the `testSuite` function to resolve a service and use it for setup or teardown purposes
So, add an `afterAll` hook in the `describe` block for `POST /custom`:
```ts title="integration-tests/http/custom-routes.spec.ts"
// other imports...
import HelloModuleService from "../../src/modules/hello/service"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
// other tests...
describe("POST /custom", () => {
// ...
afterAll(() => async () => {
const helloModuleService: HelloModuleService = getContainer().resolve(
"helloModuleService"
)
await helloModuleService.deleteMyCustoms(id)
})
})
})
},
})
```
The `afterAll` hook resolves the `HelloModuleService` and use its `deleteMyCustoms` to delete the record created by the test.
---
## Test a DELETE API Route
Consider a `/custom/:id` API route created at `src/api/custom/[id]/route.ts`:
```ts title="src/api/custom/[id]/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import HelloModuleService from "../../../modules/hello/service"
export async function DELETE(
req: MedusaRequest,
res: MedusaResponse
) {
const helloModuleService: HelloModuleService = req.scope.resolve(
"helloModuleService"
)
await helloModuleService.deleteMyCustoms(req.params.id)
res.json({
success: true,
})
}
```
This API route accepts an ID path parameter, and uses the `HelloModuleService` to delete a `MyCustom` record by that ID.
To add tests for this API route, add the following to `integration-tests/http/custom-routes.spec.ts`:
export const deleteHighlights = [
["21", "api.delete", "Send a DELETE request to the `/custom/:id` API route."]
]
```ts title="integration-tests/http/custom-routes.spec.ts" highlights={deleteHighlights}
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
// ...
describe("DELETE /custom/:id", () => {
const id = "1"
beforeAll(() => async () => {
const helloModuleService: HelloModuleService = getContainer().resolve(
"helloModuleService"
)
await helloModuleService.createMyCustoms({
id,
name: "Test",
})
})
it("Deletes my custom", async () => {
const response = await api.delete(
`/custom/${id}`
)
expect(response.status).toEqual(200)
expect(response.data).toHaveProperty("success")
expect(response.data.success).toBeTruthy()
})
})
})
},
})
```
This adds a new test for the `DELETE /custom/:id` API route. You use the `beforeAll` hook to create a `MyCustom` record using the `HelloModuleService`.
In the test, you use the `api.delete` method to send a `DELETE` request to `/custom/:id`. The test passes if the response:
- Has a `200` status code.
- Has a `success` property in its data.
- The `success` property's value is true.
@@ -0,0 +1,89 @@
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `${pageNumber} Write Integration Tests`,
}
# {metadata.title}
In this chapter, you'll learn about the `medusaIntegrationTestRunner` utility function used to write integration tests.
<Prerequisites
items={[
{
text: "Testing Tools Setup",
link: "/debugging-and-testing/testing-tools"
}
]}
/>
## medusaIntegrationTestRunner Utility
The `medusaIntegrationTestRunner` utility function is provided by the `medusa-test-utils` package to create integration tests in your Medusa project. It runs a full Medusa application, allowing you test API routes, workflows, or other customizations.
For example:
export const highlights = [
["4", "api", "A set of utility methods used to send requests to the Medusa application."],
["4", "getContainer", "A function to retrieve the Medusa container."]
]
```ts title="integration-tests/http/test.spec.ts" highlights={highlights}
import { medusaIntegrationTestRunner } from "medusa-test-utils"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
// TODO write tests...
},
})
```
The `medusaIntegrationTestRunner` function accepts an object as a parameter. The object has a required property `testSuite`.
`testSuite`'s value is a function that defines the tests to run. The function accepts as a parameter an object that has the following properties:
- `api`: a set of utility methods used to send requests to the Medusa application. It has the following methods:
- `get`: Send a `GET` request to an API route.
- `post`: Send a `POST` request to an API route.
- `delete`: Send a `DELETE` request to an API route.
- `getContainer`: a function that retrieves the Medusa Container. Use the `getContainer().resolve` method to resolve resources from the Medusa Container.
The tests in the `testSuite` function are written using [Jest](https://jestjs.io/).
---
### Run Tests
Run the following command to run your tests:
```bash npm2yarn
npm run test:integration
```
<Note title="Tip">
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](../page.mdx#add-test-commands).
</Note>
This runs your Medusa application and runs the tests available under the `src/integrations/http` directory.
---
## Other Options and Inputs
Refer to [this reference in the Development Resources documentation](!resources!/test-tools-reference/medusaIntegrationTestRunner) for other available parameter options and inputs of the `testSuite` function.
---
## Database Used in Tests
The `medusaIntegrationTestRunner` function creates a database with a random name before running the tests. Then, it drops that database after all the tests end.
To manage that database, such as changing its name or perform operations on it in your tests, refer to the [references in the Development Resources documentation](!resources!/test-tools-reference/medusaIntegrationTestRunner).
---
## Example Integration Tests
The next chapters provide examples of writing integration tests for API routes and workflows.
@@ -0,0 +1,84 @@
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `${pageNumber} Example: Write Integration Tests for Workflows`,
}
# {metadata.title}
In this chapter, you'll learn how to write integration tests for workflows using the [medusaIntegrationTestRunner utility function](../page.mdx).
<Prerequisites
items={[
{
text: "Testing Tools Setup",
link: "/debugging-and-testing/testing-tools"
}
]}
/>
## Write Integration Test for Workflow
Consider you have the following workflow defined at `src/workflows/hello-world.ts`:
```ts title="src/workflows/hello-world.ts"
import {
createWorkflow,
createStep,
StepResponse,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
const step1 = createStep("step-1", () => {
return new StepResponse("Hello, World!")
})
export const helloWorldWorkflow = createWorkflow(
"hello-world-workflow",
() => {
const message = step1()
return new WorkflowResponse(message)
}
)
```
To write a test for this workflow, create the file `integration-tests/http/workflow.spec.ts` with the following content:
```ts title="integration-tests/http/workflow.spec.ts"
import { medusaIntegrationTestRunner } from "medusa-test-utils"
import { helloWorldWorkflow } from "../../src/workflows/hello-world"
medusaIntegrationTestRunner({
testSuite: ({ getContainer }) => {
describe("Test hello-world workflow", () => {
it("returns message", async () => {
const { result } = await helloWorldWorkflow(getContainer())
.run()
expect(result).toEqual("Hello, World!")
})
})
},
})
```
You use the `medusaIntegrationTestRunner` to write an integration test for the workflow. The test pases if the workflow returns the string `"Hello, World!"`.
---
## Run Test
Run the following command to run your tests:
```bash npm2yarn
npm run test:integration
```
<Note title="Tip">
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands).
</Note>
This runs your Medusa application and runs the tests available under the `integrations/http` directory.
@@ -0,0 +1,81 @@
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 the [moduleIntegrationTestRunner utility function](../page.mdx).
<Prerequisites
items={[
{
text: "Testing Tools Setup",
link: "/debugging-and-testing/testing-tools"
}
]}
/>
## Write Integration Test for Module
Consider a `hello` module with a `HelloModuleService` that has a `getMessage` method:
```ts title="src/modules/hello/service.ts"
import { MedusaService } from "@medusajs/framework/utils"
import MyCustom from "./models/my-custom"
class HelloModuleService extends MedusaService({
MyCustom,
}){
getMessage(): string {
return "Hello, World!"
}
}
export default HelloModuleService
```
To create an integration test for the method, create the file `src/modules/hello/__tests__/service.spec.ts` with the following content:
```ts title="src/modules/hello/__tests__/service.spec.ts"
import { moduleIntegrationTestRunner } from "medusa-test-utils"
import { HELLO_MODULE } from ".."
import HelloModuleService from "../service"
import MyCustom from "../models/my-custom"
moduleIntegrationTestRunner<HelloModuleService>({
moduleName: HELLO_MODULE,
moduleModels: [MyCustom],
resolve: "./src/modules/hello",
testSuite: ({ service }) => {
describe("HelloModuleService", () => {
it("says hello world", () => {
const message = service.getMessage()
expect(message).toEqual("Hello, World!")
})
})
},
})
```
You use the `moduleIntegrationTestRunner` function to add tests for the `hello` 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:modules
```
<Note title="Tip">
If you don't have a `test:modules` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands).
</Note>
This runs your Medusa application and runs the tests available in any `__tests__` directory under the `src/modules` directory.
@@ -0,0 +1,132 @@
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `${pageNumber} Write Tests for Modules`,
}
# {metadata.title}
In this chapter, you'll learn about the `moduleIntegrationTestRunner` utility function and how to use it to write integration tests for a module's main service.
<Prerequisites
items={[
{
text: "Testing Tools Setup",
link: "/debugging-and-testing/testing-tools"
}
]}
/>
## moduleIntegrationTestRunner Utility
The `moduleIntegrationTestRunner` utility function is provided by the `medusa-test-utils` package to create 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 `hello` module, create a test file at `src/modules/hello/__tests__/service.spec.ts`:
```ts title="src/modules/hello/__tests__/service.spec.ts"
import { moduleIntegrationTestRunner } from "medusa-test-utils"
import { HELLO_MODULE } from ".."
import HelloModuleService from "../service"
import MyCustom from "../models/my-custom"
moduleIntegrationTestRunner<HelloModuleService>({
moduleName: HELLO_MODULE,
moduleModels: [MyCustom],
resolve: "./src/modules/hello",
testSuite: ({ service }) => {
// TODO write tests
},
})
```
The `moduleIntegrationTestRunner` function accepts as a parameter an object with the following properties:
- `moduleName`: The 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 model.
- `testSuite`: A function that defines the 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.
<Note title="Tip">
The type argument provided to the `moduleIntegrationTestRunner` function is used as the type of the `service` property.
</Note>
The tests in the `testSuite` function are written using [Jest](https://jestjs.io/).
---
## Run Tests
Run the following command to run your module integration tests:
```bash npm2yarn
npm run test:modules
```
<Note title="Tip">
If you don't have a `test:modules` script in `package.json`, refer to the [Medusa Testing Tools chapter](../page.mdx#add-test-commands).
</Note>
This runs your Medusa application and runs the tests available in any `__tests__` directory under the `src/modules` directory.
---
## Pass Module Options
If your module accepts options, you can set them using the `moduleOptions` property of the `moduleIntegrationTestRunner`'s parameter.
For example:
```ts
import { moduleIntegrationTestRunner } from "medusa-test-utils"
import HelloModuleService from "../service"
moduleIntegrationTestRunner<HelloModuleService>({
moduleOptions: {
apiKey: "123",
},
// ...
})
```
---
## Write Tests for Modules without Data Models
If your module doesn't have a data model, pass a dummy model in the `moduleModels` property.
For example:
```ts
import { moduleIntegrationTestRunner } from "medusa-test-utils"
import HelloModuleService from "../service"
import { model } from "@medusajs/framework/utils"
const DummyModel = model.define("dummy_model", {
id: model.id().primaryKey(),
})
moduleIntegrationTestRunner<HelloModuleService>({
moduleModels: [DummyModel],
// ...
})
```
---
### Other Options and Inputs
Refer to [this reference in the Development Resources documentation](!resources!/test-tools-reference/moduleIntegrationTestRunner) for other available parameter options and inputs of the `testSuite` function.
---
## Database Used in Tests
The `moduleIntegrationTestRunner` function creates a database with a random name before running the tests. Then, it drops that database after all the tests end.
To manage that database, such as changing its name or perform operations on it in your tests, refer to the [references in the Development Resources documentation](!resources!/test-tools-reference/moduleIntegrationTestRunner).
@@ -0,0 +1,103 @@
export const metadata = {
title: `${pageNumber} Medusa Testing Tools`,
}
# {metadata.title}
In this chapter, you'll learn about Medusa's testing tools and how to install and configure them.
## medusa-test-utils Package
Medusa provides a `medusa-test-utils` package with utility tools to create integration tests for your custom API routes, modules, or other Medusa customizations.
### Install medusa-test-utils
To use the `medusa-test-utils` package, install it as a `devDependency`:
```bash npm2yarn
npm install --save-dev medusa-test-utils@rc
```
---
## Install and Configure Jest
Writing tests with `medusa-test-utils`'s tools requires installing and configuring Jest in your project.
{/* TODO remove this note at some point in the future */}
<Note>
If your Medusa project was created after September 3rd, Jest is already installed and configured.
</Note>
Run the following command to install the required Jest dependencies:
```bash npm2yarn
npm install --save-dev jest @types/jest @swc/jest
```
Then, create the file `jest.config.js` with the following content:
```js title="jest.config.js"
const { loadEnv } = require("@medusajs/framework/utils")
loadEnv("test", process.cwd())
module.exports = {
transform: {
"^.+\\.[jt]s$": [
"@swc/jest",
{
jsc: {
parser: { syntax: "typescript", decorators: true },
},
},
],
},
testEnvironment: "node",
moduleFileExtensions: ["js", "ts", "json"],
modulePathIgnorePatterns: ["dist/"],
}
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"]
}
```
---
## Add Test Commands
Finally, add the following scripts to `package.json`:
```json title="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:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
},
```
You now have two commands:
- `test:integration:http` to run integration tests (for example, for API routes and workflows) available under the `integration-tests/http` directory.
- `test:integration:modules` to run integration tests for modules available in any `__tests__` directory under `src/modules`.
- `test:unit` to run unit tests in any `__tests__` directory under the `src` directory.
<Note>
Medusa provides utility tools for integration tests only. You can write unit tests using Jest.
</Note>
---
## Test Tools and Writing Tests
The next chapters explain how to use the testing tools provided by `medusa-test-utils` to write tests.