author avatar

amber.srivastava

Thu Sep 26 2024

How to test an API endpoint.

Lets say we have to test an API endpoint api/projects

describe("POST /api/projects", () => {
    test("redirect with 401 status if the user is not logged in", async () => {
      jest
        .spyOn(nextAuth, "getServerSession")
        .mockImplementation(() => Promise.resolve());

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: projectData,
      });

      const res = await postProjectHandler(req as any);
      expect(res.status).toEqual(401);
    });

    test("return 400 if the request body is invalid", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: {},
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);

      expect(res.status).toEqual(400);
    });

    test("store project in database", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const mockResponse = {
        ok: true,
        team: {
          id: "T08DABCD",
          name: "Prisma",
        },
      };

      const mockList = jest.fn().mockResolvedValue(mockResponse);
      <http://slackClient.team.info|slackClient.team.info> = mockList;

      const req = createRequest&lt;APIRequest&gt;({
        method: "POST",
        url: "/api/projects",
        body: {
          ...projectData,
        },
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);
      const json = await res.json();

      expect(res.status).toEqual(201);
      expect(json.project.name).toEqual("Test name");
      expect(json.project.description).toEqual(
        "Test description"
      );
    });
  });
  1. describe: This is a block in Jest used to group related tests together. In our case, it groups tests for the POST /api/projects endpoint. It helps organize tests logically.
  2. test: Each test block defines an individual test case. It contains a name (description) of what it’s testing and a function with the test logic. The three tests are: • User is redirected with a 401 if they are not logged in. • A 400 status is returned if the request body is invalid. • The project is stored in the database when valid data is provided.
  3. Mocking: • jest.spyOn(): This creates a mock (or "spy") for a specific function. In this case, we are mocking the getServerSession function from nextAuth to control its output (whether the user is logged in or not). This avoids actually calling the real function and allows you to simulate different conditions. • Mock Implementation: With .mockImplementation(), we’re replacing the real function with a custom one. For example, in the first test, Promise.resolve() is returned to simulate a missing session (not logged in).
  4. createRequest&lt;APIRequest&gt;(): This is likely a helper function that creates a mock request object for testing. We use this to simulate an HTTP request (like sending a POST request to your /api/projects endpoint). It includes: • method: Specifies that it’s a POST request. • url: The endpoint being tested. • body: The request data sent with the POST request.
  5. postProjectHandler(req as any): This function is our handler for the POST /api/projects endpoint. It processes the incoming request (in req), validates the data, and performs actions like saving to the database or returning errors. We’re testing the results of this function.
  6. Assertions: • expect(res.status).toEqual(401): This is checking if the response status matches the expected value. For example, in the first test, we expect a 401 status if the user isn’t logged in. • expect(json.project.name).toEqual("Test name"): Here, you're checking if the response JSON contains the correct project name. <#CCT1JMA0Z|> #promises <#C041BBLJ57G|> #jest #appRouter