← 홈

⌘K
🤖
Claude Code AI 도구
🤗
Hugging Face AI 도구
🦜
LangChain AI 도구
🧠
Keras AI 도구
🦙
Ollama AI 도구
🐍
Python 프로그래밍 언어
🟨
JavaScript 프로그래밍 언어
🔷
TypeScript 프로그래밍 언어
⚛️
React 프로그래밍 언어
🐹
Go 프로그래밍 언어
🦀
Rust 프로그래밍 언어
📊
MATLAB 프로그래밍 언어
🗄️
SQL 프로그래밍 언어
⚙️
C/C++ 프로그래밍 언어
Java 프로그래밍 언어
🟣
C# 프로그래밍 언어
🍎
Swift 프로그래밍 언어
🟠
Kotlin 프로그래밍 언어
Next.js 프로그래밍 언어
💚
Vue.js 프로그래밍 언어
🔥
Svelte 프로그래밍 언어
🎨
Tailwind CSS 프로그래밍 언어
💚
Node.js 프로그래밍 언어
🌐
HTML 프로그래밍 언어
🎨
CSS/SCSS 프로그래밍 언어
🐘
PHP 프로그래밍 언어
💎
Ruby 프로그래밍 언어
🔴
Scala 프로그래밍 언어
📊
R 프로그래밍 언어
🎯
Dart 프로그래밍 언어
💧
Elixir 프로그래밍 언어
🌙
Lua 프로그래밍 언어
🐪
Perl 프로그래밍 언어
🅰️
Angular 프로그래밍 언어
🚂
Express.js 프로그래밍 언어
🐱
NestJS 프로그래밍 언어
🛤️
Ruby on Rails 프로그래밍 언어
◼️
GraphQL 프로그래밍 언어
🟪
Haskell 프로그래밍 언어
💚
Nuxt.js 프로그래밍 언어
🔷
SolidJS 프로그래밍 언어
htmx 프로그래밍 언어
💻
VS Code 개발 도구
🧠
PyCharm 개발 도구
📓
Jupyter 개발 도구
🧠
IntelliJ IDEA 개발 도구
💚
Neovim 개발 도구
🔮
Emacs 개발 도구
🔀
Git DevOps & CLI
🐳
Docker DevOps & CLI
☸️
Kubernetes DevOps & CLI
☁️
AWS CLI DevOps & CLI
🔄
GitHub Actions DevOps & CLI
🐧
Linux 명령어 DevOps & CLI
💻
Bash 스크립팅 DevOps & CLI
🌐
Nginx DevOps & CLI
📝
Vim DevOps & CLI
🔨
Makefile DevOps & CLI
🧪
Pytest DevOps & CLI
🪟
Windows DevOps & CLI
📦
패키지 매니저 DevOps & CLI
🍎
macOS DevOps & CLI
🏗️
Terraform DevOps & CLI
🔧
Ansible DevOps & CLI
Helm DevOps & CLI
🔨
Jenkins DevOps & CLI
🔥
Prometheus DevOps & CLI
📊
Grafana DevOps & CLI
💻
Zsh DevOps & CLI
🐟
Fish Shell DevOps & CLI
💙
PowerShell DevOps & CLI
🔄
Argo CD DevOps & CLI
🔀
Traefik DevOps & CLI
☁️
Azure CLI DevOps & CLI
☁️
Google Cloud CLI DevOps & CLI
📟
tmux DevOps & CLI
🔧
jq DevOps & CLI
✂️
sed DevOps & CLI
📊
awk DevOps & CLI
🌊
Apache Airflow DevOps & CLI
🔢
NumPy 데이터베이스 & 데이터
🐼
Pandas 데이터베이스 & 데이터
🔥
PyTorch 데이터베이스 & 데이터
🧠
TensorFlow 데이터베이스 & 데이터
📈
Matplotlib 데이터베이스 & 데이터
🐘
PostgreSQL 데이터베이스 & 데이터
🐬
MySQL 데이터베이스 & 데이터
🍃
MongoDB 데이터베이스 & 데이터
🔴
Redis 데이터베이스 & 데이터
🔍
Elasticsearch 데이터베이스 & 데이터
🤖
Scikit-learn 데이터베이스 & 데이터
👁️
OpenCV 데이터베이스 & 데이터
Apache Spark 데이터베이스 & 데이터
🪶
SQLite 데이터베이스 & 데이터
Supabase 데이터베이스 & 데이터
🔵
Neo4j 데이터베이스 & 데이터
📨
Apache Kafka 데이터베이스 & 데이터
🐰
RabbitMQ 데이터베이스 & 데이터
🔤
Regex 유틸리티
📝
Markdown 유틸리티
📄
LaTeX 유틸리티
🔐
SSH & GPG 유틸리티
🌐
curl & HTTP 유틸리티
📜
reStructuredText 유틸리티
🚀
Postman 유틸리티
🎬
FFmpeg 유틸리티
🖼️
ImageMagick 유틸리티
🔍
ripgrep 유틸리티
🔍
fzf 유틸리티
📗
Microsoft Excel 오피스 애플리케이션
📘
Microsoft Word 오피스 애플리케이션
📙
Microsoft PowerPoint 오피스 애플리케이션
📝
한컴 한글 한컴오피스
📽️
한컴 한쇼 한컴오피스
📊
한컴 한셀 한컴오피스
📄
Google 문서 Google Workspace
📊
Google 스프레드시트 Google Workspace
📽️
Google 프레젠테이션 Google Workspace
🔌
Cadence Virtuoso EDA & 하드웨어
⚙️
Synopsys EDA EDA & 하드웨어
💎
Verilog & VHDL EDA & 하드웨어
LTSpice EDA & 하드웨어
🔧
KiCad EDA & 하드웨어
📝
Notion 생산성 도구
💎
Obsidian 생산성 도구
💬
Slack 생산성 도구
🎮
Discord 생산성 도구
🎨
Figma 디자인 도구
📘
Confluence Atlassian
📋
Jira Atlassian
🃏
Jest 테스팅
Vitest 테스팅
🎭
Playwright 테스팅
🌲
Cypress 테스팅
🌐
Selenium 테스팅
💙
Flutter 모바일 개발
📱
React Native 모바일 개발
🍎
SwiftUI 모바일 개발
📱
Expo 모바일 개발
🐍
Django 웹 프레임워크
FastAPI 웹 프레임워크
🌶️
Flask 웹 프레임워크
🍃
Spring Boot 웹 프레임워크
🍸
Gin 웹 프레임워크
Vite 빌드 도구
📦
Webpack 빌드 도구
esbuild 빌드 도구
🐘
Gradle 빌드 도구
🪶
Maven 빌드 도구
🔧
CMake 빌드 도구
🎮
Unity 게임 개발
🤖
Godot 게임 개발
🔌
Arduino 임베디드 & IoT
🔍
Nmap 보안
🐕
Datadog 모니터링
📖
Swagger/OpenAPI 문서화
검색 결과가 없습니다
EN KO

기초

CLI 명령어

npm install -D vitest Vitest 설치
npx vitest 테스트 실행 (감시 모드)
npx vitest run 테스트 한번 실행
npx vitest --ui UI 열기
npx vitest --coverage 커버리지와 함께 실행
npx vitest --reporter=verbose 상세 출력
npx vitest related src/file.ts 관련 테스트 실행
npx vitest bench 벤치마크 실행

설정

vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
    include: ['**/*.{test,spec}.{js,ts,jsx,tsx}'],
    exclude: ['node_modules', 'dist'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
    },
  },
});
Vite 설정과 함께
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
  },
});

테스트 작성

테스트 구조

기본 테스트
import { describe, it, expect, test } from 'vitest';

describe('Math operations', () => {
  it('adds numbers', () => {
    expect(1 + 1).toBe(2);
  });

  test('multiplies numbers', () => {
    expect(2 * 3).toBe(6);
  });

  it.skip('skipped test', () => {});
  it.only('only this test runs', () => {});
  it.todo('implement later');
});
중첩 describe
describe('User', () => {
  describe('when logged in', () => {
    it('shows dashboard', () => {
      // ...
    });
  });

  describe('when logged out', () => {
    it('shows login page', () => {
      // ...
    });
  });
});
매개변수화된 테스트
import { describe, it, expect } from 'vitest';

describe.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 1, expected: 3 },
])('add($a, $b)', ({ a, b, expected }) => {
  it(`returns ${expected}`, () => {
    expect(a + b).toBe(expected);
  });
});

it.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
  expect(a + b).toBe(expected);
});

어설션

기본 매처
expect(value).toBe(expected);        // strict equality
expect(value).toEqual(expected);     // deep equality
expect(value).toStrictEqual(expected); // strict deep equality

expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();
expect(value).toBeNaN();
숫자 매처
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
expect(0.1 + 0.2).toBeCloseTo(0.3, 5);
문자열 매처
expect(string).toMatch(/pattern/);
expect(string).toContain('substring');
expect(string).toHaveLength(10);
배열/객체 매처
expect(array).toContain(item);
expect(array).toContainEqual({ a: 1 });
expect(array).toHaveLength(3);

expect(object).toHaveProperty('key');
expect(object).toHaveProperty('key', value);
expect(object).toMatchObject({ key: value });
예외 매처
expect(() => fn()).toThrow();
expect(() => fn()).toThrow(Error);
expect(() => fn()).toThrow('error message');
expect(() => fn()).toThrow(/pattern/);

expect(promise).rejects.toThrow();
await expect(asyncFn()).rejects.toThrow('error');

설정 및 정리

설정/정리
import { beforeAll, afterAll, beforeEach, afterEach } from 'vitest';

beforeAll(async () => {
  // Run once before all tests
  await setupDatabase();
});

afterAll(async () => {
  // Run once after all tests
  await cleanupDatabase();
});

beforeEach(() => {
  // Run before each test
  resetState();
});

afterEach(() => {
  // Run after each test
  cleanup();
});
설정 파일
// src/test/setup.ts
import { vi } from 'vitest';
import '@testing-library/jest-dom/vitest';

// Mock global
globalThis.fetch = vi.fn();

// Reset mocks before each test
beforeEach(() => {
  vi.clearAllMocks();
});

// Cleanup after each test
afterEach(() => {
  vi.useRealTimers();
});

모킹

함수

모의 함수
import { vi, expect } from 'vitest';

const fn = vi.fn();
fn('arg1', 'arg2');

expect(fn).toHaveBeenCalled();
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith('arg1', 'arg2');
expect(fn).toHaveBeenLastCalledWith('arg1', 'arg2');
모의 반환값
const fn = vi.fn();

fn.mockReturnValue('default');
fn.mockReturnValueOnce('first');
fn.mockResolvedValue('async result');
fn.mockResolvedValueOnce('first async');
fn.mockRejectedValue(new Error('fail'));

fn.mockImplementation((x) => x * 2);
fn.mockImplementationOnce((x) => x * 3);
메서드 스파이
const obj = {
  method: (x: number) => x * 2,
};

const spy = vi.spyOn(obj, 'method');
spy.mockReturnValue(10);

obj.method(5); // returns 10

expect(spy).toHaveBeenCalledWith(5);

spy.mockRestore(); // restore original

모듈

모듈 모킹
import { vi } from 'vitest';

vi.mock('./utils', () => ({
  fetchData: vi.fn(() => Promise.resolve({ data: 'mocked' })),
  helper: vi.fn(),
}));

// Partial mock
vi.mock('./utils', async (importOriginal) => {
  const actual = await importOriginal();
  return {
    ...actual,
    fetchData: vi.fn(),
  };
});
노드 모듈 모킹
vi.mock('axios', () => ({
  default: {
    get: vi.fn(() => Promise.resolve({ data: {} })),
    post: vi.fn(),
  },
}));

// In test
import axios from 'axios';

it('fetches data', async () => {
  vi.mocked(axios.get).mockResolvedValue({ data: { id: 1 } });
  // ...
});
호이스팅된 모킹
// vi.hoisted ensures mock is defined before imports
const mockFetch = vi.hoisted(() => vi.fn());

vi.mock('./api', () => ({
  fetchData: mockFetch,
}));

import { fetchData } from './api';

it('uses mock', () => {
  mockFetch.mockResolvedValue({ data: 'test' });
  // ...
});

타이머

가짜 타이머
import { vi, beforeEach, afterEach } from 'vitest';

beforeEach(() => {
  vi.useFakeTimers();
});

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

it('handles setTimeout', () => {
  const fn = vi.fn();
  setTimeout(fn, 1000);

  expect(fn).not.toHaveBeenCalled();

  vi.advanceTimersByTime(1000);
  expect(fn).toHaveBeenCalled();
});

it('handles intervals', () => {
  const fn = vi.fn();
  setInterval(fn, 100);

  vi.advanceTimersByTime(350);
  expect(fn).toHaveBeenCalledTimes(3);
});
타이머 유틸리티
vi.useFakeTimers();

vi.advanceTimersByTime(1000);    // Advance by ms
vi.advanceTimersToNextTimer();   // Run next timer
vi.runAllTimers();               // Run all pending
vi.runOnlyPendingTimers();       // Run only pending

vi.setSystemTime(new Date(2023, 0, 1));
vi.getMockedSystemTime();        // Get mocked time

vi.useRealTimers();              // Restore real timers

비동기 테스트

비동기 테스트

Async/await
it('fetches data', async () => {
  const data = await fetchData();
  expect(data).toEqual({ id: 1 });
});

it('handles errors', async () => {
  await expect(fetchBadData()).rejects.toThrow('Not found');
});
프로미스
it('resolves', () => {
  return expect(fetchData()).resolves.toEqual({ id: 1 });
});

it('rejects', () => {
  return expect(fetchBadData()).rejects.toThrow();
});
콜백
it('calls callback', () => {
  return new Promise((resolve) => {
    doSomethingAsync((result) => {
      expect(result).toBe('done');
      resolve();
    });
  });
});

스냅샷

스냅샷 테스트

기본 스냅샷
it('matches snapshot', () => {
  const tree = render(<Button>Click me</Button>);
  expect(tree).toMatchSnapshot();
});

it('matches inline snapshot', () => {
  const user = getUser();
  expect(user).toMatchInlineSnapshot(`
    {
      "id": 1,
      "name": "John",
    }
  `);
});
스냅샷 업데이트
// CLI
npx vitest -u
npx vitest --update

// In watch mode, press 'u' to update

커버리지

커버리지 설정

설정
// vitest.config.ts
export default defineConfig({
  test: {
    coverage: {
      provider: 'v8', // or 'istanbul'
      reporter: ['text', 'json', 'html', 'lcov'],
      reportsDirectory: './coverage',
      include: ['src/**/*.{js,ts}'],
      exclude: [
        'node_modules',
        'src/**/*.test.{js,ts}',
        'src/**/*.d.ts',
      ],
      all: true,
      lines: 80,
      functions: 80,
      branches: 80,
      statements: 80,
    },
  },
});
커버리지와 함께 실행
npx vitest --coverage
npx vitest --coverage.enabled --coverage.provider=v8

DOM 테스트

테스팅 라이브러리

React 컴포넌트
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';

it('renders button', () => {
  render(<Button>Click me</Button>);
  expect(screen.getByRole('button')).toBeInTheDocument();
});

it('handles click', async () => {
  const user = userEvent.setup();
  const onClick = vi.fn();
  render(<Button onClick={onClick}>Click</Button>);

  await user.click(screen.getByRole('button'));
  expect(onClick).toHaveBeenCalledTimes(1);
});
쿼리
// Get (throws if not found)
screen.getByRole('button');
screen.getByText('Hello');
screen.getByLabelText('Email');
screen.getByPlaceholderText('Search');
screen.getByTestId('submit-btn');

// Query (returns null)
screen.queryByRole('button');

// Find (async, waits)
await screen.findByRole('button');

// Multiple
screen.getAllByRole('listitem');