Documentation

7.2.1. Example: Write Integration Tests for API Routes

In this chapter, you'll learn how to write integration tests for API routes using the medusaIntegrationTestRunner utility function.

Test a GET API Route#

Consider the following API route created at src/api/custom/route.ts:

src/api/custom/route.ts
1import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"2
3export async function GET(4  req: MedusaRequest,5  res: MedusaResponse6){7  res.json({8    message: "Hello, World!",9  })10}

To write an integration test that tests this API route, create the file integration-tests/http/custom-routes.spec.ts with the following content:

integration-tests/http/custom-routes.spec.ts
1import { medusaIntegrationTestRunner } from "medusa-test-utils"2
3medusaIntegrationTestRunner({4  testSuite: ({ api, getContainer }) => {5    describe("Custom endpoints", () => {6      describe("GET /custom", () => {7        it("returns correct message", async () => {8          const response = await api.get(9            `/custom`10          )11  12          expect(response.status).toEqual(200)13          expect(response.data).toHaveProperty("message")14          expect(response.data.message).toEqual("Hello, World!")15        })16      })17    })18  },19})

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:

TipIf you don't have a test:integration script in package.json , refer to the Medusa Testing Tools chapter .

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:

src/modules/hello/models/my-custom.ts
1import { model } from "@medusajs/utils"2
3const MyCustom = model.define("my_custom", {4  id: model.id().primaryKey(),5  name: model.text(),6})7
8export default MyCustom

And consider that the file src/api/custom/route.ts defines another route handler for POST requests:

src/api/custom/route.ts
1// other imports...2import HelloModuleService from "../../../modules/hello/service"3
4// ...5
6export async function POST(7  req: MedusaRequest,8  res: MedusaResponse9) {10  const helloModuleService: HelloModuleService = req.scope.resolve(11    "helloModuleService"12  )13
14  const myCustom = await helloModuleService.createMyCustoms(15    req.body16  )17
18  res.json({19    my_custom: myCustom,20  })21}

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:

integration-tests/http/custom-routes.spec.ts
1// other imports...2import HelloModuleService from "../../src/modules/hello/service"3
4medusaIntegrationTestRunner({5  testSuite: ({ api, getContainer }) => {6    describe("Custom endpoints", () => {7      // other tests...8
9      describe("POST /custom", () => {10        const id = "1"11
12        it("Creates my custom", async () => {13  14          const response = await api.post(15            `/custom`,16            {17              id,18              name: "Test",19            }20          )21  22          expect(response.status).toEqual(200)23          expect(response.data).toHaveProperty("my_custom")24          expect(response.data.my_custom).toEqual({25            id,26            name: "Test",27            created_at: expect.any(String),28            updated_at: expect.any(String),29          })30        })31      })32    })33  },34})

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 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:

integration-tests/http/custom-routes.spec.ts
1// other imports...2import HelloModuleService from "../../src/modules/hello/service"3
4medusaIntegrationTestRunner({5  testSuite: ({ api, getContainer }) => {6    describe("Custom endpoints", () => {7      // other tests...8
9      describe("POST /custom", () => {10        // ...11        afterAll(() => async () => {12          const helloModuleService: HelloModuleService = getContainer().resolve(13            "helloModuleService"14          )15
16          await helloModuleService.deleteMyCustoms(id)17        })18      })19    })20  },21})

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:

src/api/custom/[id]/route.ts
1import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"2import HelloModuleService from "../../../modules/hello/service"3
4export async function DELETE(5  req: MedusaRequest,6  res: MedusaResponse7) {8  const helloModuleService: HelloModuleService = req.scope.resolve(9    "helloModuleService"10  )11
12  await helloModuleService.deleteMyCustoms(req.params.id)13
14  res.json({15    success: true,16  })17}

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:

integration-tests/http/custom-routes.spec.ts
1medusaIntegrationTestRunner({2  testSuite: ({ api, getContainer }) => {3    describe("Custom endpoints", () => {4      // ...5
6      describe("DELETE /custom/:id", () => {7        const id = "1"8
9        beforeAll(() => async () => {10          const helloModuleService: HelloModuleService = getContainer().resolve(11            "helloModuleService"12          )13
14          await helloModuleService.createMyCustoms({15            id,16            name: "Test",17          })18        })19
20        it("Deletes my custom", async () => {21          const response = await api.delete(22            `/custom/${id}`23          )24
25          expect(response.status).toEqual(200)26          expect(response.data).toHaveProperty("success")27          expect(response.data.success).toBeTruthy()28        })29      })30    })31  },32})

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.
Was this chapter helpful?
Edit this page