Loading...
본문 바로가기
👥
총 방문자
📖
0개 이상
총 포스팅
🧑
오늘 방문자 수
📅
0일째
블로그 운영

여러분의 방문을 환영해요! 🎉

다양한 개발 지식을 쉽고 재미있게 알려드리는 블로그가 될게요. 함께 성장해요! 😊

코딩 정보/React

[vite][vitest] 프로젝트 중 테스트 코드를 작성하며..

by 꽁이꽁설꽁돌 2025. 2. 26.
728x90
반응형
     

목차

     

    나는 프로젝트를 하면서 테스트 코드를 작성하는 미션을 받았고 msw 세팅을 한 상태에서 

    테스트 코드를 작성할 프로그램을 고르기 시작했다.

     

    jest와 vitest중 멀 쓰지?

    처음에 제안한 것이 바로 jest! 이것은 근데 우리가 기존 세팅을 vite로 해서 세팅하는데

    배보다 배꼽이 더 크다는 생각이 하면 할 수록 들어 검색을 해본 결과..

    https://bumang.blog/99

     

    vite쓸꺼면 Jest는 쓰지말기

    요새 유행하는 번들러 환경 Vite에, 가장 유명한 테스팅 라이브러리 Jest를 엮어쓰려고 했으나 Jest는 웹팩 기반 라이브러리라 Vite환경에서 쓰려면 매우 복잡한 설정들을 거쳐야 한다. 아래 글에서

    bumang.blog

     

    결론은 vite 에서는 import.meta.env.VITE_XXX 와 같이 환경 변수를 사용하는데
    WEBPACK 환경에서 위와 같은 환경 변수를 사용하기 위해서는 별도의 babel 관련 설정이 추가되어야 한다는 것이었다.

     

     

    그래서 얼른 vitest로 바꾸어 진행을 했다.

    그렇게 순조롭게 진행되는 줄 알았으나 msw 모킹을 하는 부분에서 문제가 생겼다.

     

    다음과 같은 오류가 떴다...

    src/hooks/queries/test/clubs.test.tsx [ src/hooks/queries/test/clubs.test.tsx ]
    Error: No known conditions for "./browser" specifier in "msw" package
      Plugin: vite:import-analysis
      File: C:/Users/sins0/Desktop/Projects/mokkoji-fe/src/mocks/browsers.ts:1:28
      1  |  import { setupWorker } from "msw/browser";
         |                               ^
      2  |  import { handlers } from "./handlers";
      3  |  export const worker = setupWorker(...handlers);
     ❯ e node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:15470:25
     ❯ n node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:15470:650
     ❯ o node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:15470:1293
     ❯ resolveExportsOrImports node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:16673:18
     ❯ resolveDeepImport node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:16686:25
     ❯ tryNodeResolve node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:16516:18
     ❯ ResolveIdContext.resolveId node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:16289:19
     ❯ EnvironmentPluginContainer.resolveId node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:47553:17
     ❯ TransformPluginContext.resolve node_modules/vitest/node_modules/vite/dist/node/chunks/dep-ByPKlqZ5.js:47756:15

     

    vitest와 msw는 따로 사용

    결론은 다음과 같았다.
     
    브라우저환경에서는 service worker api가 있는데 node환경에서 실행되는 vitest는 service worker api 가 없기 때문에 msw/node를 써야 한다는 것이었다.
     
     
     
    서비스 워커는 웹 응용 프로그램, 브라우저, 그리고 네트워크 사이의 프록시 서버 역할을 하는데

    그 중에서도 특히 우리가 자세히 볼 부분은 오프라인 경험을 생성하고 네트워크 요청을 가로채는 

    역할을 할 수 있다는 점이다.

     

     

     

    그래서 우리는 모킹한 데이터 외에 임시 데이터를 또 만들어 주어 통합테스트와 유닛테스트를

    하기로 결정하였다. 

    또한 테스트 부분은 로직이 그래도 복잡하다고 볼 수 있는 api를 다루는 부분을 중심으로 진행했다.

     

    clubList.test.tsx

    import { describe, it, expect, beforeAll, afterAll } from "vitest";
    import { render, screen, waitFor } from "@testing-library/react";
    import { setupServer } from "msw/node";
    import { MemoryRouter } from "react-router-dom";
    import { http, HttpResponse } from "msw";
    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    import ClubList from "./ClubList";
    
    const server = setupServer(
      http.get("/clubs", () => {
        // 클라이언트에서 `/clubs` 경로로 요청하면, 아래의 JSON 데이터를 반환함
        return HttpResponse.json({
          data: {
            clubs: [
              {
                id: 1,
                name: "그리디",
                category: "학술/교양",
                affiliation: "중앙동아리",
                description: "간단 소개",
                recruitStartDate: "2025-10-12",
                recruitEndDate: "2025-10-13",
                imageUrl: "https://example.com/images/greedy.jpg",
                favorite: true,
              },
            ],
            pagination: {
              page: 1,
              size: 9,
              totalPages: 3,
              totalElements: 27,
            },
          },
        });
      })
    );
    
    beforeAll(() => server.listen());
    afterAll(() => server.close());
    
    const queryClient = new QueryClient();
    
    describe("ClubList", () => {
      it("api로부터 전달받은 데이터를 ClubBox 컴포넌트를 통해 화면에 랜더링해야한다", async () => {
        // ClubList 컴포넌트 렌더링
        render(
          <MemoryRouter>
            <QueryClientProvider client={queryClient}>
              <ClubList />
            </QueryClientProvider>
          </MemoryRouter>
        );
    
        // ClubBox 의 내용 확인
        await waitFor(() => screen.queryByText("그리디"));
        expect(screen.queryByText("그리디"));
        expect(screen.queryByText("간단 소개"));
        expect(screen.queryByText("학술/교양"));
        expect(screen.queryByText("중앙동아리"));
        // 동아리 로고 이미지
        const image = screen.queryByAltText("그리디");
        expect(image);
        // 즐겨찾기 버튼
        expect(screen.getByRole("button", { name: /favoriteButton/i }));
      });
    
      it("api 호출 실패", async () => {
        server.use(
          http.get("/clubs", () => {
            return new HttpResponse(null, { status: 500 });
          })
        );
      });
    });

     

    테스트가 성공적으로 진행된 것을 볼 수 있다.

     

     

     

     

    반응형