Rumah > hujung hadapan web > tutorial js > Permintaan Rangkaian Mengejek Dipermudahkan: Mengintegrasikan Jest dan MSW

Permintaan Rangkaian Mengejek Dipermudahkan: Mengintegrasikan Jest dan MSW

WBOY
Lepaskan: 2024-09-07 15:01:02
asal
1192 orang telah melayarinya

Menulis ujian unit yang melibatkan ejekan atau panggilan API boleh terasa amat menggembirakan—saya sendiri pernah ke sana. Dalam artikel ini, saya akan membimbing anda melalui cara yang lebih mudah dan cekap untuk mengejek permintaan API semasa ujian.
Sebelum kita menyelami, berikut ialah senarai alatan yang akan kami gunakan:

  • Bertindak balas
  • Pustaka Ujian React
  • gurauan
  • Craco : > kami memerlukan ini untuk memanjangkan konfigurasi jest nanti
  • MSW (pekerja perkhidmatan olok-olok)

Jangan risau jika anda tidak biasa dengan segala-galanya—ikut sahaja, dan saya akan membimbing anda melalui setiap langkah.

Berikut ialah pautan Github ke projek

Ikhtisar
Kami akan membina apl React ringkas yang mengambil dan memaparkan senarai Todos menggunakan API Pemegang Tempat Json. Dalam projek ini, kami akan menulis senario ujian untuk mengesahkan perkara berikut:

  • Apl menunjukkan keadaan pemuatan semasa permintaan API sedang dijalankan.
  • Ia memaparkan mesej ralat jika permintaan gagal.
  • Ia memastikan senarai data daripada API dipaparkan dengan betul.
  • Ia memberikan maklum balas apabila permintaan berjaya tetapi tidak mengembalikan data.

Panduan ini akan merangkumi dua pendekatan utama;

  1. Cara Tradisional Mengejek Panggilan API
  2. Pendekatan Moden Menggunakan MSW (Mock Service Worker)

Jom mulakan!

Untuk mula membina apl, ikut langkah berikut:

1. Cipta apl React baharu: Jalankan arahan berikut untuk mencipta aplikasi React anda:

npx create-react-app msw-example
Salin selepas log masuk

2. Mulakan aplikasi: Selepas persediaan, navigasi ke folder projek dan jalankan:

npm start
Salin selepas log masuk

3. Pasang pakej yang diperlukan: Seterusnya, pasang @tanstack/react-query untuk mengurus data pihak klien:

npm install @tanstack/react-query
Salin selepas log masuk

React Query (Tanstack Query) membantu dalam mengendalikan pengurusan keadaan bahagian pelayan, termasuk caching, penyegerakan dan pengambilan data. Anda boleh mengetahui lebih lanjut mengenainya dalam Dokumentasi Rasmi mereka

Anda kini boleh mula menulis logik apl dan menyediakan React Query untuk mengurus pengambilan data dengan cekap. Inilah rupanya selepas menyediakannya.

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

import { Todos } from "components/Todos";

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <div data-testid="app" className="App">
        <Todos />
      </div>
    </QueryClientProvider>
  );
}

export default App;
Salin selepas log masuk

Seterusnya kami mencipta komponen Todos yang memaparkan senarai todos kami.

Todos.js

import { useQuery } from "@tanstack/react-query";

import { getTodos } from "api/todo";

export function Todos() {
  const { data, isError, isLoading } = useQuery({
    queryFn: getTodos,
    queryKey: ["TODOS"],
  });

  if (isLoading) {
    return <p>loading todo list</p>;
  }

  if (isError) {
    return <p>an error occurred fetching todo list</p>;
  }

  return (
    <div>
      {Boolean(data.length) ? (
        <ol>
          {data.map((item) => (
            <li key={item.id}>{item.title}</li>
          ))}
        </ol>
      ) : (
        <p>You do not have todos created yet</p>
      )}
    </div>
  );
}

Salin selepas log masuk

Sekarang segala-galanya telah disediakan, mari mula menulis ujian untuk senario yang kami gariskan sebelum ini. Mula-mula, kami akan melaksanakan ini menggunakan pendekatan tradisional yang kami sudah biasa—mengejek panggilan API menggunakan Jest

Lihat repo github supaya anda boleh mengikutinya

Cara Tradisional Mengejek Panggilan API

React dan Jest berfungsi dengan lancar bersama-sama di luar kotak, jadi tidak perlu untuk konfigurasi atau persediaan tambahan—sekurang-kurangnya buat masa ini. Kami akan membuat fail bernama Todos.test.js di sebelah komponen Todo.js kami, tempat kami akan mengimport komponen Todos dan menulis ujian kami..

Kami mempunyai fungsi yang dipanggil getTodos yang bertanggungjawab untuk membuat panggilan API untuk mendapatkan semula senarai tugasan dan mengembalikan respons.

export async function getTodos() {
  const response = await fetch("https://jsonplaceholder.typicode.com/todos", {
    headers: {
      "Content-Type": "application/json",
    },
  });

  if (!response.ok) {
    const res = await response.json();
    throw new Error(res.message || response.status);
  }

  return response.json();
}


Salin selepas log masuk

Dalam fail Todos.test.js anda, anda perlu mengimport komponen Todos dan mencipta fungsi utiliti yang menyediakan pembungkus dengan pembekal React Query. Ini memastikan komponen Todos dan anak-anaknya boleh menggunakan pertanyaan tindak balas untuk mengurus keadaan pelayan dalam ujian.

import { render, screen, waitFor, within } from "@testing-library/react";

import { Todos } from "./Todos";
import { reactQueryWrapper } from "utils/reactQueryWrapper";
import { getTodos } from "api/todo";

const { wrapper, queryCache } = reactQueryWrapper();

Salin selepas log masuk

Seterusnya, kita perlu mengejek fungsi getTodos. Ini akan membolehkan kami menentukan nilai pulangan untuk setiap senario ujian, memberikan kami kawalan ke atas data yang dipulangkan oleh fungsi semasa ujian. Selain itu, kami akan memastikan bahawa apa-apa sisa data daripada kes ujian sebelumnya dibersihkan, jadi setiap kes ujian bermula dengan senarai yang bersih.

Contoh Kod

jest.mock("api/todo", () => ({
  getTodos: jest.fn(),
}));

afterEach(() => {
  queryCache.clear();
  jest.clearAllMocks();
});

Salin selepas log masuk

Todos.test.js

import { render, screen, waitFor, within } from "@testing-library/react";

import { Todos } from "./Todos";
import { reactQueryWrapper } from "utils/reactQueryWrapper";
import { getTodos } from "api/todo";

const { wrapper, queryCache } = reactQueryWrapper();

jest.mock("api/todo", () => ({
  getTodos: jest.fn(),
}));

afterEach(() => {
  queryCache.clear();
});

afterEach(() => {
  jest.clearAllMocks();
});

Salin selepas log masuk

Senario Ujian Pertama: Memberi keadaan pemuatan
Kami ingin mengesahkan bahawa komponen kami memaparkan keadaan pemuatan dengan betul semasa permintaan sedang dijalankan.

test("Renders loading state", () => {
  getTodos.mockImplementation(() => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve();
      }, 1000);
    });
  });

  render(<Todos />, { wrapper });
  const loadingText = screen.getByText("loading todo list");
  expect(loadingText).toBeInTheDocument();
});
Salin selepas log masuk

Senario Ujian Kedua: Memberikan keadaan ralat apabila permintaan gagal atau terdapat ralat rangkaian
Kami ingin mengesahkan bahawa komponen itu betul menghasilkan keadaan ralat apabila permintaan API gagal atau menghadapi ralat rangkaian.

test("Renders error state when request fails or there is network error", async () => {
  getTodos.mockImplementationOnce(() => {
    return new Promise((resolve, reject) => {
      reject();
    });
  });

  render(<Todos />, { wrapper });
  await screen.findByText("an error occurred fetching todo list");
  expect(
    screen.getByText("an error occurred fetching todo list")
  ).toBeInTheDocument();
});
Salin selepas log masuk

Senario Ujian Ketiga: Memberi senarai tugasan
Kami ingin mengesahkan bahawa komponen kami memaparkan senarai tugasan dengan betul apabila permintaan berjaya.

test("Renders list of todos", async () => {
  getTodos.mockImplementation(() => {
    return Promise.resolve([
      { id: 1, title: "Exercise" },
      { id: 2, title: "Cook" },
    ]);
  });

  render(<Todos />, { wrapper });

  const loadingText = screen.queryByText("loading todo list");
  await waitFor(() => expect(loadingText).not.toBeInTheDocument());
  const list = screen.getByRole("list");
  expect(list).toBeInTheDocument();
  expect(within(list).getAllByRole("listitem")).toHaveLength(2);
});
Salin selepas log masuk

Senario Ujian Keempat: Memberi senarai tugasan
Kami ingin mengesahkan bahawa komponen anda memaparkan mesej maklum balas dengan betul apabila permintaan API mengembalikan senarai tugasan kosong.

test("Renders feedback message when user has an empty list of todos", async () => {
  getTodos.mockImplementationOnce(() => {
    return Promise.resolve([]);
  });

  render(<Todos />, { wrapper });

  await waitFor(() =>
    expect(screen.queryByText("loading todo list")).not.toBeInTheDocument()
  );
  expect(
    screen.getByText("You do not have todos created yet")
  ).toBeInTheDocument();
});
Salin selepas log masuk

Great! Now that we've covered mocking API calls with Jest, let’s explore a better approach using Mock Service Worker (MSW). MSW provides a more elegant and maintainable way to mock API calls by intercepting network requests at the network level rather than within your tests.

Introducing MSW (Mock Service Worker)

Mock Service Worker (MSW) is an API mocking library designed for both browser and Node.js environments. It allows you to intercept outgoing requests, observe them, and provide mocked responses. MSW helps you simulate real-world scenarios in your tests, making them more robust and reliable.

Read more about MSW

Setting Up MSW

Step 1: Install MSW using the following command:

npm install msw@latest --save-dev
Salin selepas log masuk

Step 2: Set up the environment you wish to intercept requests in—either Browser or Node. Before doing so, create a mock directory within your src directory. Inside this directory, you'll create the following files and directories:

browser.js: Handles request interception in the browser environment.
server.js: Handles request interception in the Node.js environment.
handlers: A directory containing files that define the API endpoints to intercept.

Here’s how your folder structure should look:

src/
  └── mock/
      ├── browser.js
      ├── server.js
      └── handlers/
Salin selepas log masuk

This setup ensures that you have a clear organization for intercepting and handling requests in both browser and Node.js environments using MSW.

Browser Environment Setup

To set up MSW for intercepting requests in the browser, follow these steps:

1. Create the browser.js File

In your src/mock directory, create a file named browser.js. This
file will set up the MSW worker to intercept requests in the
browser environment.

// src/mock/browser.js

import { setupWorker } from 'msw/browser';

// Create a worker instance to intercept requests
export const worker = setupWorker();

Salin selepas log masuk

2. Generate the mockServiceWorker.js File
This file is required for MSW to function properly in the browser.
Generate it using the following command from the root directory of
your application:

npx msw init <PUBLIC_DIR> --save
Salin selepas log masuk

This command initializes the MSW service worker and places the mockServiceWorker.js file into the public directory of your React app.

3. Start the Service Worker

Import and start the worker in your application entry point
(typically index.js or App.js).

// src/index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

if (process.env.NODE_ENV === "development") {
  const mswState = localStorage.getItem("mswState") === "enabled";
  if (mswState) {
    const { worker } = require("./mocks/browser");
    worker.start();
    window.__mswStop = worker.stop;
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Salin selepas log masuk

4. Verify the Setup
To ensure that the service worker is correctly set up, navigate to
the URL of your application in the browser:

http://localhost:3000/mockServiceWorker.js
Salin selepas log masuk

You should see the service worker script displayed in your browser. This confirms that the service worker is correctly installed and ready to intercept requests.

If your MSW setup is correct and enabled, you should see a console message indicating that MSW is active. Your browser console should display logs similar to this:

Mocking Network Requests Made Easy: Integrating Jest and MSW

These logs confirm that the MSW service worker is properly intercepting network requests and is ready to mock API responses according to the handlers you’ve defined.

Node Environment Setup

To set up MSW for intercepting requests in a Node.js environment (for example, in server-side tests), follow these steps:

Step 1: Create the server.js File
In the src/mock directory, create a file named server.js. This file sets up the MSW server to intercept requests in a Node.js environment.

// src/mock/server.js

import { setupServer } from "msw/browser";

// Create a server instance with the defined request handlers
export const server = setupServer();

Salin selepas log masuk

Step 2: Define the API Handlers
Create a file named posts.js in the handlers directory.This file will describe the APIs you want to intercept and the mock responses.

// src/mock/handlers/posts.js

import { http, HttpResponse } from "msw";

export const postHandlers = [

 // Handler for GET /todos request
  http.get("https://jsonplaceholder.typicode.com/todos", () => {
    return HttpResponse.json([
      { id: 1, title: "totam quia non" },
      { id: 2, title: "sunt cum tempora" },
    ]);
  }),
];

Salin selepas log masuk

Here, we're defining that when MSW intercepts a GET request to https://jsonplaceholder.typicode.com/todos, it should respond with a 200 status code and the provided JSON data.

Step 3: Hook Handlers to the Browser Worker
Update the browser.js file to include the defined handlers.

import { setupWorker } from "msw/browser";

import { postHandlers } from "./handlers/posts";

export const worker = setupWorker(...postHandlers);
Salin selepas log masuk

Step 4: Hook Handlers to the Node Server
Ensure the handlers are also used in the Node.js environment by updating the server.js file.

import { setupServer } from "msw/node";

import { postHandlers } from "./handlers/posts";

export const server = setupServer(...postHandlers);

Salin selepas log masuk

With these configurations in place, your MSW setup is complete and ready for both browser and Node.js environments. Congratulations on completing the setup! ?

Using MSW in our Tests
To use MSW in your tests, you need to set up your test environment to utilize the mock server for intercepting API calls. Here’s a guide to setting up and writing tests using MSW with your Todos component.

  1. Create the Test File
    Create a new file named Todos.MSW.test.js next to your
    Todos.jscomponent. This file will contain your tests that
    utilize MSW for mocking API responses.

  2. Set Up Test Environment
    In your Todos.MSW.test.js file, import the necessary modules and
    set up the environment for using MSW with your tests. Below is an
    example setup:

import { render, screen, waitFor, within } from "@testing-library/react";
import { http, delay, HttpResponse } from "msw";

import { Todos } from "./Todos";
import { reactQueryWrapper } from "utils/reactQueryWrapper";
import { server } from "mocks/server";

const { wrapper, queryCache } = reactQueryWrapper();

afterEach(() => {
  queryCache.clear();
});

afterEach(() => {
  jest.clearAllMocks();
});

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Salin selepas log masuk

First Test Scenario: Renders loading state
We want to verify that our component correctly displays the loading state while the request is in progress.

test("Renders loading state", () => {
  server.use(
    http.get("https://jsonplaceholder.typicode.com/todos", async () => {
      await delay(1000);
      return HttpResponse.json([]);
    })
  );

  render(<Todos />, { wrapper });
  const loadingText = screen.getByText("loading todo list");
  expect(loadingText).toBeInTheDocument();
});
Salin selepas log masuk

Second Test Scenario: Renders error state when request fails or there is network error
We want to verify that the component correctly renders an error state when the API request fails or encounters a network error.

test("Renders error state when request fails or there is network error", async () => {
  server.use(
    http.get("https://jsonplaceholder.typicode.com/todos", async () => {
      return HttpResponse.json([], {
        status: 500,
      });
    })
  );

  render(<Todos />, { wrapper });
  await screen.findByText("an error occurred fetching todo list");
  expect(
    screen.getByText("an error occurred fetching todo list")
  ).toBeInTheDocument();
});

Salin selepas log masuk

Third Test Scenario: Renders list of todos
We want to verify that our component correctly renders the list of todos when the request is successful.

test("Renders list of todos", async () => {

  render(<Todos />, { wrapper });

  const loadingText = screen.queryByText("loading todo list");
  await waitFor(() => expect(loadingText).not.toBeInTheDocument());
  const list = screen.getByRole("list");
  expect(list).toBeInTheDocument();
  expect(within(list).getAllByRole("listitem")).toHaveLength(2);
});
Salin selepas log masuk

Fourth Test Scenario: Renders list of todos
We want to verify that your component correctly renders a feedback message when the API request returns an empty list of todos.

test("Renders feedback message when user has an empty list of todos", async () => {
   server.use(
    http.get("https://jsonplaceholder.typicode.com/todos", () => {
      return HttpResponse.json([]);
    })
  );
  render(<Todos />, { wrapper });

  await waitFor(() =>
    expect(screen.queryByText("loading todo list")).not.toBeInTheDocument()
  );
  expect(
    screen.getByText("You do not have todos created yet")
  ).toBeInTheDocument();
});
Salin selepas log masuk

Final Thoughts
Mocking API calls is crucial for effective testing, allowing you to simulate different scenarios without relying on real backend services. While traditional Jest mocking can be effective, MSW offers a more sophisticated solution with better support for various environments and more realistic request handling.

Here are a few tips to keep in mind:

  • Choose the Right Tool: Use MSW for a more comprehensive
    solution that integrates seamlessly with your React application,
    especially when dealing with complex request handling.

  • Organize Your Handlers: Keep your API handlers well-organized
    and modular to make them easier to maintain and extend.

  • Clean Up After Tests: Ensure that your tests clean up properly
    by resetting handlers and clearing mocks to avoid interference
    between tests.

  • Verify Setup: Always check your setup by inspecting the network
    requests and responses to ensure that everything is working as
    expected.
    By incorporating MSW into your testing strategy, you'll achieve more reliable and maintainable tests, leading to a smoother development experience and higher quality software.

Happy testing! ?

Atas ialah kandungan terperinci Permintaan Rangkaian Mengejek Dipermudahkan: Mengintegrasikan Jest dan MSW. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan