Jest 동작 과정 밑바닥부터 간단 정리

2025. 5. 11. 16:42리액트

728x90

Jest + React Testing Library가 여러분의 ArticleList.test.tsx를 실제로 “돌려” 보기까지, 그리고 개별 test(...) 블록을 실행해 결과를 리포팅하기까지의 상세한 단계를 정리합니다.


1. CLI로 테스트 실행

 
# 프로젝트 루트에서
npx jest
# 모든 테스트 실행
npx jest src/05/04/ArticleList.test.tsx
# 특정 파일만 실행
  • Node 프로세스가 생성되고
  • jest.config.js(또는 package.json의 설정)를 읽어서
    • 어떤 파일을 테스트로 볼지(testMatch)
    • 어떤 “환경”에서 돌릴지(testEnvironment, 보통 "jsdom")
    • 어떤 변환(transform)을 거칠지(ts-jest, babel-jest 등)
    • 스냅샷 위치(snapshotResolver) 등을 로딩

2. 테스트 파일 수집 & 분할

  • 설정에 매칭되는 *.test.tsx 파일을 워커(worker) 프로세스에 분배
  • 워커 한 개가 ArticleList.test.tsx만 전담하는 경우가 많음
  • 워커는 Node 환경이지만, jest-environment-jsdom을 통해 jsdom 기반의 가상 브라우저 전역객체(window, document)를 갖는다

3. 코드 트랜스폼 (ts-jest)

  1. import ArticleList from "./ArticleList"
  2. TypeScript / TSX 문법을 그대로 Node가 이해할 수 없으니,
  3. ts-jest가 런타임에 해당 모듈을
    • TypeScript 컴파일러(api)로 트랜스파일 → JavaScript
    • JSX → React.createElement 호출로 변환
  4. (이 변환은 메모리상에서만 일어나며, 디스크에 .js 파일을 생성하지 않습니다)

4. 테스트 환경 세팅 (jsdom)

  • 각 워커는 jsdom 인스턴스를 띄워
    • global.window, global.document, global.navigator 등을 제공
    • 브라우저 API(querySelector, createElement 등) 사용 가능
  • beforeEach 단계에서 jsdom의 document.body.innerHTML = "" 로 DOM 초기화

5. 테스트 코드 평가 (Module Load)

테스트 파일 최상단의 import 구문이 실행되어…

import { render, screen, within } from "@testing-library/react"; 
import { ArticleList } from "./ArticleList"; 
import { items } from "./fixture";
 
  • React Testing Library의 헬퍼 함수들
  • 실제 <ArticleList> 컴포넌트 구현
  • fixture.ts 에 정의된 테스트용 데이터
    를 워커가 로드해 메모리에 올립니다.

6. 테스트 함수 실행

각 test(...) 블록은 아래와 같은 순서로 실행됩니다.

test("제목을 표시한다", () => {
  // 1) render: ReactDOM.createRoot(container).render(...)
  render(<ArticleList items={items} />);
  
  // 2) DOM 쿼리: screen.getByRole(...)
  const heading = screen.getByRole("heading", { name: "기사 목록" });
  
  // 3) Assertion: toBeInTheDocument()
  expect(heading).toBeInTheDocument();
});
  1. render()
    • 가상의 <div data-testid="root"> 같은 컨테이너를 만들고
    • React 18 기준 createRoot → root.render()
    • 여러분의 컴포넌트를 jsdom(document.body)에 “마운트”
  2. screen/within 쿼리
    • 내부적으로 document.body.querySelectorAll 또는
      aria-query 라이브러리를 사용해
    • 역할(role), 텍스트, 테스트 iD 등으로 노드를 찾아 반환
  3. expect + Matcher
    • expect(node).toBeInTheDocument() 같은 matcher가
    • 실제로 node !== null 과 같은 조건을 검사
    • 조건 불일치 시 에러를 던져 해당 테스트만 FAIL
  4. cleanup (자동)
    • React Testing Library는 각 테스트 후 unmount() 와
      document.body.innerHTML = "" 를 호출해
    • 이전 테스트 렌더링 흔적을 제거

7. 스냅샷 비교

test("Snapshot…", () => {
  const { container } = render(<ArticleList items={items} />);
  expect(container).toMatchSnapshot();
});
  • container 안의 DOM 트리를 문자열로 직렬화
  • __snapshots__/ArticleList.test.tsx.snap 파일과 비교
  • 다르면 FAIL → 콘솔에 diff 표시
  • 의도된 변경이면 jest -u 로 스냅샷 갱신

8. 리포팅 & 종료

  • 워커 프로세스가 PASS/FAIL 결과를 마스터 프로세스에 전달
  • 콘솔에 각 테스트의 성공·실패, 실행 시간, 전체 요약 출력
  • (watch 모드라면 파일 변경을 감시하면서 반복)
  • 마지막에 Node 프로세스가 종료

요약

  1. Node + Jest CLI 가 설정 읽고 워커 띄움
  2. ts-jest 가 TSX → JS로 변환
  3. jsdom 가상 브라우저 환경 생성
  4. render() 로 React 컴포넌트 마운트
  5. screen/within 으로 DOM 검증
  6. expect 가 어설션 수행
  7. cleanup → 다음 테스트로
  8. 스냅샷 비교(해당 테스트에 있을 때)
  9. 최종 PASS/FAIL 보고

이 모든 과정이 실제 브라우저가 아니라 jsdom 위에서, Node 프로세스 내부에서 일어나며, 여러분이 터미널에 입력한 npx jest 하나로 자동으로 관리됩니다.

 


 

- 추가 설명

 

  • render()
    • jsdom 환경의 document.body 안에 실제 DOM 트리를 만듭니다.
  • screen → document.body
    • 전역 쿼리 함수(getByRole, getByText 등)를 screen 으로 묶어 제공합니다.
  • getByRole("list")
    • document.body.querySelectorAll('[role="list"], ul') 같은 내부 로직으로 <ul>을 찾고 반환
  • within(list)
    • list 요소를 “새로운 root”로 삼아 다시 쿼리 유틸리티 집합을 생성
  • within(list).getAllByRole("listitem")
    • list.querySelectorAll('[role="listitem"], li') 같은 내부 로직으로 <li>만 조회
  • 어설션 (expect(…).toHaveLength(3))
    • 반환된 배열 길이를 검사, 부족하거나 많으면 테스트 실패
  • screen:
    • 문서 전체에서 요소를 찾을 땐 기본으로 사용
    • 편리하고 가독성도 좋습니다.
  • within:
    • 문서에 동일한 요소(또는 role)가 여러 개 있을 때
    • 특정 컨테이너 내부만 검사하고 싶을 때

 

728x90