[React] 테스트 코드 공부 중 발생한 에러들

한호수 (The Lake)·2023년 7월 22일
1
post-thumbnail
post-custom-banner

개요

전에 CRA에서 jest@testing-library를 통해서 간단하게 리액트 테스트 코드를 작성해본적이 있었다. 처음 테스트 코드를 작성할땐 테스트 코드를 작성하는 시간보다 셋업하면서 만난 버그들을 고치느라 시간이 더 소요되었던 경험이 있었다. 당시에는 해결하는데 급급해서 기록을 못하고 넘어갔지만 이번에 Vite를 사용하면서 Vitest를 사용해볼 기회가 생겨서 기록을 남긴다.

1. ERROR: Expected ">" but found "router"

  • test 파일내부에서 jsx 문법을 사용할때 확장자가 tsx(or jsx)가 아니라 ts(or js)로 해서 발생한 에러 hobby.test.ts -> hobby.test.tsx

2. Invariant Violation: [MSW] Failed to execute setupWorker in a non-browser environment. Consider using setupServer for Node.js environment instead.

  • Vite에서 지원하는 환경 변수 import.meta.env.DEV는 테스트 환경에서 생각과 다르게 작동하여서 발생한 문제
  • Vite 공식문서에 의하면 import.meta.env.DEV는 실행환경에 따라 boolean 값을 리턴한다고 하지만 test 환경에서는 숫자 1을 리턴하여서 msw service worker 가 동작하여서 에러가 발생하였음
  • 환경변수import.meta.env.MODE 또는 process.env.NODE_ENV를 사용하여 검증하는 방법으로 해결하였음
// 기존 코드
// main.tsx
if (import.meta.env.DEV) {
  (async () => {
    const { worker } = await import('./mocks/browser');
    worker.start();
  })();
}
// 수정 후
// main.tsx
if (import.meta.env.MODE === "development") {
  (async () => {
    const { worker } = await import('./mocks/browser');
    worker.start();
  })();
  
//or

if (process.env.NODE_ENV === "development") {
  (async () => {
    const { worker } = await import('./mocks/browser');
    worker.start();
  })();
}

3. Error: createRoot(...): Target container is not a DOM element.

  • Test 환경에서 document.getElementById('root') 값이 비어있기 때문으로 추정. root를 찾을 수 없을때 document.createElement('div')를 추가해서 해결
// main.tsx
ReactDOM.createRoot(
  (document.getElementById('root') as HTMLElement) ||
    document.createElement('div') //  || 연산자 사용해서 해결
  
)

4. Failed to parse URL from "/api경로"

  • 테스트 코드는 node.js 환경에서 동작하기 때문에 node의 fetch가 작동하게됨
  • node.js fetch를 사용했을 때 URL을 절대경로를 주지 않았을때 발생(node 18버전에 추가된 fetch는 절대경로를 인자로 받음)
  • 해결방법은 절대경로를 주는 방법도 있지만 axios 라이브러리로 마이그레이션하여서 해결하였음

node.js 버전 18에 fetch가 추가되었기 때문에 노드 버전이 낮다면 fetch가 없어서 다른 에러가 발생할 수 있음

5. Error: Uncaught [ReferenceError: IntersectionObserver is not defined]

  • test 환경은 node에서 동작하는데 실제 코드에서 사용된 IntersectionObserver은 브라우저에서만 존재하는 객체라서 문제가 발생하는것으로 추정된다. 해결법은 테스트 라이브러리의 mock function 기능을 사용하여 해결하였다.
// src/utils/test-utils.tsx
// api를 vitest의 vi 객체를 활용해 가짜 함수를 만들어 사용한다.

import { vi } from 'vitest';

const intersectionObserverMock = () => ({
  observe: () => null,
  disconnect: () => null,
});
window.IntersectionObserver = vi
  .fn()
  .mockImplementation(intersectionObserverMock);

맺음말

지금 보면 대부분 간단하게 해결할 수 있는 에러들이었지만 이틀은 고생했던것 같다. 아마도 Vitest를 사용하는 사람들이 적어서 참고할 자료가 적고, 너무 간단한것들이라 포스팅을 안해서 그런것 같다. 나 같은 초보가 고통을 받지 않길 바라는 마음에 포스팅한다.

profile
항상 근거를 찾는 사람이 되자
post-custom-banner

2개의 댓글

comment-user-thumbnail
2023년 7월 22일

글 잘 봤습니다.

1개의 답글