docs: fixes and improvements to testing docs (#11244)
* docs: fixes and improvements to testing docs * generate files
This commit is contained in:
+63
@@ -304,3 +304,66 @@ In the test, you use the `api.delete` method to send a `DELETE` request to `/cus
|
||||
- Has a `success` property in its data.
|
||||
- The `success` property's value is true.
|
||||
|
||||
---
|
||||
|
||||
## Pass Headers in Test Requests
|
||||
|
||||
Some requests require passing headers. For example, all routes prefixed with `/store` must pass a publishable API key in the header.
|
||||
|
||||
The `get`, `post`, and `delete` methods accept an optional third parameter that you can pass a `headers` property to, whose value is an object of headers to pass in the request.
|
||||
|
||||
For example, to pass a publishable API key in the header for a request to a `/store` route:
|
||||
|
||||
export const headersHighlights = [
|
||||
["10", "pak", "Create a publishable API key before the tests run."],
|
||||
["27", "headers", "Pass the publishable API key in the request's header."]
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/custom-routes.spec.ts" highlights={headersHighlights}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { ApiKeyDTO } from "@medusajs/framework/types"
|
||||
import { createApiKeysWorkflow } from "@medusajs/medusa/core-flows"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ api, getContainer }) => {
|
||||
describe("Custom endpoints", () => {
|
||||
let pak: ApiKeyDTO
|
||||
beforeAll(async () => {
|
||||
pak = (await createApiKeysWorkflow(getContainer()).run({
|
||||
input: {
|
||||
api_keys: [
|
||||
{
|
||||
type: "publishable",
|
||||
title: "Test Key",
|
||||
created_by: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
})).result[0]
|
||||
})
|
||||
describe("GET /custom", () => {
|
||||
it("returns correct message", async () => {
|
||||
const response = await api.get(
|
||||
`/store/custom`,
|
||||
{
|
||||
headers: {
|
||||
"x-publishable-api-key": pak.token
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toHaveProperty("message")
|
||||
expect(response.data.message).toEqual("Hello, World!")
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
In your test suit, you add a `beforeAll` hook to create a publishable API key before the tests run. To create the API key, you can use the `createApiKeysWorkflow` or the [API Key Module's service](!resources!/commerce-modules/api-key).
|
||||
|
||||
Then, in the test, you pass an object as the last parameter to `api.get` with a `headers` property. The `headers` property is an object with the key `x-publishable-api-key` and the value of the API key's token.
|
||||
|
||||
+49
@@ -93,3 +93,52 @@ If you don't have a `test:integration` script in `package.json`, refer to the [M
|
||||
</Note>
|
||||
|
||||
This runs your Medusa application and runs the tests available under the `integrations/http` directory.
|
||||
|
||||
---
|
||||
|
||||
## Test That a Workflow Throws an Error
|
||||
|
||||
You might want to test that a workflow throws an error in certain cases. To test this:
|
||||
|
||||
- Disable the `throwOnError` option when executing the workflow.
|
||||
- Use the returned `errors` property to check what errors were thrown.
|
||||
|
||||
For example, if you have a step that throws this error:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts"
|
||||
import { MedusaError } from "@medusajs/framework/utils"
|
||||
import { createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep("step-1", () => {
|
||||
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Item doesn't exist")
|
||||
})
|
||||
```
|
||||
|
||||
You can write the following test to ensure that the workflow throws that error:
|
||||
|
||||
```ts title="integration-tests/http/workflow.spec.ts"
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { helloWorldWorkflow } from "../../src/workflows/hello-world"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test hello-world workflow", () => {
|
||||
it("returns message", async () => {
|
||||
const { errors } = await helloWorldWorkflow(getContainer())
|
||||
.run({
|
||||
throwOnError: false
|
||||
})
|
||||
|
||||
expect(errors.length).toBeGreaterThan(0)
|
||||
expect(errors[0].error.message).toBe("Item doesn't exist")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
The `errors` property contains an array of errors thrown during the execution of the workflow. Each error item has an `error` object, being the error thrown.
|
||||
|
||||
If you threw a `MedusaError`, then you can check the error message in `errors[0].error.message`.
|
||||
+4
-2
@@ -58,6 +58,8 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -69,12 +71,12 @@ You use the `moduleIntegrationTestRunner` function to add tests for the `hello`
|
||||
Run the following command to run your module integration tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:modules
|
||||
npm run test:integration: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).
|
||||
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).
|
||||
|
||||
</Note>
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
// TODO write tests
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
The `moduleIntegrationTestRunner` function accepts as a parameter an object with the following properties:
|
||||
@@ -63,12 +65,12 @@ The tests in the `testSuite` function are written using [Jest](https://jestjs.io
|
||||
Run the following command to run your module integration tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:modules
|
||||
npm run test:integration: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).
|
||||
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).
|
||||
|
||||
</Note>
|
||||
|
||||
@@ -115,6 +117,8 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
moduleModels: [DummyModel],
|
||||
// ...
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -22,14 +22,6 @@ npm install --save-dev @medusajs/test-utils@latest
|
||||
|
||||
Writing tests with `@medusajs/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
|
||||
@@ -56,6 +48,7 @@ module.exports = {
|
||||
testEnvironment: "node",
|
||||
moduleFileExtensions: ["js", "ts", "json"],
|
||||
modulePathIgnorePatterns: ["dist/"],
|
||||
setupFiles: ["./integration-tests/setup.js"],
|
||||
}
|
||||
|
||||
if (process.env.TEST_TYPE === "integration:http") {
|
||||
@@ -67,6 +60,14 @@ if (process.env.TEST_TYPE === "integration:http") {
|
||||
}
|
||||
```
|
||||
|
||||
Next, create the `integration-tests/setup.js` file with the following content:
|
||||
|
||||
```js title="integration-tests/setup.js"
|
||||
const { MetadataStorage } = require("@mikro-orm/core")
|
||||
|
||||
MetadataStorage.clear()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Add Test Commands
|
||||
|
||||
@@ -59,10 +59,10 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/data-models/index/page.mdx": "2024-10-21T13:30:21.368Z",
|
||||
"app/learn/fundamentals/custom-cli-scripts/page.mdx": "2024-10-23T07:08:55.898Z",
|
||||
"app/learn/fundamentals/data-models/property-types/page.mdx": "2024-12-12T10:41:32.999Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-12-09T15:34:08.049Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-01-31T13:19:02.586Z",
|
||||
"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": "2024-12-09T15:51:15.422Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/page.mdx": "2024-12-09T15:53:56.878Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2025-01-31T13:19:02.586Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-01-31T13:19:02.587Z",
|
||||
"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": "2024-11-19T16:37:47.253Z",
|
||||
@@ -70,8 +70,8 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/api-routes/validation/page.mdx": "2024-12-09T13:04:02.426Z",
|
||||
"app/learn/fundamentals/api-routes/errors/page.mdx": "2024-12-09T16:44:19.781Z",
|
||||
"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": "2024-12-09T15:52:22.185Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2024-12-09T15:52:57.091Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx": "2025-01-31T13:19:02.586Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2025-01-31T13:19:02.587Z",
|
||||
"app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-01-06T11:19:13.178Z",
|
||||
"app/learn/fundamentals/module-links/directions/page.mdx": "2024-12-12T15:31:31.555Z",
|
||||
"app/learn/fundamentals/module-links/page.mdx": "2024-12-09T14:39:26.668Z",
|
||||
@@ -110,10 +110,9 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/data-models/check-constraints/page.mdx": "2024-12-06T14:34:50.384Z",
|
||||
"app/learn/fundamentals/module-links/link/page.mdx": "2025-01-06T09:27:25.604Z",
|
||||
"app/learn/conventions/ts-aliases/page.mdx": "2025-01-23T15:01:15.403Z",
|
||||
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-01-24T12:09:24.087Z",
|
||||
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-01-27T08:45:19.028Z",
|
||||
"app/learn/fundamentals/plugins/create/page.mdx": "2025-01-28T07:08:05.418Z",
|
||||
"app/learn/fundamentals/plugins/page.mdx": "2025-01-22T10:14:10.433Z",
|
||||
"app/learn/customization/reuse-customizations/page.mdx": "2025-01-22T10:01:57.665Z",
|
||||
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-01-27T08:45:19.028Z",
|
||||
"app/learn/update/page.mdx": "2025-01-27T08:45:19.030Z"
|
||||
}
|
||||
@@ -870,8 +870,26 @@ export const generatedSidebar = [
|
||||
"initialOpen": false
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "category",
|
||||
"title": "5. Debugging & Testing",
|
||||
"title": "5. Conventions",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "link",
|
||||
"title": "Type Aliases",
|
||||
"path": "/learn/conventions/ts-aliases",
|
||||
"children": [],
|
||||
"chapterTitle": "5.1. Type Aliases"
|
||||
}
|
||||
],
|
||||
"chapterTitle": "5. Conventions"
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"title": "6. Debugging & Testing",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -879,7 +897,7 @@ export const generatedSidebar = [
|
||||
"type": "link",
|
||||
"path": "/learn/debugging-and-testing",
|
||||
"title": "Debugging and Testing",
|
||||
"chapterTitle": "5. Debugging & Testing",
|
||||
"chapterTitle": "6. Debugging & Testing",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -888,7 +906,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/testing-tools",
|
||||
"title": "Testing Tools",
|
||||
"children": [],
|
||||
"chapterTitle": "5.1. Testing Tools"
|
||||
"chapterTitle": "6.1. Testing Tools"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -904,7 +922,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/testing-tools/integration-tests/api-routes",
|
||||
"title": "Example: API Routes Tests",
|
||||
"children": [],
|
||||
"chapterTitle": "5.2.1. Example: API Routes Tests"
|
||||
"chapterTitle": "6.2.1. Example: API Routes Tests"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -913,10 +931,10 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/testing-tools/integration-tests/workflows",
|
||||
"title": "Example: Workflows Tests",
|
||||
"children": [],
|
||||
"chapterTitle": "5.2.2. Example: Workflows Tests"
|
||||
"chapterTitle": "6.2.2. Example: Workflows Tests"
|
||||
}
|
||||
],
|
||||
"chapterTitle": "5.2. Integration Tests"
|
||||
"chapterTitle": "6.2. Integration Tests"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -932,10 +950,10 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/testing-tools/modules-tests/module-example",
|
||||
"title": "Example",
|
||||
"children": [],
|
||||
"chapterTitle": "5.3.1. Example"
|
||||
"chapterTitle": "6.3.1. Example"
|
||||
}
|
||||
],
|
||||
"chapterTitle": "5.3. Modules Tests"
|
||||
"chapterTitle": "6.3. Modules Tests"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -944,7 +962,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/instrumentation",
|
||||
"title": "Instrumentation",
|
||||
"children": [],
|
||||
"chapterTitle": "5.4. Instrumentation"
|
||||
"chapterTitle": "6.4. Instrumentation"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -953,7 +971,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/debugging-and-testing/logging",
|
||||
"title": "Logging",
|
||||
"children": [],
|
||||
"chapterTitle": "5.5. Logging"
|
||||
"chapterTitle": "6.5. Logging"
|
||||
}
|
||||
],
|
||||
"childrenSameLevel": true
|
||||
@@ -964,7 +982,7 @@ export const generatedSidebar = [
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"title": "6. Production",
|
||||
"title": "7. Production",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -972,7 +990,7 @@ export const generatedSidebar = [
|
||||
"type": "link",
|
||||
"path": "/learn/build",
|
||||
"title": "Build",
|
||||
"chapterTitle": "6. Production",
|
||||
"chapterTitle": "7. Production",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -981,7 +999,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/deployment",
|
||||
"title": "Deployment Overview",
|
||||
"children": [],
|
||||
"chapterTitle": "6.1. Deployment Overview"
|
||||
"chapterTitle": "7.1. Deployment Overview"
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -990,7 +1008,7 @@ export const generatedSidebar = [
|
||||
"path": "/learn/deployment/general",
|
||||
"title": "General Deployment",
|
||||
"children": [],
|
||||
"chapterTitle": "6.2. General Deployment"
|
||||
"chapterTitle": "7.2. General Deployment"
|
||||
}
|
||||
],
|
||||
"childrenSameLevel": true
|
||||
@@ -1001,7 +1019,7 @@ export const generatedSidebar = [
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"title": "7. Updates",
|
||||
"title": "8. Updates",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -1009,7 +1027,7 @@ export const generatedSidebar = [
|
||||
"type": "link",
|
||||
"path": "/learn/update",
|
||||
"title": "Updating Medusa",
|
||||
"chapterTitle": "7. Updates",
|
||||
"chapterTitle": "8. Updates",
|
||||
"children": [],
|
||||
"childrenSameLevel": true
|
||||
}
|
||||
@@ -1019,7 +1037,7 @@ export const generatedSidebar = [
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"title": "8. More Resources",
|
||||
"title": "9. More Resources",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
@@ -1029,7 +1047,7 @@ export const generatedSidebar = [
|
||||
"title": "More Resources",
|
||||
"children": [],
|
||||
"childrenSameLevel": true,
|
||||
"chapterTitle": "8. More Resources"
|
||||
"chapterTitle": "9. More Resources"
|
||||
}
|
||||
],
|
||||
"loaded": true,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
export const metadata = {
|
||||
title: `Test Errors`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
## Loaders for module Workflows failed
|
||||
|
||||
If you get the following error when running your tests:
|
||||
|
||||
```bash
|
||||
Loaders for module Workflows failed: Method Map.prototype.set called on incompatible receiver #<Map>
|
||||
```
|
||||
|
||||
This may occur if you have multiple test files and you don't configure your Jest environment correctly. To resolve this, add the following configuration to your `jest.config.js` file:
|
||||
|
||||
```js title="jest.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
setupFiles: ["./integration-tests/setup.js"],
|
||||
}
|
||||
```
|
||||
|
||||
Then, create the `integration-tests/setup.js` file with the following content:
|
||||
|
||||
```js title="integration-tests/setup.js"
|
||||
const { MetadataStorage } = require("@mikro-orm/core")
|
||||
|
||||
MetadataStorage.clear()
|
||||
```
|
||||
|
||||
Learn more about configuring test tools in [this documentation](!docs!/learn/debugging-and-testing/testing-tools)
|
||||
@@ -5901,5 +5901,6 @@ export const generatedEditDates = {
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.StoreProductTypeParams/page.mdx": "2025-01-27T11:43:54.211Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.StoreProductTypeResponse/page.mdx": "2025-01-27T11:43:54.212Z",
|
||||
"references/types/interfaces/types.BaseProductTypeListParams/page.mdx": "2025-01-27T11:43:54.550Z",
|
||||
"references/core_flows/Order/Steps_Order/variables/core_flows.Order.Steps_Order.updateOrderChangesStepId/page.mdx": "2025-01-27T11:43:49.278Z"
|
||||
"references/core_flows/Order/Steps_Order/variables/core_flows.Order.Steps_Order.updateOrderChangesStepId/page.mdx": "2025-01-27T11:43:49.278Z",
|
||||
"app/troubleshooting/test-errors/page.mdx": "2025-01-31T13:08:42.639Z"
|
||||
}
|
||||
@@ -1235,6 +1235,10 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/s3/page.mdx",
|
||||
"pathname": "/troubleshooting/s3"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/test-errors/page.mdx",
|
||||
"pathname": "/troubleshooting/test-errors"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/workflow-errors/page.mdx",
|
||||
"pathname": "/troubleshooting/workflow-errors"
|
||||
|
||||
@@ -17293,6 +17293,14 @@ export const generatedSidebar = [
|
||||
"path": "/troubleshooting/workflow-errors",
|
||||
"title": "Workflow Errors",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "link",
|
||||
"path": "/troubleshooting/test-errors",
|
||||
"title": "Test Errors",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -45,6 +45,11 @@ export const troubleshootingSidebar = [
|
||||
path: "/troubleshooting/workflow-errors",
|
||||
title: "Workflow Errors",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: "/troubleshooting/test-errors",
|
||||
title: "Test Errors",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user