React/jest

[React Testing Library] msw를 활용한 mock API 테스트

Judith Hopps 2023. 8. 4. 21:07
반응형

3. MSW를 활용한 mock API 테스트

본 라이브러리를 학습하기 위해 코딩앙마님의 강의를 수강하였습니다.

 

3.1 Mock Serveice Worker 다운 및 세팅

 

Node - Getting Started

Mock Service Worker Docs

mswjs.io

 

Install - Getting Started

Mock Service Worker Docs

mswjs.io

위 사이트를 방문해서 install 및 integrate를 해준다.

src/mock 안에 handlers.js + server.js를 생성하면 된다.

 

그 후 src/setupTests(생성X).js의 내용을 다음과 같이 수정한다.

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
import '@testing-library/jest-dom';

// src/setupTests.js
import { server } from './mock/server.js';
// Establish API mocking before all tests.
beforeAll(() => server.listen());

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers());

// Clean up after the tests are finished.
afterAll(() => server.close());

 

3.2 api 이용해서 테스트

실전이 아닌 연습용으로 무료 api를 사용했다.

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.

jsonplaceholder.typicode.com

 

src/mock/handlers.js를 다음과 같이 수정한다.

 

import { rest } from 'msw';

export const handlers = [
  // Match a GET request to a third-party server.
  rest.get('https://jsonplaceholder.typicode.com/todos', (req, res, ctx) => {
    return res(
      ctx.status(200), //500 : 서버 에러
      ctx.json([
        {
          id: 1,
          title: '청소',
          completed: true,
        },
        {
          id: 2,
          title: '설거지',
          completed: false,
        },
        {
          id: 3,
          title: '빨래',
          completed: true,
        },
      ])
    );
  }),
];

 

src/component/TodoList.js를 다음과 같이 작성한다.

import { useEffect, useState } from 'react';

export default function TodoList() {
  const [todoList, setTodoList] = useState([]);
  const [errorMsg, setErrorMsg] = useState('');

  useEffect(() => {
      .then((response) => response.json())
      .then((json) => setTodoList(json))
      .catch(() => {
        setErrorMsg('에러 발생... ');
      });
  }, []);

  return (
    <>
      <h1>TodoList</h1>

      {errorMsg ? (
        <h5>{errorMsg}</h5>
      ) : (
        <ul>
          {todoList.map((todo) => (
            <li
              key={todo.id}
              style={{
                textDecoration: todo.completed ? 'line-through' : undefined,
              }}
            >
              {todo.title}
            </li>
          ))}
        </ul>
      )}
    </>
  );
}

 

src/component/TodoList.test.js를 다음과 같이 작성한다.

 

import { render, screen } from '@testing-library/react';
import TodoList from './TodoList';
import { rest } from 'msw';
import { server } from '../mock/server';

describe('TodoList', () => {
  test('TodoList 라는 제목이 있다.', () => {
    render(<TodoList />);
    const titleElement = screen.getByRole('heading', {
      name: 'TodoList',
    });
    // const titleElement = screen.getByText("TodoList")
    expect(titleElement).toBeInTheDocument();
  });
 
  test('리스트 3개가 잘 나온다.', async () => {
    render(<TodoList />);
    const listElement = await screen.findAllByRole('listitem');
    expect(listElement).toHaveLength(3);
  });
});

프로미스로 반환되므로, await screen.findAllByRole('listitem') 을 사용해야한다. 

 

 

3.3 mock 서버 이용하여 에러 생성

방법 1. 모든 api 서버 오류 처리

src/mock/handlers.js를 다음과 같이 수정한다.

import { rest } from 'msw';

export const handlers = [
  // Match a GET request to a third-party server.
  rest.get('https://jsonplaceholder.typicode.com/todos', (req, res, ctx) => {
    return res(
      ctx.status(500),
 
    );
  }),
];

하지만 , 이렇게 수정하면 모든 코드가 에러 처리되므로 테스트하기에 적절하지 않을 수 있다. 

 

방법 2. test 안에서 서버 오류 처리

import { render, screen } from '@testing-library/react';
import TodoList from './TodoList';
import { rest } from 'msw';
import { server } from '../mock/server';
 
test('에러가 났을 때 에러 메세지를 보여준다.', async () => {
    server.use(
      rest.get(
        (req, res, ctx) => {
          return res(
            ctx.status(500) //500 : 서버 에러
 
          );
        }
      )
    );

    render(<TodoList />);
    const errorElement = await screen.findByText('에러 발생...');
    expect(errorElement).toBeInTheDocument();
  });

각 test 내부에서만 server 오류를 일으켜 각각 테스트에 적합하다.

src/setupTests.js의 afterEach(() => server.resetHandlers()); 때문이다.

반응형