docs: improved workflows integration tests guide (#13090)
This commit is contained in:
@@ -28,7 +28,7 @@ There are several ways to debug workflows in Medusa:
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
Write integration tests
|
||||
[Write integration tests](#approach-1-write-integration-tests)
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
To ensure your workflow produces the expected results and handles edge cases.
|
||||
@@ -36,7 +36,7 @@ There are several ways to debug workflows in Medusa:
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
Add breakpoints
|
||||
[Add breakpoints](#approach-2-add-breakpoints)
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
To inspect specific steps in your workflow and understand the data flow.
|
||||
@@ -44,7 +44,7 @@ There are several ways to debug workflows in Medusa:
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
Log messages
|
||||
[Log messages](#approach-3-log-messages)
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
To check values during execution with minimal overhead.
|
||||
@@ -52,7 +52,7 @@ There are several ways to debug workflows in Medusa:
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
View Workflow Executions in Medusa Admin
|
||||
[View Workflow Executions in Medusa Admin](#approach-4-monitor-workflow-executions-in-medusa-admin)
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
To monitor stored workflow executions and long-running workflows, especially in production environments.
|
||||
@@ -140,12 +140,12 @@ import {
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk";
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep(
|
||||
"step-1",
|
||||
async () => {
|
||||
const message = "Hello from step 1!";
|
||||
const message = "Hello from step 1!"
|
||||
|
||||
return new StepResponse(
|
||||
message
|
||||
@@ -171,10 +171,10 @@ export const myWorkflow = createWorkflow(
|
||||
step2()
|
||||
|
||||
return new WorkflowResponse({
|
||||
response
|
||||
response,
|
||||
})
|
||||
}
|
||||
);
|
||||
)
|
||||
```
|
||||
</CodeTab>
|
||||
<CodeTab label="Transform Callback" value="transform-callback">
|
||||
@@ -424,12 +424,12 @@ import {
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk";
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep(
|
||||
"step-1",
|
||||
async () => {
|
||||
const message = "Hello from step 1!";
|
||||
const message = "Hello from step 1!"
|
||||
|
||||
return new StepResponse(
|
||||
message
|
||||
@@ -447,10 +447,10 @@ export const myWorkflow = createWorkflow(
|
||||
const response = step1()
|
||||
|
||||
return new WorkflowResponse({
|
||||
response
|
||||
response,
|
||||
})
|
||||
}
|
||||
);
|
||||
)
|
||||
```
|
||||
|
||||
<Note>
|
||||
@@ -460,12 +460,3 @@ Refer to the [Store Workflow Executions](../../fundamentals/workflows/store-exec
|
||||
</Note>
|
||||
|
||||
You can view all executions of this workflow in the Medusa Admin under the [Workflows settings page](!user-guide!/settings/developer/workflows). Each execution will show you the status, input, and output data.
|
||||
|
||||
---
|
||||
|
||||
## Related Topics
|
||||
|
||||
- [Error Handling in Workflows](../../fundamentals/workflows/errors/page.mdx) - For debugging error scenarios and compensation functions
|
||||
- [Long-Running Workflows](../../fundamentals/workflows/long-running-workflow/page.mdx) - For debugging async workflows and step status management
|
||||
- [Store Workflow Executions](../../fundamentals/workflows/store-executions/page.mdx) - For programmatic access to execution details
|
||||
- [Workflow Execution States](!user-guide!/settings/developer/workflows#workflow-execution-status) - For understanding execution statuses in the admin
|
||||
|
||||
@@ -6,7 +6,13 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn how to write integration tests for workflows using [medusaIntegrationTestRunner](../page.mdx) from Medusa's Testing Framwork.
|
||||
In this chapter, you'll learn how to write integration tests for workflows using [medusaIntegrationTestRunner](../page.mdx) from Medusa's Testing Framework.
|
||||
|
||||
<Note>
|
||||
|
||||
For other debugging approaches, refer to the [Debug Workflows](../../../debug-workflows/page.mdx) chapter.
|
||||
|
||||
</Note>
|
||||
|
||||
<Prerequisites
|
||||
items={[
|
||||
@@ -17,7 +23,7 @@ In this chapter, you'll learn how to write integration tests for workflows using
|
||||
]}
|
||||
/>
|
||||
|
||||
## Write Integration Test for Workflow
|
||||
## Write Integration Test for a Workflow
|
||||
|
||||
Consider you have the following workflow defined at `src/workflows/hello-world.ts`:
|
||||
|
||||
@@ -65,7 +71,7 @@ medusaIntegrationTestRunner({
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
You use the `medusaIntegrationTestRunner` to write an integration test for the workflow. The test pases if the workflow returns the string `"Hello, World!"`.
|
||||
You use the `medusaIntegrationTestRunner` to write an integration test for the workflow. The test passes if the workflow returns the string `"Hello, World!"`.
|
||||
|
||||
### Jest Timeout
|
||||
|
||||
@@ -78,32 +84,32 @@ jest.setTimeout(60 * 1000)
|
||||
|
||||
---
|
||||
|
||||
## Run Test
|
||||
## Run Tests
|
||||
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
<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).
|
||||
If you don't have a `test:integration:http` 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.
|
||||
This runs your Medusa application and runs the tests available under the `integration-tests/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:
|
||||
You might want to verify that a workflow throws an error in certain edge cases. To test that a workflow throws an error:
|
||||
|
||||
- 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:
|
||||
For example, if you have the following step in your workflow that throws a `MedusaError`:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts"
|
||||
import { MedusaError } from "@medusajs/framework/utils"
|
||||
@@ -123,7 +129,7 @@ import { helloWorldWorkflow } from "../../src/workflows/hello-world"
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test hello-world workflow", () => {
|
||||
it("returns message", async () => {
|
||||
it("should throw error when item doesn't exist", async () => {
|
||||
const { errors } = await helloWorldWorkflow(getContainer())
|
||||
.run({
|
||||
throwOnError: false,
|
||||
@@ -139,6 +145,432 @@ medusaIntegrationTestRunner({
|
||||
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.
|
||||
The `errors` property contains an array of errors thrown during the execution of the workflow. Each error item has an `error` object, which is the error thrown.
|
||||
|
||||
If you threw a `MedusaError`, then you can check the error message in `errors[0].error.message`.
|
||||
If you threw a `MedusaError`, then you can check the error message in `errors[0].error.message`.
|
||||
|
||||
---
|
||||
|
||||
## Test Long-Running Workflows
|
||||
|
||||
Since [long-running workflows](../../../../fundamentals/workflows/long-running-workflow/page.mdx) run asynchronously, testing them requires a different approach than synchronous workflows.
|
||||
|
||||
When testing long-running workflows, you need to:
|
||||
|
||||
1. Set the asynchronous steps as successful manually.
|
||||
2. Subscribe to the workflow's events to listen for the workflow execution's completion.
|
||||
3. Verify the output of the workflow after it has completed.
|
||||
|
||||
For example, consider you have the following long-running workflow defined at `src/workflows/long-running-workflow.ts`:
|
||||
|
||||
```ts title="src/workflows/long-running-workflow.ts" highlights={[["15"]]}
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
WorkflowResponse,
|
||||
StepResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep("step-1", async () => {
|
||||
return new StepResponse({})
|
||||
})
|
||||
|
||||
const step2 = createStep(
|
||||
{
|
||||
name: "step-2",
|
||||
async: true,
|
||||
},
|
||||
async () => {
|
||||
console.log("Waiting to be successful...")
|
||||
}
|
||||
)
|
||||
|
||||
const step3 = createStep("step-3", async () => {
|
||||
return new StepResponse("Finished three steps")
|
||||
})
|
||||
|
||||
const longRunningWorkflow = createWorkflow(
|
||||
"long-running",
|
||||
function () {
|
||||
step1()
|
||||
step2()
|
||||
const message = step3()
|
||||
|
||||
return new WorkflowResponse({
|
||||
message,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export default longRunningWorkflow
|
||||
```
|
||||
|
||||
`step2` in this workflow is an asynchronous step that you need to set as successful manually in your test.
|
||||
|
||||
You can write the following test to ensure that the long-running workflow completes successfully:
|
||||
|
||||
export const longRunningWorkflowHighlights1 = [
|
||||
["11", "longRunningWorkflow", "Execute the long-running workflow."],
|
||||
["14", "workflowEngineService", "Resolve the Workflow Engine Module's service."],
|
||||
["19", "workflowCompletion", "Create a promise to wait for the workflow's completion."],
|
||||
["30", "subscribe", "Subscribe to the workflow's events."],
|
||||
["44", "setStepSuccess", "Set the asynchronous step as successful."],
|
||||
["54", "afterSubscriber", "Wait for the promise to resolve when workflow execution completes."],
|
||||
["56", "expect", "Assert that the workflow's result matches the expected output."],
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/long-running-workflow.spec.ts" highlights={longRunningWorkflowHighlights1}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import longRunningWorkflow from "../../src/workflows/long-running-workflow"
|
||||
import { Modules, TransactionHandlerType } from "@medusajs/framework/utils"
|
||||
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test long-running workflow", () => {
|
||||
it("returns message", async () => {
|
||||
const container = getContainer()
|
||||
const { transaction } = await longRunningWorkflow(container)
|
||||
.run()
|
||||
|
||||
const workflowEngineService = container.resolve(
|
||||
Modules.WORKFLOW_ENGINE
|
||||
)
|
||||
|
||||
let workflowOk: any
|
||||
const workflowCompletion = new Promise((ok) => {
|
||||
workflowOk = ok
|
||||
})
|
||||
|
||||
const subscriptionOptions = {
|
||||
workflowId: "long-running",
|
||||
transactionId: transaction.transactionId,
|
||||
subscriberId: "long-running-subscriber",
|
||||
}
|
||||
|
||||
|
||||
await workflowEngineService.subscribe({
|
||||
...subscriptionOptions,
|
||||
subscriber: async (data) => {
|
||||
if (data.eventType === "onFinish") {
|
||||
workflowOk(data.result.message)
|
||||
// unsubscribe
|
||||
await workflowEngineService.unsubscribe({
|
||||
...subscriptionOptions,
|
||||
subscriberOrId: subscriptionOptions.subscriberId,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-2",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done!"),
|
||||
})
|
||||
|
||||
const afterSubscriber = await workflowCompletion
|
||||
|
||||
expect(afterSubscriber).toBe("Finished three steps")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
In this test, you:
|
||||
|
||||
1. Execute the long-running workflow and get the transaction details from the `run` method's result.
|
||||
2. Resolve the [Workflow Engine Module](!resources!/infrastructure-modules/workflow-engine)'s service from the Medusa container.
|
||||
3. Create a promise to wait for the workflow's completion.
|
||||
4. Subscribe to the workflow's events using the Workflow Engine Module's `subscribe` method.
|
||||
- The `subscriber` function is called whenever an event related to the workflow occurs. On the `onFinish` event that indicates the workflow has completed, you resolve the promise with the workflow's result.
|
||||
5. Set the asynchronous step as successful using the `setStepSuccess` method of the Workflow Engine Module.
|
||||
6. Wait for the promise to resolve, which indicates that the workflow has completed successfully.
|
||||
7. Finally, you assert that the workflow's result matches the expected output.
|
||||
|
||||
If you run the integration test, it will execute the long-running workflow and verify that it completes and returns the expected result.
|
||||
|
||||
### Example with Multiple Asynchronous Steps
|
||||
|
||||
If your long-running workflow has multiple asynchronous steps, you must set each of them as successful in your test before the workflow can complete.
|
||||
|
||||
Here's how the test would look like if you had two asynchronous steps:
|
||||
|
||||
export const longRunningWorkflowHighlights2 = [
|
||||
["43", "setStepSuccess", "Set the first asynchronous step as successful."],
|
||||
["53", "setStepSuccess", "Set the second asynchronous step as successful."],
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/long-running-workflow-multiple-steps.spec.ts" highlights={longRunningWorkflowHighlights2}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import longRunningWorkflow from "../../src/workflows/long-running-workflow"
|
||||
import { Modules, TransactionHandlerType } from "@medusajs/framework/utils"
|
||||
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test long-running workflow with multiple async steps", () => {
|
||||
it("returns message", async () => {
|
||||
const container = getContainer()
|
||||
const { transaction } = await longRunningWorkflow(container)
|
||||
.run()
|
||||
|
||||
const workflowEngineService = container.resolve(
|
||||
Modules.WORKFLOW_ENGINE
|
||||
)
|
||||
|
||||
let workflowOk: any
|
||||
const workflowCompletion = new Promise((ok) => {
|
||||
workflowOk = ok
|
||||
})
|
||||
|
||||
const subscriptionOptions = {
|
||||
workflowId: "long-running",
|
||||
transactionId: transaction.transactionId,
|
||||
subscriberId: "long-running-subscriber",
|
||||
}
|
||||
|
||||
await workflowEngineService.subscribe({
|
||||
...subscriptionOptions,
|
||||
subscriber: async (data) => {
|
||||
if (data.eventType === "onFinish") {
|
||||
workflowOk(data.result.message)
|
||||
// unsubscribe
|
||||
await workflowEngineService.unsubscribe({
|
||||
...subscriptionOptions,
|
||||
subscriberOrId: subscriptionOptions.subscriberId,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-2",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done!"),
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-3",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done with step 3!"),
|
||||
})
|
||||
|
||||
const afterSubscriber = await workflowCompletion
|
||||
|
||||
expect(afterSubscriber).toBe("Finished three steps")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you set both `step-2` and `step-3` as successful before waiting for the workflow to complete.
|
||||
|
||||
---
|
||||
|
||||
## Test Database Operations in Workflows
|
||||
|
||||
In real use cases, you'll often test workflows that perform database operations, such as creating a brand.
|
||||
|
||||
When you test such workflows, you may need to:
|
||||
|
||||
- Verify that the database operations were performed correctly. For example, that a brand was created with the expected properties.
|
||||
- Perform database actions before testing the workflow. For example, creating a brand before testing a workflow that deletes it.
|
||||
|
||||
This section provides examples of both scenarios.
|
||||
|
||||
### Verify Database Operations in Workflow Test
|
||||
|
||||
To retrieve data from the database after running a workflow, you can resolve and use either the module's service (for example, the Brand Module's service) or [Query](../../../../fundamentals/module-links/query/page.mdx).
|
||||
|
||||
For example, the following test verifies that a brand was created by a workflow:
|
||||
|
||||
export const workflowBrandHighlights = [
|
||||
["10", "createBrandWorkflow", "Execute the create brand workflow."],
|
||||
["17", "brandModuleService", "Resolve the Brand Module's service."],
|
||||
["19", "retrieveBrand", "Retrieve the created brand from the database."],
|
||||
["21", "expect", "Assert that the brand was created with the expected properties."],
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand.spec.ts" highlights={workflowBrandHighlights}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { createBrandWorkflow } from "../../src/workflows/create-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test create brand workflow", () => {
|
||||
it("creates a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result: brand } = await createBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
name: "Test Brand",
|
||||
},
|
||||
})
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
|
||||
const createdBrand = await brandModuleService.retrieveBrand(brand.id)
|
||||
expect(createdBrand).toBeDefined()
|
||||
expect(createdBrand.name).toBe("Test Brand")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
In this test, you run the workflow, which creates a brand. Then, you retrieve the brand from the database using the Brand Module's service and verify that it was created with the expected properties.
|
||||
|
||||
### Perform Database Actions Before Testing Workflow
|
||||
|
||||
You can perform database actions before testing workflows in the `beforeAll` or `beforeEach` hooks of your test suite. In those hooks, you can create data that is useful for your workflow tests.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Learn more about test hooks in [Jest's Documentation](https://jestjs.io/docs/setup-teardown).
|
||||
|
||||
</Note>
|
||||
|
||||
You can perform the database actions before testing a workflow by either:
|
||||
|
||||
- Using the module's service (for example, the Brand Module's service).
|
||||
- Using an existing workflow that performs the database actions.
|
||||
|
||||
#### Use Module's Service
|
||||
|
||||
For example, the following test creates a brand using the Brand Module's service before running the workflow that deletes it:
|
||||
|
||||
export const workflowBrandDeleteHighlights = [
|
||||
["14", "createBrands", "Create a brand using the Brand Module's service."],
|
||||
["24", "deleteBrandWorkflow", "Run the delete brand workflow."],
|
||||
["34", "expect", "Assert that the brand was deleted successfully."],
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand-delete.spec.ts"
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { deleteBrandWorkflow } from "../../src/workflows/delete-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
let brandId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const container = getContainer()
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
|
||||
const brand = await brandModuleService.createBrands({
|
||||
name: "Test Brand",
|
||||
})
|
||||
|
||||
brandId = brand.id
|
||||
})
|
||||
|
||||
describe("Test delete brand workflow", () => {
|
||||
it("deletes a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result } = await deleteBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
id: brandId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
await expect(brandModuleService.retrieveBrand(brandId))
|
||||
.rejects.toThrow()
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you:
|
||||
|
||||
1. Use the `beforeAll` hook to create a brand before running the workflow that deletes it.
|
||||
2. Create a test that runs the `deleteBrandWorkflow` to delete the created brand.
|
||||
3. Verify that the brand was deleted successfully by checking that retrieving it throws an error.
|
||||
|
||||
#### Use Existing Workflow
|
||||
|
||||
Alternatively, if you already have a workflow that performs the database operations, you can use that workflow in the `beforeAll` or `beforeEach` hook. This is useful if the database operations are complex and are already encapsulated in a workflow.
|
||||
|
||||
For example, you can modify the `beforeAll` hook to use the `createBrandWorkflow`:
|
||||
|
||||
export const workflowBrandDeleteHighlights2 = [
|
||||
["13", "createBrandWorkflow", "Create a brand using the create brand workflow."],
|
||||
["26", "deleteBrandWorkflow", "Run the delete brand workflow."],
|
||||
["36", "expect", "Assert that the brand was deleted successfully."],
|
||||
]
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand-delete.spec.ts" highlights={workflowBrandDeleteHighlights2}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { deleteBrandWorkflow } from "../../src/workflows/delete-brand"
|
||||
import { createBrandWorkflow } from "../../src/workflows/create-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
let brandId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const container = getContainer()
|
||||
|
||||
const { result: brand } = await createBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
name: "Test Brand",
|
||||
},
|
||||
})
|
||||
|
||||
brandId = brand.id
|
||||
})
|
||||
|
||||
describe("Test delete brand workflow", () => {
|
||||
it("deletes a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result } = await deleteBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
id: brandId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
await expect(brandModuleService.retrieveBrand(brandId))
|
||||
.rejects.toThrow()
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you:
|
||||
|
||||
1. Use the `beforeAll` hook to run the `createBrandWorkflow`, which creates a brand before running the workflow that deletes it.
|
||||
2. Create a test that runs the `deleteBrandWorkflow` to delete the created brand.
|
||||
3. Verify that the brand was deleted successfully by checking that retrieving it throws an error.
|
||||
|
||||
@@ -52,7 +52,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/custom-cli-scripts/page.mdx": "2025-07-25T15:32:47.587Z",
|
||||
"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/integration-tests/workflows/page.mdx": "2025-07-30T13:43:44.636Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-07-23T15:32:18.008Z",
|
||||
"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",
|
||||
@@ -126,5 +126,5 @@ export const generatedEditDates = {
|
||||
"app/learn/installation/docker/page.mdx": "2025-07-23T15:34:18.530Z",
|
||||
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
|
||||
"app/learn/introduction/from-v1-to-v2/page.mdx": "2025-07-30T08:13:48.592Z",
|
||||
"app/learn/debugging-and-testing/debug-workflows/page.mdx": "2025-07-30T10:38:41.398Z"
|
||||
"app/learn/debugging-and-testing/debug-workflows/page.mdx": "2025-07-30T13:45:14.117Z"
|
||||
}
|
||||
@@ -3575,12 +3575,12 @@ import {
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk";
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep(
|
||||
"step-1",
|
||||
async () => {
|
||||
const message = "Hello from step 1!";
|
||||
const message = "Hello from step 1!"
|
||||
|
||||
return new StepResponse(
|
||||
message
|
||||
@@ -3606,10 +3606,10 @@ export const myWorkflow = createWorkflow(
|
||||
step2()
|
||||
|
||||
return new WorkflowResponse({
|
||||
response
|
||||
response,
|
||||
})
|
||||
}
|
||||
);
|
||||
)
|
||||
```
|
||||
|
||||
### Transform Callback
|
||||
@@ -3842,12 +3842,12 @@ import {
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk";
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep(
|
||||
"step-1",
|
||||
async () => {
|
||||
const message = "Hello from step 1!";
|
||||
const message = "Hello from step 1!"
|
||||
|
||||
return new StepResponse(
|
||||
message
|
||||
@@ -3865,25 +3865,16 @@ export const myWorkflow = createWorkflow(
|
||||
const response = step1()
|
||||
|
||||
return new WorkflowResponse({
|
||||
response
|
||||
response,
|
||||
})
|
||||
}
|
||||
);
|
||||
)
|
||||
```
|
||||
|
||||
Refer to the [Store Workflow Executions](https://docs.medusajs.com/learn/fundamentals/workflows/store-executions/index.html.md) chapter to learn more.
|
||||
|
||||
You can view all executions of this workflow in the Medusa Admin under the [Workflows settings page](https://docs.medusajs.com/user-guide/settings/developer/workflows/index.html.md). Each execution will show you the status, input, and output data.
|
||||
|
||||
***
|
||||
|
||||
## Related Topics
|
||||
|
||||
- [Error Handling in Workflows](https://docs.medusajs.com/learn/fundamentals/workflows/errors/index.html.md) - For debugging error scenarios and compensation functions
|
||||
- [Long-Running Workflows](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow/index.html.md) - For debugging async workflows and step status management
|
||||
- [Store Workflow Executions](https://docs.medusajs.com/learn/fundamentals/workflows/store-executions/index.html.md) - For programmatic access to execution details
|
||||
- [Workflow Execution States](https://docs.medusajs.com/user-guide/settings/developer/workflows#workflow-execution-status/index.html.md) - For understanding execution statuses in the admin
|
||||
|
||||
|
||||
# Configure Instrumentation
|
||||
|
||||
@@ -4804,13 +4795,15 @@ The next chapters provide examples of writing integration tests for API routes a
|
||||
|
||||
# Example: Write Integration Tests for Workflows
|
||||
|
||||
In this chapter, you'll learn how to write integration tests for workflows using [medusaIntegrationTestRunner](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/integration-tests/index.html.md) from Medusa's Testing Framwork.
|
||||
In this chapter, you'll learn how to write integration tests for workflows using [medusaIntegrationTestRunner](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/integration-tests/index.html.md) from Medusa's Testing Framework.
|
||||
|
||||
For other debugging approaches, refer to the [Debug Workflows](https://docs.medusajs.com/learn/debugging-and-testing/debug-workflows/index.html.md) chapter.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Testing Tools Setup](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/index.html.md)
|
||||
|
||||
## Write Integration Test for Workflow
|
||||
## Write Integration Test for a Workflow
|
||||
|
||||
Consider you have the following workflow defined at `src/workflows/hello-world.ts`:
|
||||
|
||||
@@ -4858,7 +4851,7 @@ medusaIntegrationTestRunner({
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
You use the `medusaIntegrationTestRunner` to write an integration test for the workflow. The test pases if the workflow returns the string `"Hello, World!"`.
|
||||
You use the `medusaIntegrationTestRunner` to write an integration test for the workflow. The test passes if the workflow returns the string `"Hello, World!"`.
|
||||
|
||||
### Jest Timeout
|
||||
|
||||
@@ -4871,28 +4864,28 @@ jest.setTimeout(60 * 1000)
|
||||
|
||||
***
|
||||
|
||||
## Run Test
|
||||
## Run Tests
|
||||
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
If you don't have a `test:integration` 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).
|
||||
If you don't have a `test:integration:http` 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 under the `integrations/http` directory.
|
||||
This runs your Medusa application and runs the tests available under the `integration-tests/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:
|
||||
You might want to verify that a workflow throws an error in certain edge cases. To test that a workflow throws an error:
|
||||
|
||||
- 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:
|
||||
For example, if you have the following step in your workflow that throws a `MedusaError`:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts"
|
||||
import { MedusaError } from "@medusajs/framework/utils"
|
||||
@@ -4912,7 +4905,7 @@ import { helloWorldWorkflow } from "../../src/workflows/hello-world"
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test hello-world workflow", () => {
|
||||
it("returns message", async () => {
|
||||
it("should throw error when item doesn't exist", async () => {
|
||||
const { errors } = await helloWorldWorkflow(getContainer())
|
||||
.run({
|
||||
throwOnError: false,
|
||||
@@ -4928,10 +4921,398 @@ medusaIntegrationTestRunner({
|
||||
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.
|
||||
The `errors` property contains an array of errors thrown during the execution of the workflow. Each error item has an `error` object, which is the error thrown.
|
||||
|
||||
If you threw a `MedusaError`, then you can check the error message in `errors[0].error.message`.
|
||||
|
||||
***
|
||||
|
||||
## Test Long-Running Workflows
|
||||
|
||||
Since [long-running workflows](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow/index.html.md) run asynchronously, testing them requires a different approach than synchronous workflows.
|
||||
|
||||
When testing long-running workflows, you need to:
|
||||
|
||||
1. Set the asynchronous steps as successful manually.
|
||||
2. Subscribe to the workflow's events to listen for the workflow execution's completion.
|
||||
3. Verify the output of the workflow after it has completed.
|
||||
|
||||
For example, consider you have the following long-running workflow defined at `src/workflows/long-running-workflow.ts`:
|
||||
|
||||
```ts title="src/workflows/long-running-workflow.ts" highlights={[["15"]]}
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
WorkflowResponse,
|
||||
StepResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep("step-1", async () => {
|
||||
return new StepResponse({})
|
||||
})
|
||||
|
||||
const step2 = createStep(
|
||||
{
|
||||
name: "step-2",
|
||||
async: true,
|
||||
},
|
||||
async () => {
|
||||
console.log("Waiting to be successful...")
|
||||
}
|
||||
)
|
||||
|
||||
const step3 = createStep("step-3", async () => {
|
||||
return new StepResponse("Finished three steps")
|
||||
})
|
||||
|
||||
const longRunningWorkflow = createWorkflow(
|
||||
"long-running",
|
||||
function () {
|
||||
step1()
|
||||
step2()
|
||||
const message = step3()
|
||||
|
||||
return new WorkflowResponse({
|
||||
message,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export default longRunningWorkflow
|
||||
```
|
||||
|
||||
`step2` in this workflow is an asynchronous step that you need to set as successful manually in your test.
|
||||
|
||||
You can write the following test to ensure that the long-running workflow completes successfully:
|
||||
|
||||
```ts title="integration-tests/http/long-running-workflow.spec.ts" highlights={longRunningWorkflowHighlights1}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import longRunningWorkflow from "../../src/workflows/long-running-workflow"
|
||||
import { Modules, TransactionHandlerType } from "@medusajs/framework/utils"
|
||||
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test long-running workflow", () => {
|
||||
it("returns message", async () => {
|
||||
const container = getContainer()
|
||||
const { transaction } = await longRunningWorkflow(container)
|
||||
.run()
|
||||
|
||||
const workflowEngineService = container.resolve(
|
||||
Modules.WORKFLOW_ENGINE
|
||||
)
|
||||
|
||||
let workflowOk: any
|
||||
const workflowCompletion = new Promise((ok) => {
|
||||
workflowOk = ok
|
||||
})
|
||||
|
||||
const subscriptionOptions = {
|
||||
workflowId: "long-running",
|
||||
transactionId: transaction.transactionId,
|
||||
subscriberId: "long-running-subscriber",
|
||||
}
|
||||
|
||||
|
||||
await workflowEngineService.subscribe({
|
||||
...subscriptionOptions,
|
||||
subscriber: async (data) => {
|
||||
if (data.eventType === "onFinish") {
|
||||
workflowOk(data.result.message)
|
||||
// unsubscribe
|
||||
await workflowEngineService.unsubscribe({
|
||||
...subscriptionOptions,
|
||||
subscriberOrId: subscriptionOptions.subscriberId,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-2",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done!"),
|
||||
})
|
||||
|
||||
const afterSubscriber = await workflowCompletion
|
||||
|
||||
expect(afterSubscriber).toBe("Finished three steps")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
In this test, you:
|
||||
|
||||
1. Execute the long-running workflow and get the transaction details from the `run` method's result.
|
||||
2. Resolve the [Workflow Engine Module](https://docs.medusajs.com/resources/infrastructure-modules/workflow-engine/index.html.md)'s service from the Medusa container.
|
||||
3. Create a promise to wait for the workflow's completion.
|
||||
4. Subscribe to the workflow's events using the Workflow Engine Module's `subscribe` method.
|
||||
- The `subscriber` function is called whenever an event related to the workflow occurs. On the `onFinish` event that indicates the workflow has completed, you resolve the promise with the workflow's result.
|
||||
5. Set the asynchronous step as successful using the `setStepSuccess` method of the Workflow Engine Module.
|
||||
6. Wait for the promise to resolve, which indicates that the workflow has completed successfully.
|
||||
7. Finally, you assert that the workflow's result matches the expected output.
|
||||
|
||||
If you run the integration test, it will execute the long-running workflow and verify that it completes and returns the expected result.
|
||||
|
||||
### Example with Multiple Asynchronous Steps
|
||||
|
||||
If your long-running workflow has multiple asynchronous steps, you must set each of them as successful in your test before the workflow can complete.
|
||||
|
||||
Here's how the test would look like if you had two asynchronous steps:
|
||||
|
||||
```ts title="integration-tests/http/long-running-workflow-multiple-steps.spec.ts" highlights={longRunningWorkflowHighlights2}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import longRunningWorkflow from "../../src/workflows/long-running-workflow"
|
||||
import { Modules, TransactionHandlerType } from "@medusajs/framework/utils"
|
||||
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test long-running workflow with multiple async steps", () => {
|
||||
it("returns message", async () => {
|
||||
const container = getContainer()
|
||||
const { transaction } = await longRunningWorkflow(container)
|
||||
.run()
|
||||
|
||||
const workflowEngineService = container.resolve(
|
||||
Modules.WORKFLOW_ENGINE
|
||||
)
|
||||
|
||||
let workflowOk: any
|
||||
const workflowCompletion = new Promise((ok) => {
|
||||
workflowOk = ok
|
||||
})
|
||||
|
||||
const subscriptionOptions = {
|
||||
workflowId: "long-running",
|
||||
transactionId: transaction.transactionId,
|
||||
subscriberId: "long-running-subscriber",
|
||||
}
|
||||
|
||||
await workflowEngineService.subscribe({
|
||||
...subscriptionOptions,
|
||||
subscriber: async (data) => {
|
||||
if (data.eventType === "onFinish") {
|
||||
workflowOk(data.result.message)
|
||||
// unsubscribe
|
||||
await workflowEngineService.unsubscribe({
|
||||
...subscriptionOptions,
|
||||
subscriberOrId: subscriptionOptions.subscriberId,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-2",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done!"),
|
||||
})
|
||||
|
||||
await workflowEngineService.setStepSuccess({
|
||||
idempotencyKey: {
|
||||
action: TransactionHandlerType.INVOKE,
|
||||
transactionId: transaction.transactionId,
|
||||
stepId: "step-3",
|
||||
workflowId: "long-running",
|
||||
},
|
||||
stepResponse: new StepResponse("Done with step 3!"),
|
||||
})
|
||||
|
||||
const afterSubscriber = await workflowCompletion
|
||||
|
||||
expect(afterSubscriber).toBe("Finished three steps")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you set both `step-2` and `step-3` as successful before waiting for the workflow to complete.
|
||||
|
||||
***
|
||||
|
||||
## Test Database Operations in Workflows
|
||||
|
||||
In real use cases, you'll often test workflows that perform database operations, such as creating a brand.
|
||||
|
||||
When you test such workflows, you may need to:
|
||||
|
||||
- Verify that the database operations were performed correctly. For example, that a brand was created with the expected properties.
|
||||
- Perform database actions before testing the workflow. For example, creating a brand before testing a workflow that deletes it.
|
||||
|
||||
This section provides examples of both scenarios.
|
||||
|
||||
### Verify Database Operations in Workflow Test
|
||||
|
||||
To retrieve data from the database after running a workflow, you can resolve and use either the module's service (for example, the Brand Module's service) or [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query/index.html.md).
|
||||
|
||||
For example, the following test verifies that a brand was created by a workflow:
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand.spec.ts" highlights={workflowBrandHighlights}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { createBrandWorkflow } from "../../src/workflows/create-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
describe("Test create brand workflow", () => {
|
||||
it("creates a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result: brand } = await createBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
name: "Test Brand",
|
||||
},
|
||||
})
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
|
||||
const createdBrand = await brandModuleService.retrieveBrand(brand.id)
|
||||
expect(createdBrand).toBeDefined()
|
||||
expect(createdBrand.name).toBe("Test Brand")
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
```
|
||||
|
||||
In this test, you run the workflow, which creates a brand. Then, you retrieve the brand from the database using the Brand Module's service and verify that it was created with the expected properties.
|
||||
|
||||
### Perform Database Actions Before Testing Workflow
|
||||
|
||||
You can perform database actions before testing workflows in the `beforeAll` or `beforeEach` hooks of your test suite. In those hooks, you can create data that is useful for your workflow tests.
|
||||
|
||||
Learn more about test hooks in [Jest's Documentation](https://jestjs.io/docs/setup-teardown).
|
||||
|
||||
You can perform the database actions before testing a workflow by either:
|
||||
|
||||
- Using the module's service (for example, the Brand Module's service).
|
||||
- Using an existing workflow that performs the database actions.
|
||||
|
||||
#### Use Module's Service
|
||||
|
||||
For example, the following test creates a brand using the Brand Module's service before running the workflow that deletes it:
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand-delete.spec.ts"
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { deleteBrandWorkflow } from "../../src/workflows/delete-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
let brandId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const container = getContainer()
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
|
||||
const brand = await brandModuleService.createBrands({
|
||||
name: "Test Brand",
|
||||
})
|
||||
|
||||
brandId = brand.id
|
||||
})
|
||||
|
||||
describe("Test delete brand workflow", () => {
|
||||
it("deletes a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result } = await deleteBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
id: brandId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
await expect(brandModuleService.retrieveBrand(brandId))
|
||||
.rejects.toThrow()
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you:
|
||||
|
||||
1. Use the `beforeAll` hook to create a brand before running the workflow that deletes it.
|
||||
2. Create a test that runs the `deleteBrandWorkflow` to delete the created brand.
|
||||
3. Verify that the brand was deleted successfully by checking that retrieving it throws an error.
|
||||
|
||||
#### Use Existing Workflow
|
||||
|
||||
Alternatively, if you already have a workflow that performs the database operations, you can use that workflow in the `beforeAll` or `beforeEach` hook. This is useful if the database operations are complex and are already encapsulated in a workflow.
|
||||
|
||||
For example, you can modify the `beforeAll` hook to use the `createBrandWorkflow`:
|
||||
|
||||
```ts title="integration-tests/http/workflow-brand-delete.spec.ts" highlights={workflowBrandDeleteHighlights2}
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { deleteBrandWorkflow } from "../../src/workflows/delete-brand"
|
||||
import { createBrandWorkflow } from "../../src/workflows/create-brand"
|
||||
import { BRAND_MODULE } from "../../src/modules/brand"
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ getContainer }) => {
|
||||
let brandId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const container = getContainer()
|
||||
|
||||
const { result: brand } = await createBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
name: "Test Brand",
|
||||
},
|
||||
})
|
||||
|
||||
brandId = brand.id
|
||||
})
|
||||
|
||||
describe("Test delete brand workflow", () => {
|
||||
it("deletes a brand", async () => {
|
||||
const container = getContainer()
|
||||
const { result } = await deleteBrandWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
id: brandId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
|
||||
const brandModuleService = container.resolve(BRAND_MODULE)
|
||||
await expect(brandModuleService.retrieveBrand(brandId))
|
||||
.rejects.toThrow()
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you:
|
||||
|
||||
1. Use the `beforeAll` hook to run the `createBrandWorkflow`, which creates a brand before running the workflow that deletes it.
|
||||
2. Create a test that runs the `deleteBrandWorkflow` to delete the created brand.
|
||||
3. Verify that the brand was deleted successfully by checking that retrieving it throws an error.
|
||||
|
||||
|
||||
# Write Tests for Modules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user