본문으로 바로가기
제품데스크톱 도구TASTECAD도면 확인TASTEFILES파일 관리TASTEFTP파일 전송TASTESSH원격 작업공간TASTEZIP압축과 해제개발 도구TASTECODERust 통합 개발 환경TASTESTUDIO통합 개발·테스트 환경TASTEETL데이터 통합(ETL)서버TASTEREMOTE원격 데스크톱 서버TASTEGEO공간정보 서버TASTEMAIL메일 작업공간시작하기다운로드문서구매모든 제품
마켓플레이스
소식
개발소식오늘의 개발 소식개발 문서프로그래밍 언어RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron알고리즘알고리즘 기초알고리즘 핵심알고리즘 심화실무 알고리즘
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스커뮤니티 안내
협업기술 전수홈페이지 구축데스크톱 앱 구축릴리스·결제 파이프라인판매 파트너문의
서비스원격 데스크톱설치 패키지 커스텀
TASTEDEV
제품

데스크톱 도구

TASTECAD복잡한 도면을 가볍게 열다TASTEFILES필요한 파일만, 가장 빠르게TASTEFTP파일이 오가는 가장 단정한 길TASTESSH서버와 나 사이, 더 단단한 연결TASTEZIP더 빠르게 묶고, 더 안전하게 풀다

개발 도구

TASTECODERust 앱을 편집 · 빌드 · 디버깅 · 테스트까지 한 창에서TASTESTUDIO편집부터 원격 테스트와 승인 기반 AI 수정까지TASTEETL값을 보며 데이터를 옮깁니다

서버

TASTEREMOTE우리 회사 서버로 운영하는 원격 데스크톱TASTEGEOGeoServer 호환 공간정보 서버를 Rust로 다시 세웁니다TASTEMAIL메일의 주도권을 다시 내 손에

시작하기

다운로드모든 제품 최신 판문서제품 사용법구매구독 · 영구 라이선스모든 제품모든 제품 한눈에
모든 제품
마켓플레이스소식
개발

소식

오늘의 개발 소식언어 · 프레임워크 · GitHub · AI 공식 발표개발 문서언어 · 프레임워크 · 알고리즘 안내서

프로그래밍 언어

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

프레임워크

프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular
서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron

알고리즘

알고리즘 기초복잡도 분석 · 정렬 · 탐색 · 기본 자료구조 · 트리와 힙알고리즘 핵심그래프 탐색 · 최단 경로와 최소 신장 트리 · 동적 계획법 · 탐욕 알고리즘 · 분할 정복 · 백트래킹알고리즘 심화문자열 알고리즘 · 수학과 정수론 · 비트 연산 · 구간 트리 · 유니온 파인드실무 알고리즘코딩 면접 풀이 전략 · LRU 캐시 · 레이트 리미터 · 일관된 해시
개발 문서 전체 보기
커뮤니티
프로젝트빌더와 작업 발견개발 로그결정과 시행착오프롬프트재사용 가능한 지시AI 도구 이슈Claude · Codex · Gemini 문제와 우회법쇼케이스완성된 결과커뮤니티 안내공개하고 함께 만드는 방식
협업
기술 전수Rust·egui 네이티브 앱 만들기홈페이지 구축10개 언어, 계정, 문서·다운로드데스크톱 앱 구축Rust·egui, WebView 없이릴리스·결제 파이프라인서명 · MSI·deb·rpm·AppImage · 해시판매 파트너소개하고 결제액의 30% 받기문의구축 · 제휴 · 투자 문의
서비스
원격 데스크톱브라우저로 내 컴퓨터에 접속설치 패키지 커스텀필요한 기능만, 설정은 미리
구매
KO
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
로그인
로그인
TASTEDEV

작은 도구부터, 더 좋은 개발까지.

support@tastedev.netTASTEDEV 후원하기
제품제품군구매문서다운로드마켓플레이스고객 지원
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스
정책개인정보처리방침이용약관구독 약관환불 정책커뮤니티 운영 정책
계정로그인가입하기
방문자
오늘
012345678901234567890123456789012345678901234567890123456789
어제
012345678901234567890123456789012345678901234567890123456789
누적 조회
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
상호
지엑스소프트
대표자
최영구
사업자등록번호
853-44-00368
주소
인천광역시 미추홀구 경인로 351 9층 V24
전화
+82-10-4404-1523
이메일
whitecalvin@tastedev.net
개인정보 보호책임자
최영구

© 2026 TASTEDEV제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

React 문서
React
React 시작하기프로젝트 구조핵심 개념데이터와 상태 관리테스트빌드와 배포
토론

React 안내서 · 5/6

테스트

React 앱의 테스트는 보통 두 층으로 나눕니다. 컴포넌트와 훅은 Vitest와 React Testing Library로 빠르게 검사하고, 실제 브라우저에서 사용자 흐름 전체는 Playwright로 확인합니다.

Vitest와 React Testing Library 설치

Vitest는 Vite 설정을 그대로 재사용하는 테스트 도구라 별도의 변환 설정이 거의 필요 없습니다. 브라우저 DOM을 흉내 내는 jsdom과 Testing Library 패키지를 함께 설치합니다.

npm install -D vitest jsdom @testing-library/react @testing-library/dom @testing-library/user-event @testing-library/jest-dom

vite.config.ts에 test 항목을 추가합니다. 맨 위의 참조 주석은 TypeScript가 test 항목의 타입을 알게 해 줍니다.

/// <reference types="vitest/config" />
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    environment: "jsdom",
    globals: true,
    setupFiles: "./src/test/setup.ts",
    include: ["src/**/*.test.{ts,tsx}"],
  },
});

globals: true를 켜면 Testing Library가 각 테스트가 끝난 뒤 그린 화면을 자동으로 정리합니다. include를 정해 두면 뒤에서 만들 Playwright 테스트를 Vitest가 잘못 실행하지 않습니다. 설정 파일 src/test/setup.ts에는 toBeInTheDocument() 같은 DOM 전용 검사 함수를 등록합니다.

import "@testing-library/jest-dom/vitest";

마지막으로 package.json의 scripts에 "test": "vitest"를 추가합니다. npm test는 감시 모드로 실행되어 파일을 저장할 때마다 관련 테스트를 다시 돌리고, CI에서는 npx vitest run으로 한 번만 실행합니다.

컴포넌트 테스트

Testing Library는 구현 세부가 아니라 사용자가 보는 화면을 기준으로 테스트하도록 이끕니다. 요소는 가능하면 getByRole, getByLabelText처럼 접근성 정보로 찾고, 클릭이나 입력은 실제 사용자 동작에 가까운 user-event로 흉내 냅니다.

// src/Counter.tsx
import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>클릭 {count}회</button>;
}
// src/Counter.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { Counter } from "./Counter";

describe("Counter", () => {
  it("클릭하면 숫자가 올라간다", async () => {
    const user = userEvent.setup();
    render(<Counter />);

    const button = screen.getByRole("button", { name: "클릭 0회" });
    await user.click(button);

    expect(button).toHaveTextContent("클릭 1회");
  });
});

비동기 화면과 모의 객체

데이터를 불러오는 컴포넌트는 네트워크 대신 모의 응답을 돌려주게 합니다. vi.spyOn으로 전역 fetch를 바꾸고, 나중에 나타나는 요소는 기다렸다가 찾는 findBy... 쿼리로 확인합니다. 앞 장의 UserName 컴포넌트를 예로 듭니다.

import { render, screen } from "@testing-library/react";
import { afterEach, expect, it, vi } from "vitest";
import { UserName } from "./UserName";

afterEach(() => {
  vi.restoreAllMocks();
});

it("사용자 이름을 불러와 보여 준다", async () => {
  vi.spyOn(globalThis, "fetch").mockResolvedValue(
    new Response(JSON.stringify({ id: 1, name: "하늘" })),
  );

  render(<UserName userId={1} />);

  expect(screen.getByText("불러오는 중…")).toBeInTheDocument();
  expect(await screen.findByText("하늘")).toBeInTheDocument();
});

API 호출이 많은 앱이라면 요청을 네트워크 수준에서 가로채는 Mock Service Worker(MSW)를 쓰면 테스트와 개발 서버에서 같은 모의 API를 공유할 수 있습니다.

사용자 정의 훅 테스트

화면 없이 훅만 검사하려면 renderHook을 씁니다. 상태를 바꾸는 호출은 act로 감싸 React가 업데이트를 모두 반영한 뒤 결과를 확인합니다.

import { act, renderHook } from "@testing-library/react";
import { expect, it } from "vitest";
import { useTodos } from "./useTodos";

it("할 일을 추가한다", () => {
  const { result } = renderHook(() => useTodos());

  act(() => result.current.add("우유 사기"));

  expect(result.current.todos).toHaveLength(1);
  expect(result.current.todos[0].text).toBe("우유 사기");
});

Playwright로 E2E 테스트

Playwright는 Chromium, Firefox, WebKit을 실제로 띄워 사용자처럼 앱을 조작합니다. 초기화 명령이 설정 파일, 예제 테스트, 브라우저 설치를 한 번에 처리합니다.

npm init playwright@latest

playwright.config.ts에 webServer를 지정하면 테스트 전에 개발 서버를 자동으로 띄웁니다.

import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./e2e",
  use: { baseURL: "http://localhost:5173" },
  webServer: {
    command: "npm run dev",
    url: "http://localhost:5173",
    reuseExistingServer: !process.env.CI,
  },
  projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
// e2e/counter.spec.ts (첫 화면에 Counter가 있다고 가정합니다)
import { expect, test } from "@playwright/test";

test("카운터 버튼이 동작한다", async ({ page }) => {
  await page.goto("/");
  await page.getByRole("button", { name: /클릭/ }).click();
  await expect(page.getByRole("button", { name: "클릭 1회" })).toBeVisible();
});

npx playwright test로 실행하고, --ui를 붙이면 단계별로 화면을 보며 디버깅할 수 있습니다. expect는 조건이 맞을 때까지 자동으로 기다리므로 임의의 대기 시간을 넣을 필요가 없습니다.

정리

  • 컴포넌트 · 훅 테스트는 Vitest + React Testing Library, 브라우저 흐름은 Playwright로 나눕니다.
  • 요소는 역할과 레이블로 찾고, 동작은 user-event로 흉내 냅니다.
  • 비동기 결과는 findBy...로 기다리고, 네트워크는 vi.spyOn이나 MSW로 모의합니다.
  • Playwright의 webServer 설정으로 개발 서버를 자동으로 띄워 E2E 테스트를 실행합니다.
이 장에 대해 질문이 있나요?
이전 장데이터와 상태 관리다음 장빌드와 배포

댓글 0개

인기 댓글순최신순

로그인 · 로그인하면 댓글을 남길 수 있습니다.