출시·고도화 중
Vue.js · Nuxt 안내서 · 5/6
Vue 프로젝트의 테스트는 보통 세 층으로 나눕니다. composable과 스토어 같은 순수 로직은 Vitest로, 컴포넌트는 Vitest와 Vue Test Utils로, 사용자의 실제 흐름은 Playwright 같은 E2E 도구로 검사합니다. Nuxt 프로젝트에서는 @nuxt/test-utils가 Nuxt 환경을 테스트 안에 띄워 줍니다.
create-vue에서 Vitest를 골랐다면 설정이 이미 되어 있습니다. 직접 추가할 때는 다음 패키지를 설치합니다.
npm install -D vitest @vue/test-utils jsdomvitest.config.ts에서 Vite 설정을 이어받고, 브라우저 API를 흉내 내는 jsdom 환경을 지정합니다.
import { fileURLToPath } from "node:url";
import { mergeConfig, defineConfig, configDefaults } from "vitest/config";
import viteConfig from "./vite.config";
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: "jsdom",
exclude: [...configDefaults.exclude, "e2e/**"],
root: fileURLToPath(new URL("./", import.meta.url)),
},
}),
);npm run test:unit(또는 npx vitest)을 실행하면 감시 모드로 테스트가 돌고, 파일을 저장할 때마다 관련 테스트만 다시 실행됩니다.
composable은 일반 함수처럼 부르고 결과를 확인합니다. Pinia 스토어는 테스트마다 새 Pinia를 활성화해 서로 영향을 주지 않게 합니다.
import { describe, it, expect, beforeEach } from "vitest";
import { setActivePinia, createPinia } from "pinia";
import { useCounter } from "@/composables/useCounter";
import { useCartStore } from "@/stores/cart";
describe("useCounter", () => {
it("increment와 double", () => {
const { count, double, increment } = useCounter(1);
increment();
expect(count.value).toBe(2);
expect(double.value).toBe(4);
});
});
describe("cart store", () => {
beforeEach(() => setActivePinia(createPinia()));
it("같은 상품은 수량이 늘어난다", () => {
const cart = useCartStore();
cart.add({ id: 1, name: "책", price: 100 });
cart.add({ id: 1, name: "책", price: 100 });
expect(cart.items[0].qty).toBe(2);
expect(cart.total).toBe(200);
});
});Vue Test Utils의 mount는 컴포넌트를 렌더링한 래퍼를 돌려줍니다. props를 넘기고, 요소를 찾아 이벤트를 일으킨 뒤 화면 글자나 내보낸 이벤트를 확인합니다. DOM 갱신은 비동기이므로 trigger와 setValue는 await합니다.
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import TodoItem from "@/components/TodoItem.vue";
describe("TodoItem", () => {
it("글자를 보여 주고 삭제 이벤트를 내보낸다", async () => {
const wrapper = mount(TodoItem, { props: { text: "장보기", done: false } });
expect(wrapper.text()).toContain("장보기");
await wrapper.find("button").trigger("click");
expect(wrapper.emitted("remove")?.[0]).toEqual(["user"]);
});
});전역 플러그인이 필요한 컴포넌트는 mount(Comp, { global: { plugins: [router, createPinia()] } })처럼 넘깁니다. 구현 세부보다 사용자가 보는 결과를 확인하는 테스트가 리팩터링에 강합니다.
Nuxt 컴포넌트는 자동 가져오기와 Nuxt 컴포저블에 기대므로 일반 jsdom 환경에서는 그대로 돌지 않습니다. @nuxt/test-utils는 테스트 안에서 Nuxt 런타임을 띄우는 nuxt 환경과 mountSuspended를 제공합니다.
npm install -D @nuxt/test-utils vitest @vue/test-utils happy-dom// vitest.config.ts
import { defineVitestConfig } from "@nuxt/test-utils/config";
export default defineVitestConfig({
test: { environment: "nuxt" },
});// tests/counter.nuxt.test.ts
import { it, expect } from "vitest";
import { mountSuspended } from "@nuxt/test-utils/runtime";
import AppCounter from "~/components/AppCounter.vue";
it("Nuxt 환경에서 렌더링된다", async () => {
const wrapper = await mountSuspended(AppCounter);
expect(wrapper.text()).toContain("0");
});mountSuspended는 비동기 setup과 useFetch를 기다린 뒤 결과를 돌려줍니다. 서버 API 호출은 registerEndpoint로 가짜 응답을 등록할 수 있습니다.
E2E 테스트는 실제 브라우저로 앱을 열어 사용자처럼 조작합니다. create-vue에서 Playwright를 골랐거나 npm init playwright@latest로 추가합니다.
// e2e/home.spec.ts
import { test, expect } from "@playwright/test";
test("검색어로 목록을 거른다", async ({ page }) => {
await page.goto("/");
await page.getByPlaceholder("검색").fill("Vue");
await expect(page.getByRole("listitem")).toHaveCount(1);
});playwright.config.ts의 webServer 항목에 개발 서버나 미리보기 서버 실행 명령을 적어 두면 테스트 전에 자동으로 서버가 켜집니다. npx playwright test로 실행하고, --ui를 붙이면 단계별로 살펴볼 수 있습니다.
setActivePinia(createPinia())를 부릅니다.@nuxt/test-utils의 nuxt 환경과 mountSuspended로 테스트합니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.