Cookie Consent by Free Privacy Policy Generator 📌 Easier TypeScript API Testing with Vitest + MSW

✅ Easier TypeScript API Testing with Vitest + MSW

💡 Newskategorie: Programmierung
🔗 Quelle:


Recently, I took time to write unit tests to ensure if my Slack Web API client library works as expected.

As someone who has developed web services for a long time, I've often found mocking HTTP requests in test scenarios to be bothersome and less flexible than I would prefer.

The Game Changer

However, I discovered a great combination that transformed my API call testing in TypeScript: Vitest and Mock Service Worker (MSW). Their well-crafted design makes them incredibly easy to use, enhancing the overall testing experience.

How It Works

For those eager to see the actual code, you can find it here:

Here’s a step-by-step guide to setting up a new project and writing effective tests:

Setting Up New Project:

Let's start by creating a new project and install the required dependences:

mkdir my-test-app
cd my-test-app
npm init -y
npm i slack-web-api-client
npm i --save-dev typescript vitest msw

Configuring TypeScript:

Add a basic tsconfig.json for writing in TypeScript (note that you don't need to use exactly the same one):

  "compilerOptions": {
    "outDir": "./dist",
    "target": "es2021",
    "noImplicitAny": true,
    "module": "commonjs",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true,
    "allowJs": false
  "include": ["src/**/*"]

Start Writing Test Code:

Start by setting up Vist and MSW in a new test source file under the ./test directory:

import { setupServer } from "msw/node";
import { HttpResponse, http } from "msw";
import { afterAll, afterEach, beforeAll, describe, test, expect } from "vitest";

const server = setupServer();
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

Just by including these lines of code, you're ready to capture all outgoing HTTP requests via the fetch function and reproduce any scenario you'd like!

Now, let's add our first simple test:

import { SlackAPIClient } from "slack-web-api-client";

describe("Slack API client", async () => {
  test("can perform api.test API call", async () => {
    server.use("", () => {
        return HttpResponse.json({ ok: true });
    const client = new SlackAPIClient();
    const response = await client.api.test();

Run this test using npx vitest and check the output. If you see the following output on your terminal, congratulations! You've successfully run your first test using MSW!

$ npx vitest

 DEV  v1.5.1 /new-app

 ✓ test/sample.test.ts (1)
   ✓ Slack API client (1)
     ✓ can perform api.test API call

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  17:18:37
   Duration  653ms (transform 87ms, setup 0ms, collect 256ms, tests 39ms, environment 0ms, prepare 101ms)

 PASS  Waiting for file changes...
       press h to show help, press q to quit

When you modify the server.use(...) section as shown below,

    server.use("", () => {
        return HttpResponse.json("ratelimited", { status: 429, headers: { "Retry-After": "1" } });

the same test should then start to fail:

test/sample.test.ts (1) 1048ms
   ❯ Slack API client (1) 1047ms
     × can perform api.test API call 1045ms

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  test/sample.test.ts > Slack API client > can perform api.test API call
SlackAPIConnectionError: Failed to call api.test (cause: SlackAPIConnectionError: Failed to call api.test (status: 429, body: "ratelimited"))
 ❯ node_modules/slack-web-api-client/src/client/api-client.ts:581:21
 ❯ test/sample.test.ts:24:22
     22|     );
     23|     const client = new SlackAPIClient();
     24|     const response = await client.api.test();
       |                      ^
     25|     assert.isUndefined(response.error);
     26|   });

Serialized Error: { apiName: 'api.test', status: -1, body: '', headers: undefined }
Caused by: SlackAPIConnectionError: Failed to call api.test (status: 429, body: "ratelimited")
 ❯ node_modules/slack-web-api-client/src/client/api-client.ts:602:13
 ❯ node_modules/slack-web-api-client/src/client/api-client.ts:577:18
 ❯ test/sample.test.ts:24:22

However, this library attempts a retry when it receives a rate-limited error response from Slack. Therefore, after adjusting the scenario to be more realistic,

    const responses = [
      HttpResponse.json("ratelimited", { status: 429, headers: { "Retry-After": "1" } }),
      HttpResponse.json({ ok: true }),
    server.use("", () => {
        return responses.shift();

the test will start passing again!

 RERUN  test/sample.test.ts x3

 ✓ test/sample.test.ts (1) 1044ms
   ✓ Slack API client (1) 1042ms
     ✓ can perform api.test API call 1041ms

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  17:28:21
   Duration  1.21s

 PASS  Waiting for file changes...

The interaction here is very smooth. Every time you save a change to the test code, the test is immediately executed again. Additionally, the outputs from the Vitest framework are so easy to understand that you won't be confused about what to do next.

Wrap Up

For me, using Vitest and MSW has significantly changed the testing experience for SDK development. I highly recommend trying these tools!


✅ Easier TypeScript API Testing with Vitest + MSW

📈 85.7 Punkte

✅ Integration testing of Redux-components with MSW

📈 34.67 Punkte

✅ [local] Modbus Slave PLC 7 - '.msw' Buffer Overflow (PoC)

📈 27.94 Punkte


📈 27.94 Punkte

✅ How to Build a Vue E-commerce App Using MSW

📈 27.94 Punkte

✅ 📚 How to Handle Multiple MSW Handlers in Storybook Stories

📈 27.94 Punkte

✅ CVE-2023-27195 | Trimble TM4Web 22.2.0 Registration tm_ajax.msw access control

📈 27.94 Punkte

✅ #0daytoday #Modbus Slave PLC 7 - .msw Buffer Overflow Exploit [remote #exploits #0day #Exploit]

📈 27.94 Punkte


Datei nicht gefunden!