Vite ๊ธฐ๋ฐ์ React ํ๋ก์ ํธ์์ Vitest + React Testing Library๋ฅผ ํ์ฉํ ํ ์คํธ ํ๊ฒฝ์ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํฉ๋๋ค.
์ค์ ์ค์ ๋ฐ ๋ฌธ์ ํด๊ฒฐ ๊ณผ์ ๊น์ง ๋ชจ๋ ํฌํจํ์ฌ ์์ธํ๊ฒ ์์๊ฐ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ , Vite๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด React ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
# Vite + React ํ๋ก์ ํธ ์์ฑ
npm create vite@latest my-project --template react
cd my-project
# ํจํค์ง ์ค์น
npm install
๐ Vite๋ ๋น ๋ฅธ ๊ฐ๋ฐ ํ๊ฒฝ์ ์ ๊ณตํ๋ ๋น๋ ํด์ด๋ฉฐ, --template react
์ต์
์ ํตํด React ํ๊ฒฝ์ ์ค์ ํฉ๋๋ค.
Vite ํ๋ก์ ํธ์์ ํ ์คํธ๋ฅผ ์คํํ๋ ค๋ฉด Vitest์ React Testing Library๋ฅผ ์ค์นํด์ผ ํฉ๋๋ค.
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
โ ์ค์นํ๋ ํจํค์ง ์ค๋ช
vitest
โ Jest์ ์ ์ฌํ ํ
์คํธ ํ๋ ์์ํฌ (Vite์ ์ต์ ํ๋จ)@testing-library/react
โ React ์ปดํฌ๋ํธ ํ
์คํธ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ@testing-library/jest-dom
โ DOM ๊ด๋ จ ์ถ๊ฐ ๋งค์ฒ(matcher) ์ ๊ณต (toBeInTheDocument()
๋ฑ)jsdom
โ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ๊ฐ์์ผ๋ก ์ ๊ณตํ์ฌ React ์ปดํฌ๋ํธ๋ฅผ ํ
์คํธํ ์ ์๋๋ก ํจpackage.json
์คํฌ๋ฆฝํธ ์ถ๊ฐpackage.json
์ ํ
์คํธ ์คํ ๋ช
๋ น์ด๋ฅผ ์ถ๊ฐํฉ๋๋ค.
๐ package.json
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest",
"test:watch": "vitest --watch"
}
โ ๊ฐ ๋ช ๋ น์ด ์ค๋ช
"test": "vitest"
โ ํ
์คํธ ์คํ"test:watch": "vitest --watch"
โ ํ์ผ์ด ๋ณ๊ฒฝ๋ ๋ ์๋์ผ๋ก ํ
์คํธ ์คํvite.config.js
์ค์ Vite์์ Vitest๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์ค์ ํ์ผ์ ์์ฑํฉ๋๋ค.
๐ vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { configDefaults } from "vitest/config";
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
setupFiles: "./vitest.setup.js",
exclude: [...configDefaults.exclude, "e2e/*"],
},
});
โ ์ค์ ์ค๋ช
environment: "jsdom"
โ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ์๋ฎฌ๋ ์ด์
setupFiles: "./vitest.setup.js"
โ ํ
์คํธ ์คํ ์ ์ ํ์ํ ์ค์ ์ ๋ก๋exclude: [...configDefaults.exclude, "e2e/*"]
โ e2e ํ
์คํธ ๋๋ ํ ๋ฆฌ ์ ์ธvitest.setup.js
์ถ๊ฐํ
์คํธ ํ๊ฒฝ์ ์ค์ ํ๋ vitest.setup.js
ํ์ผ์ ์์ฑํฉ๋๋ค.
๐ vitest.setup.js
import "@testing-library/jest-dom";
์ด ํ์ผ์ ํตํด @testing-library/jest-dom
์ ํ์ฅ ๋งค์ฒ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ปดํฌ๋ํธ๋ณ๋ก tests/
๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ์ฌ ํ
์คํธ ํ์ผ์ ๊ด๋ฆฌํฉ๋๋ค.
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ
src/
โโโ components/
โ โโโ Header.jsx
โ โโโ Footer.jsx
โ โโโ tests/
โ โ โโโ Header.test.jsx
โ โ โโโ Footer.test.jsx
โโโ vite.config.js
โโโ vitest.setup.js
โโโ package.json
Footer
์ปดํฌ๋ํธ ํ
์คํธ๐ src/components/tests/Footer.test.jsx
import { render, screen } from "@testing-library/react";
import Footer from "../Footer";
test("Footer๊ฐ ์ ์์ ์ผ๋ก ๋ ๋๋ง๋์ด์ผ ํ๋ค", () => {
render(<Footer />);
expect(screen.getByText("์จ์ ์ด์ฌ๋ฆฌ๋ธ์ ์ฃผ์ํ์ฌ")).toBeInTheDocument();
expect(screen.getByText("์ด์ฉ์ฝ๊ด | ๋ฒ์ ๊ณ ์ง")).toBeInTheDocument();
expect(screen.getByText(/ํ๋์ํ ๊ตฌ๋งค์์ ์๋น์ค/)).toBeInTheDocument();
});
test("ํ์ฌ์๊ฐ ๋งํฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์กด์ฌํด์ผ ํ๋ค", () => {
render(<Footer />);
const companyLink = screen.getByText("ํ์ฌ์๊ฐ");
expect(companyLink.closest("a")).toHaveAttribute("href", "https://corp.oliveyoung.com/ko");
});
test("๊ณ ๊ฐ์ผํฐ ๋ฐ ๋ฒ์ ์ ๋ณด ๋งํฌ๋ค์ด ์กด์ฌํด์ผ ํ๋ค", () => {
render(<Footer />);
expect(screen.getByText("๊ฐ์ธ์ ๋ณด์ฒ๋ฆฌ๋ฐฉ์นจ")).toBeInTheDocument();
expect(screen.getByText("์ฒญ์๋
๋ณดํธ๋ฐฉ์นจ")).toBeInTheDocument();
expect(screen.getByText("์ด๋ฉ์ผ๋ฌด๋จ์์ง๊ฑฐ๋ถ")).toBeInTheDocument();
});
Header
์ปดํฌ๋ํธ ํ
์คํธ๐ src/components/tests/Header.test.jsx
import { render, screen, fireEvent } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import Header from "../Header";
test("Header๊ฐ ์ ์์ ์ผ๋ก ๋ ๋๋ง๋์ด์ผ ํ๋ค", () => {
render(
<MemoryRouter>
<Header />
</MemoryRouter>
);
expect(screen.getByAltText("์ฌ๋ฆฌ๋ธ์ ๋ก๊ณ ")).toBeInTheDocument();
expect(screen.getByPlaceholderText("์ํ, ๋ธ๋๋, ์ฑ๋ถ ๊ฒ์")).toBeInTheDocument();
expect(screen.getByText("ํ์๊ฐ์
")).toBeInTheDocument();
});
test("๋ก๊ณ ํด๋ฆญ ์ ํ(/)์ผ๋ก ์ด๋ํด์ผ ํ๋ค", () => {
const { container } = render(
<MemoryRouter>
<Header />
</MemoryRouter>
);
const logo = screen.getByAltText("์ฌ๋ฆฌ๋ธ์ ๋ก๊ณ ");
fireEvent.click(logo);
expect(container.innerHTML).toContain("์ฌ๋ฆฌ๋ธ์");
});
npm run test
โ๏ธ ์ ์์ ์ผ๋ก ์ค์ ๋์๋ค๋ฉด ์๋์ฒ๋ผ ์ถ๋ ฅ๋ฉ๋๋ค.
โ src/components/tests/Footer.test.jsx (3 tests)
โ src/components/tests/Header.test.jsx (2 tests)
Test Files 2 passed (2)
Tests 5 passed (5)
Vitest๊ฐ ์คํ๋์ง ์์ (vitest: command not found
)
npm install -D vitest
@testing-library/react
๋ฅผ ์ฐพ์ง ๋ชปํจ
npm install -D @testing-library/react
@testing-library/jest-dom
์ด ํ์ํจ
npm install -D @testing-library/jest-dom
ํจํค์ง ๋ฌธ์ ํด๊ฒฐ (node_modules
์ญ์ ํ ์ฌ์ค์น)
rm -rf node_modules package-lock.json
npm install
๋จ๊ณ | ๋ช ๋ น์ด |
---|---|
1. Vite ํ๋ก์ ํธ ์์ฑ | npm create vite@latest my-project --template react |
2. ํจํค์ง ์ค์น | npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom |
3. package.json ์ค์ | "test": "vitest" ์ถ๊ฐ |
4. vite.config.js ์ค์ | environment: "jsdom" ๋ฑ ์ถ๊ฐ |
5. vitest.setup.js ์ค์ | import "@testing-library/jest-dom" ์ถ๊ฐ |
6. ํ ์คํธ ์์ฑ | src/components/tests/*.test.jsx ์์ฑ |
7. ํ ์คํธ ์คํ | npm run test |
์ด์ React + Vite ํ๋ก์ ํธ์์ Vitest๋ฅผ ํ์ฉํ ํ ์คํธ ํ๊ฒฝ์ ์๋ฒฝํ๊ฒ ๊ตฌ์ถํ ์ ์์ต๋๋ค! ๐
์์ผ๋ก ๋ค๋ฅธ ํ๋ก์ ํธ์์๋ ์ด ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ์ฌ ๋น ๋ฅด๊ฒ ํ ์คํธ ํ๊ฒฝ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
๊ถ๊ธํ ์ ์ด ์์ผ๋ฉด ์ธ์ ๋ ์ง ์ง๋ฌธํ์ธ์! ๐